[PATCH umr 11/17] gui/waves_panel: refactor the wave storage and wave identification
Nicolai Hähnle
nicolai.haehnle at amd.com
Tue Jun 6 09:17:19 UTC 2023
Store the waves' and shaders' JSON objects individually in STL structures
instead of keeping everything inside of a giant parent JSON object. This
is a first step towards updating individual waves.
At the same time, identify waves by their HW ID. This makes the collapsed
overview more informative and presumably behaves better if the set of
active waves changes between queries.
Also handle the CU/WGP distinction correctly for gfx10+ and add some
robustness to the active shader display.
Signed-off-by: Nicolai Hähnle <nicolai.haehnle at amd.com>
---
src/app/gui/waves_panel.cpp | 280 ++++++++++++++++++++++--------------
1 file changed, 170 insertions(+), 110 deletions(-)
diff --git a/src/app/gui/waves_panel.cpp b/src/app/gui/waves_panel.cpp
index fa4521e..7e13b48 100644
--- a/src/app/gui/waves_panel.cpp
+++ b/src/app/gui/waves_panel.cpp
@@ -18,149 +18,185 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*/
#include "panels.h"
#include <regex.h>
+#include <unordered_map>
class WavesPanel : public Panel {
public:
WavesPanel(struct umr_asic *asic) : Panel(asic) {
/* SGPR */
shader_syntax.add_definition("(s[[:digit:]]+|s\\[[[:digit:]]+:[[:digit:]]+\\])", { "#d33682" });
/* VGPR */
shader_syntax.add_definition("(v[[:digit:]]+|v\\[[[:digit:]]+:[[:digit:]]+\\])", { "#6c71c4" });
/* Constants */
shader_syntax.add_definition("(0x[[:digit:]]*)\\b", { "#b58900" });
/* Comments */
shader_syntax.add_definition("(;)", { "#586e75" });
/* Keywords */
shader_syntax.add_definition("(attr[[:digit:]]+|exec|m0|[[:alpha:]]+cnt\\([[:digit:]]\\))", { "#3097a1" });
}
+ ~WavesPanel() {
+ clear_waves_and_shaders();
+ }
+
+ void clear_waves_and_shaders() {
+ for (const auto &wave : waves)
+ json_value_free(json_object_get_wrapping_value(wave.wave));
+ waves.clear();
+
+ for (const auto &entry : shaders)
+ json_value_free(json_object_get_wrapping_value(entry.second));
+ shaders.clear();
+ }
+
+ std::string get_wave_id(JSON_Object *wave) {
+ unsigned se = (unsigned int)json_object_get_number(wave, "se");
+ unsigned sh = (unsigned int)json_object_get_number(wave, "sh");
+ unsigned cu = (unsigned int)json_object_get_number(wave, "cu");
+ unsigned wgp = (unsigned int)json_object_get_number(wave, "wgp");
+ unsigned simd_id = (unsigned int)json_object_get_number(wave, "simd_id");
+ unsigned wave_id = (unsigned int)json_object_get_number(wave, "wave_id");
+
+ char id[128];
+ if (asic->family < FAMILY_NV) {
+ snprintf(id, sizeof(id), "se%u.sa%u.cu%u.simd%u.wave%u", se, sh, cu, simd_id, wave_id);
+ } else {
+ snprintf(id, sizeof(id), "se%u.sa%u.wgp%u.simd%u.wave%u", se, sh, wgp, simd_id, wave_id);
+ }
+
+ return id;
+ }
+
+ size_t find_wave_by_id(const std::string &id) {
+ size_t i;
+ for (i = 0; i < waves.size(); ++i) {
+ if (waves[i].id == id)
+ break;
+ }
+ return i;
+ }
+
+ void update_shaders(JSON_Object *shaders_dict) {
+ int shaders_count = json_object_get_count(shaders_dict);
+ for (int i = 0; i < shaders_count; ++i) {
+ shaders.emplace(json_object_get_name(shaders_dict, i),
+ json_object(json_value_deep_copy(json_object_get_value_at(shaders_dict, i))));
+ }
+ }
+
void process_server_message(JSON_Object *response, void *raw_data, unsigned raw_data_size) {
JSON_Value *error = json_object_get_value(response, "error");
if (error)
return;
JSON_Object *request = json_object(json_object_get_value(response, "request"));
JSON_Value *answer = json_object_get_value(response, "answer");
const char *command = json_object_get_string(request, "command");
- if (strcmp(command, "waves"))
- return;
+ if (strcmp(command, "waves") == 0) {
+ active_shader_wave.clear();
+ clear_waves_and_shaders();
- active_shader = NULL;
- if (last_answer) {
- json_value_free(json_object_get_wrapping_value(last_answer));
- }
- last_answer = json_object(json_value_deep_copy(answer));
-
- details.max_vgpr = 0;
-
- JSON_Array *waves = json_array(json_object_get_value(last_answer, "waves"));
- int wave_count = json_array_get_count(waves);
- for (int i = 0; i < wave_count ; i++) {
- JSON_Object *wave = json_object(json_array_get_value(waves, i));
- JSON_Value *vgpr = json_object_get_value(wave, "vgpr");
- if (vgpr) {
- int s = json_array_get_count(json_array(vgpr));
- details.max_vgpr = std::max(s, details.max_vgpr);
+ 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);
}
- }
- if (details.max_vgpr) {
- details.vgpr = (bool*)realloc(details.vgpr, wave_count * details.max_vgpr);
- details.view = (int*)realloc(details.view, wave_count * details.max_vgpr * sizeof(int));
- memset(details.vgpr, 0, wave_count * details.max_vgpr);
- memset(details.view, 0, wave_count * details.max_vgpr * sizeof(int));
+ 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) {
ImGui::SameLine();
ImGui::Checkbox("Resume waves", &resume);
}
ImGui::SameLine();
ImGui::BeginDisabled(!can_send_request);
if (ImGui::Button("Query")) {
send_waves_command(halt, resume, turn_off_gfxoff);
}
ImGui::EndDisabled();
ImGui::Separator();
- if (last_answer) {
+ if (!waves.empty()) {
ImGui::BeginChild("Waves", ImVec2(avail.x / 2, 0), false, ImGuiWindowFlags_NoTitleBar);
- JSON_Array *waves = json_object_get_array(last_answer, "waves");
- JSON_Object *shaders = json_object(json_object_get_value(last_answer, "shaders"));
bool force_scroll = false;
- int w = json_array_get_count(waves);
- for (int i = 0; i < w; i++) {
- JSON_Object *wave = json_object(json_array_get_value(waves, i));
+ for (size_t i = 0; i < waves.size(); ++i) {
+ JSON_Object *wave = waves[i].wave;
JSON_Object *status = json_object(json_object_get_value(wave, "status"));
- ImGui::PushID(i);
-
int active_threads = -1;
JSON_Array *threads = json_object_get_array(wave, "threads");
if (threads) {
active_threads = 0;
int s = json_array_get_count(threads);
for (int i = 0; i < s; i++) {
active_threads += json_array_get_boolean(threads, i);
}
}
const char *shader_address_str = json_object_get_string(wave, "shader");
char label[256];
if (active_threads < 0)
- sprintf(label, "Wave %d", i);
+ sprintf(label, "Wave %s", waves[i].id.c_str());
else if (shader_address_str)
- sprintf(label, "Wave %d (#dbde79%d threads, valid PC)", i, active_threads);
+ sprintf(label, "Wave %s (#dbde79%d threads, valid PC)", waves[i].id.c_str(), active_threads);
else
- sprintf(label, "Wave %d (#dbde79%d threads)", i, active_threads);
+ sprintf(label, "Wave %s (#dbde79%d threads)", waves[i].id.c_str(), active_threads);
- if (ImGui::TreeNode(label)) {
+ if (ImGui::TreeNode(waves[i].id.c_str(), "%s", label)) {
ImGui::Columns(3);
ImGui::Text("se: #586e750x%x", (unsigned int)json_object_get_number(wave, "se"));
ImGui::NextColumn();
ImGui::Text("sh: #586e750x%x", (unsigned int)json_object_get_number(wave, "sh"));
ImGui::NextColumn();
- ImGui::Text("cu: #586e750x%x", (unsigned int)json_object_get_number(wave, "cu"));
- ImGui::NextColumn();
+ if (asic->family < FAMILY_NV) {
+ ImGui::Text("cu: #586e750x%x", (unsigned int)json_object_get_number(wave, "cu"));
+ ImGui::NextColumn();
+ } else {
+ ImGui::Text("wgp: #586e750x%x", (unsigned int)json_object_get_number(wave, "wgp"));
+ ImGui::NextColumn();
+ }
ImGui::Text("simd_id: #586e750x%x", (unsigned int)json_object_get_number(wave, "simd_id"));
ImGui::NextColumn();
ImGui::Text("wave_id: #586e750x%x", (unsigned int)json_object_get_number(wave, "wave_id"));
ImGui::NextColumn();
ImGui::NextColumn();
ImGui::Text("wave_inst_dw0: #586e750x%08x", (unsigned int)json_object_get_number(wave, "wave_inst_dw0"));
ImGui::NextColumn();
ImGui::Text("wave_inst_dw1: #586e750x%08x", (unsigned int)json_object_get_number(wave, "wave_inst_dw1"));
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 = json_object(json_object_get_value(shaders, shader_address_str));
- sscanf(shader_address_str, "%" PRIx64, &base_address);
- pc = json_object_get_number(wave, "PC");
-
+ active_shader_wave = waves[i].id;
force_scroll = true;
}
} 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),
@@ -245,23 +281,23 @@ public:
ImGui::TableSetupColumn("+ 2");
ImGui::TableSetupColumn("+ 3");
ImGui::TableHeadersRow();
char label[128];
for (int vg = 0; vg < s; vg++) {
ImGui::PushID(vg);
ImGui::TableNextRow();
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, ImGui::GetColorU32(ImGuiCol_TableRowBgAlt));
ImGui::TableSetColumnIndex(0);
sprintf(label, "show v%2d", vg);
- ImGui::Checkbox(label, &details.vgpr[i * details.max_vgpr + vg]);
- if (details.vgpr[i * details.max_vgpr + vg]) {
- int *mode = &details.view[i * details.max_vgpr + vg];
+ ImGui::Checkbox(label, &waves[i].vgpr_show[vg]);
+ if (waves[i].vgpr_show[vg]) {
+ int *mode = &waves[i].vgpr_view[vg];
ImGui::TableSetColumnIndex(1);
ImGui::RadioButton("as int", mode, 0);
ImGui::TableSetColumnIndex(2);
ImGui::RadioButton("as uint", mode, 1);
ImGui::TableSetColumnIndex(3);
ImGui::RadioButton("as hex", mode, 2);
ImGui::TableSetColumnIndex(4);
ImGui::RadioButton("as float", mode, 3);
JSON_Array *vgp = json_array_get_array(vgpr, vg);
@@ -302,102 +338,126 @@ public:
json_array_get_boolean(threads, i) ?
"#859900on" : "#dc322foff");
ImGui::NextColumn();
}
ImGui::Columns(1);
ImGui::TreePop();
}
ImGui::TreePop();
}
- ImGui::PopID();
}
ImGui::EndChild();
ImGui::SameLine();
ImGui::BeginChild("Shaders", ImVec2(avail.x / 2, 0), false, ImGuiWindowFlags_NoTitleBar);
- if (active_shader) {
- int scroll = 0;
- JSON_Array *op = json_object_get_array(active_shader, "opcodes");
- uint32_t *copy = new uint32_t[json_array_get_count(op)];
- for (size_t j = 0; j < json_array_get_count(op); j++)
- copy[j] = (uint32_t)json_array_get_number(op, j);
-
- uint64_t base_address = json_object_get_number(active_shader, "address");
- char **opcode_strs = NULL;
- umr_shader_disasm(asic, (uint8_t *)copy, json_array_get_count(op) * 4, base_address, &opcode_strs);
-
- char tmp[128];
- sprintf(tmp, "0x%" PRIx64, base_address);
-
- ImGui::BeginTable("shader", 3, ImGuiTableFlags_Borders);
- ImGui::TableSetupColumn(tmp, ImGuiTableColumnFlags_WidthFixed, ImGui::CalcTextSize(" 0x0000000000 ").x);
- ImGui::TableSetupColumn("Raw Value", ImGuiTableColumnFlags_WidthFixed, ImGui::CalcTextSize( "0x00000000 ").x);
- ImGui::TableSetupColumn("Disassembly");
- ImGui::TableHeadersRow();
- for (size_t j = 0; j < json_array_get_count(op); j++) {
- uint64_t addr = base_address + j * 4;
- bool is_pc = pc == addr;
- if (is_pc) {
- /* PC points to this instruction */
- scroll = ImGui::GetCursorPos().y;
- ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0, 0.5, 0.5, 1));
- }
-
- ImGui::TableNextRow();
- ImGui::TableSetColumnIndex(0);
- ImGui::Text("+ 0x%lx", j * 4);
- if (ImGui::IsItemHovered()) {
- ImGui::BeginTooltip();
- ImGui::Text("0x%" PRIx64, base_address + j * 4);
- ImGui::EndTooltip();
- }
- ImGui::TableSetColumnIndex(1);
- ImGui::Text("0x%08x", (uint32_t)json_array_get_number(op, j));
- ImGui::TableSetColumnIndex(2);
- ImGui::Text("%s", shader_syntax.transform(opcode_strs[j]));
- free(opcode_strs[j]);
- if (is_pc)
- ImGui::PopStyleColor(1);
- }
- ImGui::EndTable();
- free(opcode_strs);
- delete[] copy;
-
- if (force_scroll) {
- ImGui::SetScrollY(scroll - avail.y / 2);
- force_redraw();
- }
- } else {
- ImGui::Text("Click on a wave's PC to show its shader disassembly");
- }
+ display_active_shader(dt, avail, force_scroll);
ImGui::EndChild();
} else {
ImGui::Text("No waves.");
}
return false;
}
+ void display_active_shader(float dt, const ImVec2& avail, bool force_scroll) {
+ if (active_shader_wave.empty()) {
+ ImGui::Text("Click on a wave's PC to show its shader disassembly");
+ return;
+ }
+
+ size_t i = find_wave_by_id(active_shader_wave);
+ if (i >= waves.size()) {
+ ImGui::Text("Selected wave has disappeared");
+ return;
+ }
+
+ JSON_Object *wave = waves[i].wave;
+ const char *shader_address_str = json_object_get_string(wave, "shader");
+ auto shader_it = shaders.find(shader_address_str);
+ if (shader_it == shaders.end()) {
+ ImGui::Text("Error: Shader for selected wave is unavailable");
+ return;
+ }
+
+ JSON_Object *shader = shader_it->second;
+ uint64_t pc = json_object_get_number(wave, "PC");
+
+ int scroll = 0;
+ JSON_Array *op = json_object_get_array(shader, "opcodes");
+ uint32_t *copy = new uint32_t[json_array_get_count(op)];
+ for (size_t j = 0; j < json_array_get_count(op); j++)
+ copy[j] = (uint32_t)json_array_get_number(op, j);
+
+ uint64_t base_address = json_object_get_number(shader, "address");
+ char **opcode_strs = NULL;
+ umr_shader_disasm(asic, (uint8_t *)copy, json_array_get_count(op) * 4, base_address, &opcode_strs);
+
+ char tmp[128];
+ sprintf(tmp, "0x%" PRIx64, base_address);
+
+ ImGui::BeginTable("shader", 3, ImGuiTableFlags_Borders);
+ ImGui::TableSetupColumn(tmp, ImGuiTableColumnFlags_WidthFixed, ImGui::CalcTextSize(" 0x0000000000 ").x);
+ ImGui::TableSetupColumn("Raw Value", ImGuiTableColumnFlags_WidthFixed, ImGui::CalcTextSize( "0x00000000 ").x);
+ ImGui::TableSetupColumn("Disassembly");
+ ImGui::TableHeadersRow();
+ for (size_t j = 0; j < json_array_get_count(op); j++) {
+ uint64_t addr = base_address + j * 4;
+ bool is_pc = pc == addr;
+ if (is_pc) {
+ /* PC points to this instruction */
+ scroll = ImGui::GetCursorPos().y;
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0, 0.5, 0.5, 1));
+ }
+
+ ImGui::TableNextRow();
+ ImGui::TableSetColumnIndex(0);
+ ImGui::Text("+ 0x%lx", j * 4);
+ if (ImGui::IsItemHovered()) {
+ ImGui::BeginTooltip();
+ ImGui::Text("0x%" PRIx64, base_address + j * 4);
+ ImGui::EndTooltip();
+ }
+ ImGui::TableSetColumnIndex(1);
+ ImGui::Text("0x%08x", (uint32_t)json_array_get_number(op, j));
+ ImGui::TableSetColumnIndex(2);
+ ImGui::Text("%s", shader_syntax.transform(opcode_strs[j]));
+ free(opcode_strs[j]);
+ if (is_pc)
+ ImGui::PopStyleColor(1);
+ }
+ ImGui::EndTable();
+ free(opcode_strs);
+ delete[] copy;
+
+ if (force_scroll) {
+ ImGui::SetScrollY(scroll - avail.y / 2);
+ force_redraw();
+ }
+ }
+
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);
}
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) {}
+ };
+
SyntaxHighlighter shader_syntax;
- JSON_Object *last_answer = NULL;
- JSON_Object *active_shader = NULL;
- uint64_t base_address;
- uint64_t pc;
- struct {
- bool *vgpr = NULL;
- int *view = NULL;
- int max_vgpr;
- } details;
+ std::vector<Wave> waves;
+ std::unordered_map<std::string, JSON_Object *> shaders;
+ std::string active_shader_wave;
bool halt = true;
bool resume = true;
bool turn_off_gfxoff = true;
};
--
2.40.0
More information about the amd-gfx
mailing list