SWDEV-432445: Handling multiple agents for ATT
Change-Id: I41d30baf2c469d8ddb58e3385b88a7b04a30422e
[ROCm/rocprofiler commit: b93d5e7e79]
Этот коммит содержится в:
коммит произвёл
Giovanni Baraldi
родитель
f275cdd602
Коммит
f446834082
@@ -306,3 +306,15 @@ Example for file plugin output:
|
||||
- Added Tool versioning to be able to run rocprofv2 using rocprof. See README for more information.
|
||||
- Added Plugin Versioning way in rocprofv2. See README for more details.
|
||||
- Added --version in the rocprof and rocprofv2 to be able to see the current rocprof/v2 version along with ROCm version information.
|
||||
|
||||
## ROCprofiler for rocm 6.2
|
||||
|
||||
### Added
|
||||
|
||||
- ATT: Continuous mode. The input file now has a DISPATCH_RANGE=begin,end that specifies continuous ATT collection during the application run.
|
||||
- ATT: Ability to dump raw codeobjects as .out files with ISA_CAPTURE_MODE=[0,1,2]
|
||||
|
||||
### Removed
|
||||
|
||||
- ATT: Network mode, since it was redundant with file mode.
|
||||
- ATT: Generated isa.s file, since the functionality was moved from collection to parsing time.
|
||||
|
||||
@@ -352,17 +352,17 @@ Tool used to collect fine-grained hardware metrics. Provides ISA-level instructi
|
||||
Path for the running application
|
||||
- ATT plugin optional parameters
|
||||
- --att_kernel "filename": Kernel filename(s) (glob) to use. A CSV file (or UI folder) will be generated for each kernel.txt file. Default: all in current folder.
|
||||
- --mode [csv, network, file, off (default)]
|
||||
- --mode [csv, file, off (default)]
|
||||
- off
|
||||
Runs trace collection but not analysis, so it can be analyzed at a later time. Run rocprofv2 ATT with the same parameters (+ --mode csv), removing the application binary, to analyze previously generated traces.
|
||||
- csv
|
||||
Dumps the analyzed assembly into a CSV format, with the hitcount and total cycles cost. Recommended mode for most users.
|
||||
- network (deprecated)
|
||||
Opens the server with the browser UI.
|
||||
att needs 2 ports available (e.g. 8000, 18000). There is an option (default: --ports "8000,18000") to change these.
|
||||
In case rocprofv2 is running on a different machine, use port forwarding `ssh -L 8000:localhost:8000 <user@IP>` so the browser can be used locally. For docker, use --network=host --ipc=host -p8000:8000 -p18000:18000
|
||||
- file (deprecated)
|
||||
Dumps the analyzed json files to disk for vieweing at a later time. Run python3 httpserver.py from within the generated ui/ folder to view the trace, similarly to network mode. The folder can be copied to another machine, and will run without rocm.
|
||||
Dumps the analyzed json files to disk for vieweing at a later time. Run python3 httpserver.py from within the generated name_ui/ folder to view the trace. The folder can be copied to another machine, and will run without rocm.
|
||||
- file,csv
|
||||
Both options can be used at the same time, generating a UI folder and a .csv.
|
||||
- network [removed]
|
||||
Network mode was removed, since it's functionality is included in file mode with the httpserver.py script generated inside the UI folder.
|
||||
- input.txt
|
||||
Required. Used to select specific compute units and other trace parameters.
|
||||
For first time users, using the following input file:
|
||||
@@ -394,14 +394,10 @@ Tool used to collect fine-grained hardware metrics. Provides ISA-level instructi
|
||||
- BUFFER_SIZE=[size] // Sets size of the ATT buffer collection, per dispatch, in megabytes (shared among all shader engines).
|
||||
- ISA_CAPTURE_MODE=[0,1,2] // Set codeobj capture mode during kernel dispatch.
|
||||
- 0 = capture symbols only.
|
||||
- 1 = capture symbols for file:// and make a copy of memory://
|
||||
- 2 = Copy file:// and memory://
|
||||
- ISA_DUMP_MODE=[0,1,2,3] // Set how captured codeobj information is dumped when a trace record arrives.
|
||||
- 0 = Default. Dump everything.
|
||||
- 1 = Dump only the code object containing the kernel address in the kernel dispatch packet.
|
||||
- 2 = Dump a single kernel symbol matching the kernel dispatch packet.
|
||||
- 3 = Disables ISA Dumping.
|
||||
- By default, kernel names are truncated for ATT.To disable, please see the kernel name truncation section below.
|
||||
- 1 = capture symbols for file:// and make a copy of memory://, dump captured copy as .out file.
|
||||
- 2 = Copy file:// and memory://, dump copied codeobj as .out files.
|
||||
- DISPATCH_RANGE=[begin],[end] // Continuously collect ATT data starting at "begin" and stop at "end". Alternative to DISPATCH= and KERNEL=.
|
||||
- By default, kernel names are truncated for ATT. To disable, please see the kernel name truncation section below.
|
||||
|
||||
- Example for vectoradd.
|
||||
|
||||
@@ -450,6 +446,8 @@ Tool used to collect fine-grained hardware metrics. Provides ISA-level instructi
|
||||
export ROCPROFILER_MAX_ATT_PROFILES=<max_collections>
|
||||
```
|
||||
|
||||
Or, alternatively, use the continuous ATT mode (DISPATCH_RANGE parameter).
|
||||
|
||||
***
|
||||
|
||||
### Flush Interval
|
||||
|
||||
@@ -438,21 +438,21 @@ if __name__ == "__main__":
|
||||
"--mode",
|
||||
help="""ATT analysis modes:\n
|
||||
off: Only run ATT collection, disable analysis.\n
|
||||
file: dump json files to disk.\n
|
||||
network: Open att server over the network.""",
|
||||
file: dump json files to disk.""",
|
||||
type=str,
|
||||
default="off",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
args.mode = args.mode.lower().split(',')
|
||||
|
||||
CSV_MODE = False
|
||||
if args.mode.lower() == 'csv':
|
||||
FILE_MODE = False
|
||||
if 'csv' in args.mode:
|
||||
CSV_MODE = True
|
||||
elif args.mode.lower() == 'file':
|
||||
args.dumpfiles = True
|
||||
elif args.mode.lower() == "network":
|
||||
args.dumpfiles = False
|
||||
else:
|
||||
if 'file' in args.mode:
|
||||
FILE_MODE = True
|
||||
|
||||
if not CSV_MODE and not FILE_MODE:
|
||||
print("Skipping analysis.")
|
||||
quit()
|
||||
|
||||
@@ -482,10 +482,21 @@ if __name__ == "__main__":
|
||||
for line in f:
|
||||
att_kernel_f.append(line.split('\n')[0])
|
||||
|
||||
# returns element index of the file:// or memory:// filepath in the string
|
||||
get_path_loc = lambda x: np.sum([len(m) for m in x.split(' ')[:3]])+3
|
||||
# adds the OUTPUT_PATH env variable to a filepath if necessary
|
||||
add_pathnv = lambda x: x[:get_path_loc(x)] + os.path.join(pathenv, x[get_path_loc(x):])
|
||||
# returns the memory address in the string
|
||||
get_addr = lambda x: int(x.split(' ')[0][2:], 16)
|
||||
# Sets a preference for 'file' paths to be added before 'memory' paths. Sorts by addr.
|
||||
get_addr_preference = lambda x: [0 if 'file' in x[get_path_loc(x):] else 1<<60][0]
|
||||
|
||||
# Get the GPU id in the string
|
||||
gpu_id = int(att_kernel_f[0].split(' ')[2].split('GPU[')[1].split(']')[0])
|
||||
# Eliminame first line in the att_kernel txt file and adds the OUTPUT_PATH as needed
|
||||
att_kernel_f = [add_pathnv(p) if '.out' == p[-4:] else p for p in att_kernel_f[1:]]
|
||||
# Sorts the list of codeobj by address, with 'file' given preference
|
||||
att_kernel_f = sorted(att_kernel_f, key=lambda x: get_addr(x)+get_addr_preference(x))
|
||||
assembly_code = deepcopy(args.assembly_code)
|
||||
|
||||
# Assembly parsing
|
||||
@@ -526,7 +537,7 @@ if __name__ == "__main__":
|
||||
|
||||
gc.collect()
|
||||
if bIsAuto:
|
||||
codeservice = CodeobjService(att_kernel_f, SO.classify_asm_line)
|
||||
codeservice = CodeobjService(gpu_id, att_kernel_f, SO.classify_asm_line)
|
||||
else:
|
||||
codeservice = None
|
||||
|
||||
@@ -563,7 +574,8 @@ if __name__ == "__main__":
|
||||
if CSV_MODE:
|
||||
from att_to_csv import dump_csv
|
||||
dump_csv(code, trace_instance_name)
|
||||
else:
|
||||
|
||||
if FILE_MODE:
|
||||
drawinfo = {
|
||||
"TIMELINES": gen_timelines(DBFILES),
|
||||
"EVENTS": EVENTS,
|
||||
@@ -573,11 +585,9 @@ if __name__ == "__main__":
|
||||
"DispatchNames": {id: codeservice.getSymbolName(addr) for id, addr in kernel_addr.items()}
|
||||
}
|
||||
view_trace(
|
||||
args,
|
||||
code,
|
||||
DBFILES,
|
||||
analysed_filenames,
|
||||
args.dumpfiles,
|
||||
0,
|
||||
gfxv,
|
||||
drawinfo,
|
||||
|
||||
@@ -53,24 +53,27 @@
|
||||
|
||||
#define C_API_BEGIN try {
|
||||
|
||||
#define C_API_END(returndata) \
|
||||
} catch (std::exception& e) \
|
||||
{ \
|
||||
std::cerr << "Error: " << e.what() << std::endl; \
|
||||
return returndata; \
|
||||
} \
|
||||
catch (std::string& s) \
|
||||
{ \
|
||||
std::cerr << "Error: " << s << std::endl; \
|
||||
return returndata; \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
return returndata; \
|
||||
#define C_API_END(returndata) \
|
||||
} catch (std::exception& e) \
|
||||
{ \
|
||||
std::cerr << "Codeobj API lookup error: " << e.what() << std::endl; \
|
||||
return returndata; \
|
||||
} \
|
||||
catch (std::string& s) \
|
||||
{ \
|
||||
std::cerr << "Codeobj API lookup error: " << s << std::endl; \
|
||||
return returndata; \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
return returndata; \
|
||||
}
|
||||
|
||||
CodeObjDecoderComponent::CodeObjDecoderComponent(const char* codeobj_data, uint64_t codeobj_size)
|
||||
{
|
||||
CodeObjDecoderComponent::CodeObjDecoderComponent(
|
||||
const char* codeobj_data,
|
||||
uint64_t codeobj_size,
|
||||
uint64_t gpu_id
|
||||
) {
|
||||
m_fd = -1;
|
||||
#if defined(_GNU_SOURCE) && defined(MFD_ALLOW_SEALING) && defined(MFD_CLOEXEC)
|
||||
m_fd = ::memfd_create(m_uri.c_str(), MFD_ALLOW_SEALING | MFD_CLOEXEC);
|
||||
@@ -113,21 +116,28 @@ CodeObjDecoderComponent::CodeObjDecoderComponent(const char* codeobj_data, uint6
|
||||
size_t line_count;
|
||||
if (dwarf_getsrclines(&die, &lines, &line_count)) continue;
|
||||
|
||||
std::shared_ptr<std::string> dwarf_line_number{nullptr};
|
||||
for (size_t i = 0; i < line_count; ++i) {
|
||||
Dwarf_Addr addr;
|
||||
int line_number;
|
||||
Dwarf_Line* line = dwarf_onesrcline(lines, i);
|
||||
if (!line) continue;
|
||||
|
||||
if (!dwarf_lineaddr(line, &addr) && !dwarf_lineno(line, &line_number) && line_number)
|
||||
m_line_number_map[addr] = {dwarf_linesrc(line, nullptr, nullptr), line_number};
|
||||
if (line && !dwarf_lineaddr(line, &addr) && !dwarf_lineno(line, &line_number) && line_number)
|
||||
{
|
||||
std::string src = dwarf_linesrc(line, nullptr, nullptr);
|
||||
dwarf_line_number = std::make_shared<std::string>(src + ':' + std::to_string(line_number));
|
||||
}
|
||||
|
||||
if (dwarf_line_number.get())
|
||||
m_line_number_map[addr] = dwarf_line_number;
|
||||
}
|
||||
cu_offset = next_offset;
|
||||
}
|
||||
// load_symbol_map();
|
||||
}
|
||||
|
||||
disassembly = std::make_unique<DisassemblyInstance>(codeobj_data, codeobj_size, std::nullopt); // Can throw
|
||||
// Can throw
|
||||
disassembly = std::make_unique<DisassemblyInstance>(codeobj_data, codeobj_size, gpu_id);
|
||||
try {
|
||||
m_symbol_map = disassembly->GetKernelMap(); // Can throw
|
||||
} catch(...) {}
|
||||
@@ -169,15 +179,11 @@ CodeObjDecoderComponent::disassemble_instruction(uint64_t faddr, uint64_t vaddr)
|
||||
throw std::exception();
|
||||
|
||||
char* cpp_line = nullptr;
|
||||
auto it = m_line_number_map.find(vaddr);
|
||||
if (it != m_line_number_map.end()) {
|
||||
const std::string& file_name = it->second.first;
|
||||
size_t line_number = it->second.second;
|
||||
|
||||
std::string cpp = file_name + ':' + std::to_string(line_number);
|
||||
cpp_line = (char*)calloc(cpp.size() + 4, sizeof(char));
|
||||
std::memcpy(cpp_line, cpp.data(), cpp.size() * sizeof(char));
|
||||
}
|
||||
auto it = m_line_number_map.find(vaddr);
|
||||
if (it != m_line_number_map.end())
|
||||
cpp_line = it->second->data();
|
||||
|
||||
size_t size = disassembly->ReadInstruction(faddr, vaddr, cpp_line);
|
||||
return {disassembly->last_instruction, size};
|
||||
}
|
||||
@@ -217,8 +223,12 @@ void CodeObjDecoderComponent::disassemble_single_kernel(uint64_t kaddr) {
|
||||
disassemble_kernel(v.faddr, vaddr);
|
||||
}
|
||||
|
||||
CodeobjDecoder::CodeobjDecoder(const char* filepath, uint64_t loadbase, uint64_t mem_size):
|
||||
loadbase(loadbase), load_end(loadbase + mem_size)
|
||||
CodeobjDecoder::CodeobjDecoder(
|
||||
const char* filepath,
|
||||
uint64_t loadbase,
|
||||
uint64_t mem_size,
|
||||
uint64_t gpu_id
|
||||
): loadbase(loadbase), load_end(loadbase + mem_size)
|
||||
{
|
||||
if (!filepath) throw "Empty filepath.";
|
||||
|
||||
@@ -237,13 +247,13 @@ CodeobjDecoder::CodeobjDecoder(const char* filepath, uint64_t loadbase, uint64_t
|
||||
file.seekg(0, file.beg);
|
||||
file.read(buffer.data(), buffer.size());
|
||||
|
||||
decoder = std::make_unique<CodeObjDecoderComponent>(buffer.data(), buffer.size());
|
||||
decoder = std::make_unique<CodeObjDecoderComponent>(buffer.data(), buffer.size(), gpu_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_ptr<CodeObjectBinary> binary = std::make_unique<CodeObjectBinary>(filepath);
|
||||
auto& buffer = binary->buffer;
|
||||
decoder = std::make_unique<CodeObjDecoderComponent>(buffer.data(), buffer.size());
|
||||
decoder = std::make_unique<CodeObjDecoderComponent>(buffer.data(), buffer.size(), gpu_id);
|
||||
}
|
||||
|
||||
auto elf_segments = decoder->disassembly->getSegments();
|
||||
@@ -297,11 +307,16 @@ CodeobjTableTranslation table;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
PUBLIC_API int addDecoder(const char* filename, uint32_t id, uint64_t loadbase, uint64_t memsize)
|
||||
{
|
||||
PUBLIC_API int addDecoder(
|
||||
const char* filename,
|
||||
uint32_t id,
|
||||
uint64_t loadbase,
|
||||
uint64_t memsize,
|
||||
uint64_t gpu_id
|
||||
) {
|
||||
C_API_BEGIN
|
||||
|
||||
table.addDecoder(filename, id, loadbase, memsize);
|
||||
table.addDecoder(filename, id, loadbase, memsize, gpu_id);
|
||||
return 0;
|
||||
|
||||
C_API_END(1)
|
||||
|
||||
@@ -37,7 +37,7 @@ class CodeObjDecoderComponent
|
||||
public:
|
||||
std::optional<SymbolInfo> find_symbol(uint64_t address);
|
||||
|
||||
CodeObjDecoderComponent(const char* codeobj_data, uint64_t codeobj_size);
|
||||
CodeObjDecoderComponent(const char* codeobj_data, uint64_t codeobj_size, uint64_t gpu_id);
|
||||
~CodeObjDecoderComponent();
|
||||
|
||||
std::pair<instruction_instance_t, size_t>
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
|
||||
int m_fd;
|
||||
|
||||
std::map<uint64_t, std::pair<std::string, size_t>> m_line_number_map{};
|
||||
std::map<uint64_t, std::shared_ptr<std::string>> m_line_number_map{};
|
||||
std::map<uint64_t, SymbolInfo> m_symbol_map{};
|
||||
|
||||
std::string m_uri;
|
||||
@@ -65,7 +65,8 @@ typedef struct {
|
||||
class CodeobjDecoder
|
||||
{
|
||||
public:
|
||||
CodeobjDecoder(const char* filepath, uint64_t loadbase, uint64_t memsize);
|
||||
CodeobjDecoder(const char* filepath, uint64_t loadbase, uint64_t memsize, uint64_t gpu_id);
|
||||
|
||||
bool decode_single(uint64_t vaddr);
|
||||
bool decode_single_at_offset(uint64_t vaddr, uint64_t voffset);
|
||||
bool add_to_map(uint64_t faddr, uint64_t vaddr, uint64_t voffset);
|
||||
@@ -111,9 +112,15 @@ class CodeobjList
|
||||
public:
|
||||
CodeobjList() = default;
|
||||
|
||||
virtual void addDecoder(const char* filepath, uint32_t id, uint64_t loadbase, uint64_t memsize)
|
||||
virtual void addDecoder(
|
||||
const char* filepath,
|
||||
uint32_t id,
|
||||
uint64_t loadbase,
|
||||
uint64_t memsize,
|
||||
uint64_t gpu_id
|
||||
)
|
||||
{
|
||||
decoders[id] = std::make_shared<CodeobjDecoder>(filepath, loadbase, memsize);
|
||||
decoders[id] = std::make_shared<CodeobjDecoder>(filepath, loadbase, memsize, gpu_id);
|
||||
}
|
||||
|
||||
virtual bool removeDecoder(uint32_t id)
|
||||
@@ -150,9 +157,15 @@ class CodeobjTableTranslation : protected CodeobjList
|
||||
public:
|
||||
CodeobjTableTranslation() = default;
|
||||
|
||||
void addDecoder(const char* filepath, uint32_t id, uint64_t loadbase, uint64_t memsize) override
|
||||
virtual void addDecoder(
|
||||
const char* filepath,
|
||||
uint32_t id,
|
||||
uint64_t loadbase,
|
||||
uint64_t memsize,
|
||||
uint64_t gpu_id
|
||||
) override
|
||||
{
|
||||
this->Super::addDecoder(filepath, id, loadbase, memsize);
|
||||
this->Super::addDecoder(filepath, id, loadbase, memsize, gpu_id);
|
||||
auto ptr = decoders.at(id);
|
||||
table.insert({ptr->begin(), static_cast<uint32_t>(ptr->size()), id, 0});
|
||||
}
|
||||
|
||||
@@ -70,6 +70,8 @@ if (amd_comgr_status_s status = call) {
|
||||
return AMD_COMGR_STATUS_ERROR; \
|
||||
}
|
||||
|
||||
std::unordered_map<uint64_t, std::string> DisassemblyInstance::agent_isa_name{};
|
||||
|
||||
CodeObjectBinary::CodeObjectBinary(const std::string& uri) : m_uri(uri) {
|
||||
const std::string protocol_delim{"://"};
|
||||
|
||||
@@ -156,7 +158,7 @@ CodeObjectBinary::CodeObjectBinary(const std::string& uri) : m_uri(uri) {
|
||||
DisassemblyInstance::DisassemblyInstance(
|
||||
const char* codeobj_data,
|
||||
uint64_t codeobj_size,
|
||||
std::optional<std::string> input_isa
|
||||
uint64_t gpu_id
|
||||
)
|
||||
{
|
||||
buffer = std::vector<char>(codeobj_size, 0);
|
||||
@@ -164,20 +166,22 @@ DisassemblyInstance::DisassemblyInstance(
|
||||
|
||||
THROW_COMGR(amd_comgr_create_data(AMD_COMGR_DATA_KIND_EXECUTABLE, &data));
|
||||
THROW_COMGR(amd_comgr_set_data(data, buffer.size(), buffer.data()));
|
||||
if (!input_isa)
|
||||
|
||||
std::string input_isa{};
|
||||
if (agent_isa_name.find(gpu_id) == agent_isa_name.end())
|
||||
{
|
||||
input_isa = "amdgcn-amd-amdhsa--gfx1100";
|
||||
size_t isa_size = 128;
|
||||
input_isa.resize(isa_size);
|
||||
THROW_COMGR(amd_comgr_get_data_isa_name(data, &isa_size, input_isa.data()));
|
||||
agent_isa_name[gpu_id] = input_isa;
|
||||
}
|
||||
if (!input_isa)
|
||||
else
|
||||
{
|
||||
input_isa = std::string();
|
||||
input_isa->resize(128);
|
||||
size_t isa_size = sizeof(input_isa->size());
|
||||
THROW_COMGR(amd_comgr_get_data_isa_name(data, &isa_size, input_isa->data()));
|
||||
input_isa = agent_isa_name.at(gpu_id);
|
||||
}
|
||||
|
||||
THROW_COMGR(amd_comgr_create_disassembly_info(
|
||||
input_isa->data(),
|
||||
input_isa.data(),
|
||||
&DisassemblyInstance::memory_callback, &DisassemblyInstance::inst_callback,
|
||||
[](uint64_t address, void* user_data) {}, &info));
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ class DisassemblyInstance {
|
||||
DisassemblyInstance(
|
||||
const char* codeobj_data,
|
||||
uint64_t codeobj_size,
|
||||
std::optional<std::string> input_isa
|
||||
uint64_t gpu_id
|
||||
);
|
||||
~DisassemblyInstance();
|
||||
|
||||
@@ -61,6 +61,8 @@ class DisassemblyInstance {
|
||||
static uint64_t memory_callback(uint64_t from, char* to, uint64_t size, void* user_data);
|
||||
static void inst_callback(const char* instruction, void* user_data);
|
||||
static amd_comgr_status_t symbol_callback(amd_comgr_symbol_t symbol, void* user_data);
|
||||
// Per-gpu_id isa_name
|
||||
static std::unordered_map<uint64_t, std::string> agent_isa_name;
|
||||
|
||||
std::optional<uint64_t> va2fo(uint64_t va);
|
||||
std::vector<std::pair<uint64_t, uint64_t>> getSegments();
|
||||
|
||||
@@ -33,7 +33,7 @@ attplugin.getInstructionFromID.restype = instruction_info_t
|
||||
attplugin.getInstructionFromID.argtypes = [c_uint32, c_uint64]
|
||||
|
||||
attplugin.addDecoder.restype = c_int
|
||||
attplugin.addDecoder.argtypes = [c_char_p, c_uint32, c_uint64, c_uint64]
|
||||
attplugin.addDecoder.argtypes = [c_char_p, c_uint32, c_uint64, c_uint64, c_uint64]
|
||||
|
||||
attplugin.removeDecoder.restype = c_int
|
||||
attplugin.removeDecoder.argtypes = [c_uint32, c_uint64]
|
||||
@@ -48,15 +48,15 @@ def getOffset(addr):
|
||||
return addr & OFFSET_MASK
|
||||
|
||||
class CodeobjInstance:
|
||||
def __init__(self, line):
|
||||
def __init__(self, gpu_id, line):
|
||||
tokens = line.split(' ')
|
||||
self.load_base = int(tokens[0], 16)
|
||||
self.memsize = int(tokens[1], 16)
|
||||
self.att_id = int(tokens[2])
|
||||
self.fpath = tokens[3]
|
||||
|
||||
encoded = self.fpath.encode('utf-8')
|
||||
self.error = attplugin.addDecoder(encoded, self.att_id, self.load_base, self.memsize)
|
||||
path = self.fpath.encode('utf-8')
|
||||
self.error = attplugin.addDecoder(path, self.att_id, self.load_base, self.memsize, gpu_id)
|
||||
if self.error != 0:
|
||||
print('Warning: Could not open', line)
|
||||
raise
|
||||
@@ -66,7 +66,7 @@ class CodeobjInstance:
|
||||
|
||||
|
||||
class CodeobjService:
|
||||
def __init__(self, att_kernel_txt, cfunc):
|
||||
def __init__(self, gpu_id, att_kernel_txt, cfunc):
|
||||
cfunc.restype = ctypes.c_int
|
||||
cfunc.argtypes = [ctypes.c_char_p, ctypes.c_size_t]
|
||||
|
||||
@@ -77,7 +77,7 @@ class CodeobjService:
|
||||
try:
|
||||
if 'memory://' == line[0:len('memory://')]:
|
||||
continue
|
||||
service = CodeobjInstance(line)
|
||||
service = CodeobjInstance(gpu_id, line)
|
||||
self.services[service.att_id] = service
|
||||
except:
|
||||
pass
|
||||
@@ -132,7 +132,10 @@ class CodeobjService:
|
||||
return (self.classifier(info_inst.inst, len(inst)), inst, cpp, info_inst.size)
|
||||
|
||||
def getSymbolName(self, addr):
|
||||
name = attplugin.getSymbolName(self.ToRawPC(addr))
|
||||
if name:
|
||||
return name.decode()
|
||||
return "Addr #"+hex(self.ToRawPC(addr))
|
||||
try:
|
||||
name = attplugin.getSymbolName(self.ToRawPC(addr))
|
||||
if name:
|
||||
return name.decode()
|
||||
return "Addr #"+hex(self.ToRawPC(addr))
|
||||
except:
|
||||
return "Addr #"+hex(addr)
|
||||
|
||||
@@ -153,127 +153,6 @@ def extract_data(df, se_number):
|
||||
return flight_count, wave_filenames, se_filename, allwaves_maxline
|
||||
|
||||
|
||||
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):
|
||||
if (
|
||||
".png?" in self.path
|
||||
and self.path.split("/")[-1] not in JSON_GLOBAL_DICTIONARY.keys()
|
||||
):
|
||||
selections = [int(s) != 0 for s in self.path.split(".png?")[-1]]
|
||||
counters_json, imagebytes = GeneratePIC(
|
||||
self.drawinfo, selections[1:], selections[0]
|
||||
)
|
||||
JSON_GLOBAL_DICTIONARY["graph_options.json"] = counters_json
|
||||
JSON_GLOBAL_DICTIONARY[self.path.split("/")[-1]] = imagebytes[
|
||||
self.path.split("/")[-1].split("?")[0]
|
||||
]
|
||||
|
||||
if ".json" in self.path or ".png" in self.path:
|
||||
try:
|
||||
response_file = JSON_GLOBAL_DICTIONARY[self.path.split("/")[-1]]
|
||||
except:
|
||||
print("Invalid json request:", self.path)
|
||||
print(JSON_GLOBAL_DICTIONARY.keys())
|
||||
self.send_error(HTTPStatus.NOT_FOUND, "File not found")
|
||||
return
|
||||
self.send_response(HTTPStatus.OK)
|
||||
self.send_header("Content-Length", str(len(response_file)))
|
||||
if ".b" in self.path:
|
||||
self.send_header("Content-type", "application/octet-stream")
|
||||
response_file = BytesIO(response_file)
|
||||
elif "timeline.png" in self.path:
|
||||
self.send_header("Content-type", "image/png")
|
||||
else:
|
||||
self.send_header("Content-type", "application/json")
|
||||
self.send_header("Last-Modified", self.date_time_string(time.time()))
|
||||
self.end_headers()
|
||||
self.copyfile(response_file, self.wfile)
|
||||
elif self.path in ["/", "/styles.css", "/index.html", "/logo.svg"]:
|
||||
http.server.SimpleHTTPRequestHandler.do_GET(self)
|
||||
else:
|
||||
print("Invalid request:", self.path)
|
||||
self.send_error(HTTPStatus.NOT_FOUND, "File not found")
|
||||
|
||||
|
||||
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(drawinfo):
|
||||
Handler = NoCacheHTTPRequestHandler
|
||||
Handler.drawinfo = drawinfo
|
||||
os.chdir(os.path.join(os.path.dirname(os.path.realpath(__file__)),"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()
|
||||
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 call_picture_callback(return_dict, drawinfo):
|
||||
response, imagebytes = GeneratePIC(drawinfo)
|
||||
return_dict["graph_options.json"] = response
|
||||
@@ -291,11 +170,9 @@ def call_picture_callback(return_dict, drawinfo):
|
||||
|
||||
|
||||
def view_trace(
|
||||
args,
|
||||
code,
|
||||
dbnames,
|
||||
att_filenames,
|
||||
bDumpOnly,
|
||||
se_time_begin,
|
||||
gfxv,
|
||||
drawinfo,
|
||||
@@ -380,30 +257,13 @@ def view_trace(
|
||||
for k, v in return_dict.items():
|
||||
JSON_GLOBAL_DICTIONARY[k] = v
|
||||
|
||||
if bDumpOnly == False:
|
||||
JSON_GLOBAL_DICTIONARY["live.json"] = Readable({"live": 1})
|
||||
if args.ports:
|
||||
assign_ports(args.ports)
|
||||
print("serving at ports: {0},{1}".format(PORT, WebSocketPort))
|
||||
try:
|
||||
PROCS = [
|
||||
Process(target=run_server, args=[drawinfo]),
|
||||
Process(target=run_websocket),
|
||||
]
|
||||
for p in PROCS:
|
||||
p.start()
|
||||
for p in PROCS:
|
||||
p.join()
|
||||
except KeyboardInterrupt:
|
||||
print("Exitting.")
|
||||
else:
|
||||
os.makedirs(trace_instance_name + "_ui/", exist_ok=True)
|
||||
JSON_GLOBAL_DICTIONARY["live.json"] = Readable({"live": 0})
|
||||
os.system(
|
||||
"cp "
|
||||
+ os.path.join(os.path.abspath(os.path.dirname(__file__)), "ui")
|
||||
+ "/* " + trace_instance_name + "_ui/"
|
||||
)
|
||||
for k, v in JSON_GLOBAL_DICTIONARY.items():
|
||||
with open(os.path.join(trace_instance_name+"_ui", k), "w" if ".json" in k else "wb") as f:
|
||||
f.write(v.read())
|
||||
os.makedirs(trace_instance_name + "_ui/", exist_ok=True)
|
||||
JSON_GLOBAL_DICTIONARY["live.json"] = Readable({"live": 0})
|
||||
os.system(
|
||||
"cp "
|
||||
+ os.path.join(os.path.abspath(os.path.dirname(__file__)), "ui")
|
||||
+ "/* " + trace_instance_name + "_ui/"
|
||||
)
|
||||
for k, v in JSON_GLOBAL_DICTIONARY.items():
|
||||
with open(os.path.join(trace_instance_name+"_ui", k), "w" if ".json" in k else "wb") as f:
|
||||
f.write(v.read())
|
||||
|
||||
Ссылка в новой задаче
Block a user