diff --git a/CHANGELOG.md b/CHANGELOG.md index 3152c5a809..96d3b0a963 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/README.md b/README.md index 357c6eb7f7..c8ad2eb8c2 100644 --- a/README.md +++ b/README.md @@ -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 ` 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= ``` + Or, alternatively, use the continuous ATT mode (DISPATCH_RANGE parameter). + *** ### Flush Interval diff --git a/plugin/att/att.py b/plugin/att/att.py index 2c42dbdf5f..725f9845d2 100755 --- a/plugin/att/att.py +++ b/plugin/att/att.py @@ -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, diff --git a/plugin/att/code_printing.cpp b/plugin/att/code_printing.cpp index f6ab9c2a10..dc87022f37 100644 --- a/plugin/att/code_printing.cpp +++ b/plugin/att/code_printing.cpp @@ -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 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(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(codeobj_data, codeobj_size, std::nullopt); // Can throw + // Can throw + disassembly = std::make_unique(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(buffer.data(), buffer.size()); + decoder = std::make_unique(buffer.data(), buffer.size(), gpu_id); } else { std::unique_ptr binary = std::make_unique(filepath); auto& buffer = binary->buffer; - decoder = std::make_unique(buffer.data(), buffer.size()); + decoder = std::make_unique(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) diff --git a/plugin/att/code_printing.hpp b/plugin/att/code_printing.hpp index 5e5a294080..a9861a04a1 100644 --- a/plugin/att/code_printing.hpp +++ b/plugin/att/code_printing.hpp @@ -37,7 +37,7 @@ class CodeObjDecoderComponent public: std::optional 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 @@ -48,7 +48,7 @@ public: int m_fd; - std::map> m_line_number_map{}; + std::map> m_line_number_map{}; std::map 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(filepath, loadbase, memsize); + decoders[id] = std::make_shared(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(ptr->size()), id, 0}); } diff --git a/plugin/att/disassembly.cpp b/plugin/att/disassembly.cpp index 659d068892..b2aa109cd8 100644 --- a/plugin/att/disassembly.cpp +++ b/plugin/att/disassembly.cpp @@ -70,6 +70,8 @@ if (amd_comgr_status_s status = call) { return AMD_COMGR_STATUS_ERROR; \ } +std::unordered_map 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 input_isa + uint64_t gpu_id ) { buffer = std::vector(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)); diff --git a/plugin/att/disassembly.hpp b/plugin/att/disassembly.hpp index 64bec5147a..37acabc79b 100644 --- a/plugin/att/disassembly.hpp +++ b/plugin/att/disassembly.hpp @@ -51,7 +51,7 @@ class DisassemblyInstance { DisassemblyInstance( const char* codeobj_data, uint64_t codeobj_size, - std::optional 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 agent_isa_name; std::optional va2fo(uint64_t va); std::vector> getSegments(); diff --git a/plugin/att/service.py b/plugin/att/service.py index 4bb61913ac..439ac8e3dd 100644 --- a/plugin/att/service.py +++ b/plugin/att/service.py @@ -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) diff --git a/plugin/att/trace_view.py b/plugin/att/trace_view.py index f637222ac7..e11b882bc7 100755 --- a/plugin/att/trace_view.py +++ b/plugin/att/trace_view.py @@ -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( - '
  • ' - + str(i).ljust(5) - + fix_space(l) - + "
  • " - 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())