Signed-off-by: Nicolai Hähnle <nicolai.haehnle@xxxxxxx> --- src/app/gui/commands.c | 50 +++++++++++++++++++++++++++++++++++++ src/app/gui/waves_panel.cpp | 40 +++++++++++++++++++++++++++++ src/lib/scan_waves.c | 2 +- src/umr.h | 2 ++ 4 files changed, 93 insertions(+), 1 deletion(-) diff --git a/src/app/gui/commands.c b/src/app/gui/commands.c index 38ae44d..fb6efa0 100644 --- a/src/app/gui/commands.c +++ b/src/app/gui/commands.c @@ -2036,20 +2036,70 @@ JSON_Value *umr_process_json_request(JSON_Object *request, void **raw_data, unsi answer = json_value_init_object(); waves_to_json(asic, ring_is_halted, 1, json_object(answer)); if (disable_gfxoff && asic->fd.gfxoff >= 0) { uint32_t value = 1; write(asic->fd.gfxoff, &value, sizeof(value)); } if (resume_waves) umr_sq_cmd_halt_waves(asic, UMR_SQ_CMD_RESUME); + } else if (strcmp(command, "singlestep") == 0) { + strcpy(asic->options.ring_name, json_object_get_string(request, "ring")); + + unsigned se = (unsigned)json_object_get_number(request, "se"); + unsigned sh = (unsigned)json_object_get_number(request, "sh"); + unsigned wgp = (unsigned)json_object_get_number(request, "wgp"); + unsigned simd_id = (unsigned)json_object_get_number(request, "simd_id"); + unsigned wave_id = (unsigned)json_object_get_number(request, "wave_id"); + + asic->options.skip_gprs = 0; + asic->options.verbose = 0; + + struct umr_wave_data wd; + memset(&wd, 0, sizeof(wd)); + + int r = umr_scan_wave_slot(asic, se, sh, wgp, simd_id, wave_id, &wd); + if (r < 0) { + last_error = "failed to scan wave slot"; + goto error; + } + + // Send the single-step command in a limited retry loop because a small number of + // single-step commands are required before an instruction is actually issued after + // a branch. + for (int retry = 0; r == 1 && retry < 5; ++retry) { + umr_sq_cmd_singlestep(asic, se, sh, wgp, simd_id, wave_id); + + struct umr_wave_data new_wd; + memset(&new_wd, 0, sizeof(new_wd)); + + r = umr_scan_wave_slot(asic, se, sh, wgp, simd_id, wave_id, &new_wd); + if (r < 0) { + last_error = "failed to scan wave slot"; + goto error; + } + + bool moved = new_wd.ws.pc_lo != wd.ws.pc_lo || new_wd.ws.pc_hi != wd.ws.pc_hi; + memcpy(&wd, &new_wd, sizeof(wd)); + if (moved) + break; + } + + answer = json_value_init_object(); + + if (r == 1) { + JSON_Value *shaders = json_value_init_object(); + JSON_Value *wave = wave_to_json(asic, &wd, 1, /* todo: stream */NULL, shaders); + json_object_set_value(json_object(answer), "wave", wave); + json_object_set_value(json_object(answer), "shaders", shaders); + } } else if (strcmp(command, "resume-waves") == 0) { strcpy(asic->options.ring_name, json_object_get_string(request, "ring")); umr_sq_cmd_halt_waves(asic, UMR_SQ_CMD_RESUME); answer = json_value_init_object(); } else if (strcmp(command, "ring") == 0) { char *ring_name = (char*)json_object_get_string(request, "ring"); uint32_t wptr, rptr, drv_wptr, ringsize, value, *ring_data; int halt_waves = json_object_get_boolean(request, "halt_waves"); enum umr_ring_type rt; asic->options.halt_waves = halt_waves; diff --git a/src/app/gui/waves_panel.cpp b/src/app/gui/waves_panel.cpp index 7e13b48..68b06ea 100644 --- a/src/app/gui/waves_panel.cpp +++ b/src/app/gui/waves_panel.cpp @@ -106,21 +106,38 @@ public: JSON_Array *waves_array = json_object_get_array(json_object(answer), "waves"); int wave_count = json_array_get_count(waves_array); for (int i = 0; i < wave_count; ++i) { JSON_Object *wave = json_object(json_value_deep_copy(json_array_get_value(waves_array, i))); waves.emplace_back(get_wave_id(wave), wave); } JSON_Object *shaders_dict = json_object_get_object(json_object(answer), "shaders"); update_shaders(shaders_dict); + } else if (strcmp(command, "singlestep") == 0) { + JSON_Object *wave = json_object(json_value_deep_copy(json_object_get_value(json_object(answer), "wave"))); + std::string id = get_wave_id(wave ? wave : request); + size_t i = find_wave_by_id(id); + if (i < waves.size()) { + json_value_free(json_object_get_wrapping_value(waves[i].wave)); + if (wave) { + waves[i].wave = wave; + } else { + waves.erase(waves.begin() + i); + } + } else { + if (wave) + waves.emplace_back(id, wave); } + + JSON_Object *shaders_dict = json_object_get_object(json_object(answer), "shaders"); + update_shaders(shaders_dict); } else { return; // should be handled by a different panel } } bool display(float dt, const ImVec2& avail, bool can_send_request) { ImGui::Checkbox("Disable gfxoff", &turn_off_gfxoff); ImGui::SameLine(); ImGui::Checkbox("Halt waves", &halt); if (halt) { @@ -185,20 +202,29 @@ public: ImGui::Columns(1); ImGui::Separator(); ImGui::NextColumn(); ImGui::Text("PC: #b589000x%" PRIx64, (uint64_t)json_object_get_number(wave, "PC")); if (shader_address_str) { ImGui::SameLine(); if (ImGui::Button("View Shader")) { active_shader_wave = waves[i].id; force_scroll = true; } + if (asic->family >= FAMILY_NV) { + ImGui::SameLine(); + ImGui::BeginDisabled(!can_send_request); + if (ImGui::Button("Single step")) { + active_shader_wave = waves[i].id; + send_singlestep_command(waves[i].wave); + } + ImGui::EndDisabled(); + } } else { } ImGui::NextColumn(); if (ImGui::TreeNodeEx("Status")) { ImGui::Columns(4); size_t n = json_object_get_count(status); for (size_t j = 0; j < n; j++) { ImGui::Text("%s: #b58900%d", json_object_get_name(status, j), (unsigned)json_number(json_object_get_value_at(status, j))); ImGui::NextColumn(); @@ -436,20 +462,34 @@ public: private: void send_waves_command(bool halt_waves, bool resume_waves, bool disable_gfxoff) { JSON_Value *req = json_value_init_object(); json_object_set_string(json_object(req), "command", "waves"); json_object_set_boolean(json_object(req), "halt_waves", halt_waves); json_object_set_boolean(json_object(req), "resume_waves", halt_waves && resume_waves); json_object_set_boolean(json_object(req), "disable_gfxoff", disable_gfxoff); json_object_set_string(json_object(req), "ring", asic->family >= FAMILY_NV ? "gfx_0.0.0" : "gfx"); send_request(req); } + + void send_singlestep_command(JSON_Object *wave) { + assert(asic->family >= FAMILY_NV); + JSON_Value *req = json_value_init_object(); + json_object_set_string(json_object(req), "command", "singlestep"); + json_object_set_string(json_object(req), "ring", asic->family >= FAMILY_NV ? "gfx_0.0.0" : "gfx"); + json_object_set_number(json_object(req), "se", json_object_get_number(wave, "se")); + json_object_set_number(json_object(req), "sh", json_object_get_number(wave, "sh")); + json_object_set_number(json_object(req), "wgp", json_object_get_number(wave, "wgp")); + json_object_set_number(json_object(req), "simd_id", json_object_get_number(wave, "simd_id")); + json_object_set_number(json_object(req), "wave_id", json_object_get_number(wave, "wave_id")); + send_request(req); + } + private: struct Wave { std::string id; // "seN.saN.etc" JSON_Object *wave; bool vgpr_show[512] = {}; int vgpr_view[512] = {}; Wave(std::string id, JSON_Object *wave) : id(id), wave(wave) {} }; diff --git a/src/lib/scan_waves.c b/src/lib/scan_waves.c index ca1d9fb..533c5d0 100644 --- a/src/lib/scan_waves.c +++ b/src/lib/scan_waves.c @@ -530,21 +530,21 @@ int umr_parse_wave_data_gfx(struct umr_asic *asic, struct umr_wave_status *ws, c else return umr_parse_wave_data_gfx_10_11(asic, ws, buf); } /** * Scan the given wave slot. Return true and fill in \p pwd if a wave is present. * Otherwise, return false. * * \param cu the CU on <=gfx9, the WGP on >=gfx10 */ -static int umr_scan_wave_slot(struct umr_asic *asic, uint32_t se, uint32_t sh, uint32_t cu, +int umr_scan_wave_slot(struct umr_asic *asic, uint32_t se, uint32_t sh, uint32_t cu, uint32_t simd, uint32_t wave, struct umr_wave_data *pwd) { unsigned thread, num_threads; int r; if (asic->family <= FAMILY_AI) r = asic->wave_funcs.get_wave_status(asic, se, sh, cu, simd, wave, &pwd->ws); else r = asic->wave_funcs.get_wave_status(asic, se, sh, MANY_TO_INSTANCE(cu, simd), 0, wave, &pwd->ws); diff --git a/src/umr.h b/src/umr.h index 8981986..030124f 100644 --- a/src/umr.h +++ b/src/umr.h @@ -1392,20 +1392,22 @@ void umr_free_maps(struct umr_asic *asic); void umr_close_asic(struct umr_asic *asic); // call this to close a fully open asic int umr_query_drm(struct umr_asic *asic, int field, void *ret, int size); int umr_query_drm_vbios(struct umr_asic *asic, int field, int type, void *ret, int size); int umr_update(struct umr_asic *asic, char *script); int umr_update_string(struct umr_asic *asic, char *sdata); /* lib helpers */ uint32_t umr_get_ip_revision(struct umr_asic *asic, const char *ipname); int umr_get_wave_status(struct umr_asic *asic, unsigned se, unsigned sh, unsigned cu, unsigned simd, unsigned wave, struct umr_wave_status *ws); struct umr_wave_data *umr_scan_wave_data(struct umr_asic *asic); +int umr_scan_wave_slot(struct umr_asic *asic, uint32_t se, uint32_t sh, uint32_t cu, + uint32_t simd, uint32_t wave, struct umr_wave_data *pwd); int umr_read_wave_status_via_mmio_gfx8_9(struct umr_asic *asic, uint32_t simd, uint32_t wave, uint32_t *dst, int *no_fields); int umr_read_wave_status_via_mmio_gfx_10_11(struct umr_asic *asic, uint32_t wave, uint32_t *dst, int *no_fields); int umr_parse_wave_data_gfx(struct umr_asic *asic, struct umr_wave_status *ws, const uint32_t *buf); int umr_get_wave_sq_info_vi(struct umr_asic *asic, unsigned se, unsigned sh, unsigned cu, struct umr_wave_status *ws); int umr_get_wave_sq_info(struct umr_asic *asic, unsigned se, unsigned sh, unsigned cu, struct umr_wave_status *ws); int umr_read_sgprs(struct umr_asic *asic, struct umr_wave_status *ws, uint32_t *dst); int umr_read_vgprs(struct umr_asic *asic, struct umr_wave_status *ws, uint32_t thread, uint32_t *dst); int umr_read_sensor(struct umr_asic *asic, int sensor, void *dst, int *size); /* mmio helpers */ -- 2.40.0