From 877791baa845cbc22dde981b3c64656722f9f75d Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Sat, 2 Sep 2023 00:12:18 +0200 Subject: [PATCH 01/22] WIP: Conceptual Stmt IR and HTML cleanup. --- .gitignore | 3 + Makefile | 13 +- .../bilateral_grid_generator.cpp | 2 +- src/Generator.cpp | 3 +- src/Lower.cpp | 3 + src/Module.cpp | 50 +- src/Module.h | 10 + src/StmtToViz.cpp | 493 ++++++++------- src/StmtToViz.h | 17 +- .../StmtToViz_dependencies.template.html | 25 - .../StmtToViz_javascript.template.html | 415 ------------- src/irvisualizer/html_template_StmtToHTML.css | 570 ++++++++++++++++++ src/irvisualizer/html_template_StmtToHTML.js | 220 +++++++ ...html_template_StmtToHTML_dependencies.html | 21 + ...plate.html => html_template_StmtToViz.css} | 0 src/irvisualizer/html_template_StmtToViz.js | 272 +++++++++ .../html_template_StmtToViz_dependencies.html | 4 + 17 files changed, 1460 insertions(+), 661 deletions(-) delete mode 100644 src/irvisualizer/StmtToViz_dependencies.template.html delete mode 100644 src/irvisualizer/StmtToViz_javascript.template.html create mode 100644 src/irvisualizer/html_template_StmtToHTML.css create mode 100644 src/irvisualizer/html_template_StmtToHTML.js create mode 100644 src/irvisualizer/html_template_StmtToHTML_dependencies.html rename src/irvisualizer/{StmtToViz_stylesheet.template.html => html_template_StmtToViz.css} (100%) create mode 100644 src/irvisualizer/html_template_StmtToViz.js create mode 100644 src/irvisualizer/html_template_StmtToViz_dependencies.html diff --git a/.gitignore b/.gitignore index 4a19876f849a..2a338353fa36 100644 --- a/.gitignore +++ b/.gitignore @@ -234,6 +234,9 @@ xcuserdata # Vim .clang_complete +# NeoVim + clangd +.cache + # Emacs tags TAGS diff --git a/Makefile b/Makefile index 244fcc00d4e5..f0e7d977b938 100644 --- a/Makefile +++ b/Makefile @@ -641,9 +641,12 @@ SOURCE_FILES = \ CodeGen_C_vectors HTML_TEMPLATE_FILES = \ - StmtToViz_dependencies \ - StmtToViz_javascript \ - StmtToViz_stylesheet + StmtToHTML_dependencies.html \ + StmtToHTML.js \ + StmtToHTML.css \ + StmtToViz_dependencies.html \ + StmtToViz.js \ + StmtToViz.css # The externally-visible header files that go into making Halide.h. # Don't include anything here that includes llvm headers. @@ -1199,8 +1202,8 @@ $(BUILD_DIR)/initmod_ptx.%_ll.cpp: $(BIN_DIR)/binary2cpp $(SRC_DIR)/runtime/nvid $(BUILD_DIR)/c_template.%.cpp: $(BIN_DIR)/binary2cpp $(SRC_DIR)/%.template.cpp ./$(BIN_DIR)/binary2cpp halide_c_template_$* < $(SRC_DIR)/$*.template.cpp > $@ -$(BUILD_DIR)/html_template.%.cpp: $(BIN_DIR)/binary2cpp $(SRC_DIR)/irvisualizer/%.template.html - ./$(BIN_DIR)/binary2cpp halide_html_template_$* < $(SRC_DIR)/irvisualizer/$*.template.html > $@ +$(BUILD_DIR)/html_template.%.cpp: $(BIN_DIR)/binary2cpp $(SRC_DIR)/irvisualizer/html_template_% + ./$(BIN_DIR)/binary2cpp halide_html_template_$(subst .,_,$*) < $(SRC_DIR)/irvisualizer/html_template_$* > $@ $(BIN_DIR)/binary2cpp: $(ROOT_DIR)/tools/binary2cpp.cpp @mkdir -p $(@D) diff --git a/apps/bilateral_grid/bilateral_grid_generator.cpp b/apps/bilateral_grid/bilateral_grid_generator.cpp index 7ef7102d081c..b885ec66ba35 100644 --- a/apps/bilateral_grid/bilateral_grid_generator.cpp +++ b/apps/bilateral_grid/bilateral_grid_generator.cpp @@ -84,7 +84,7 @@ class BilateralGrid : public Halide::Generator { // nothing } else if (get_target().has_gpu_feature()) { // 0.50ms on an RTX 2060 - + std::printf("GPU SCHEDULING\n"); Var xi("xi"), yi("yi"), zi("zi"); // Schedule blurz in 8x8 tiles. This is a tile in diff --git a/src/Generator.cpp b/src/Generator.cpp index 67a132a4d4d9..4ea3e4effc54 100644 --- a/src/Generator.cpp +++ b/src/Generator.cpp @@ -652,7 +652,8 @@ gengen -e A comma separated list of files to emit. Accepted values are: [assembly, bitcode, c_header, c_source, cpp_stub, featurization, llvm_assembly, object, python_extension, pytorch_wrapper, registration, - schedule, static_library, stmt, stmt_html, compiler_log, hlpipe]. + schedule, static_library, stmt, stmt_html, conceptual_stmt, + conceptual_stmt_html, compiler_log, hlpipe, ptx_assembly]. If omitted, default value is [c_header, static_library, registration]. -p A comma-separated list of shared libraries that will be loaded before the diff --git a/src/Lower.cpp b/src/Lower.cpp index ecff36ee58b4..1492a4a9feb5 100644 --- a/src/Lower.cpp +++ b/src/Lower.cpp @@ -432,6 +432,9 @@ void lower_impl(const vector &output_funcs, } } + // Make a copy of the Stmt code, before we lower anything to 2GL. + result_module.set_conceptual_code_stmt(s); + if (t.arch != Target::Hexagon && t.has_feature(Target::HVX)) { debug(1) << "Splitting off Hexagon offload...\n"; s = inject_hexagon_rpc(s, t, result_module); diff --git a/src/Module.cpp b/src/Module.cpp index 89239e41086c..74c7233bfd47 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -49,7 +49,10 @@ std::map get_output_info(const Target &target) {OutputFileType::schedule, {"schedule", ".schedule.h", IsSingle}}, {OutputFileType::static_library, {"static_library", is_windows_coff ? ".lib" : ".a", IsSingle}}, {OutputFileType::stmt, {"stmt", ".stmt", IsMulti}}, + {OutputFileType::conceptual_stmt, {"coneptual_stmt", ".conceptual.stmt", IsMulti}}, {OutputFileType::stmt_html, {"stmt_html", ".stmt.html", IsMulti}}, + {OutputFileType::conceptual_stmt_html, {"conceptual_stmt_html", ".conceptual.stmt.html", IsMulti}}, + {OutputFileType::ptx_assembly, {"ptx_assembly", ".ptx", IsMulti}}, }; return ext; } @@ -325,6 +328,12 @@ struct ModuleContents { MetadataNameMap metadata_name_map; bool any_strict_float{false}; std::unique_ptr auto_scheduler_results; + + /** This is a copy of the code throughout the lowering process, which + * reflects best the actual pipeline, without introducing assembly generated + * from device-specific offloads (such as Cuda PTX). In other words, we'd + * like to keep this 3GL. */ + Stmt conceptual_code; }; template<> @@ -519,6 +528,14 @@ MetadataNameMap Module::get_metadata_name_map() const { return contents->metadata_name_map; } +void Module::set_conceptual_code_stmt(const Internal::Stmt &stmt) { + contents->conceptual_code = stmt; +} + +const Internal::Stmt &Module::get_conceptual_stmt() const { + return contents->conceptual_code; +} + void Module::compile(const std::map &output_files) const { validate_outputs(output_files); @@ -551,7 +568,7 @@ void Module::compile(const std::map &output_files) std::string assembly_path; if (contains(output_files, OutputFileType::assembly)) { assembly_path = output_files.at(OutputFileType::assembly); - } else if (contains(output_files, OutputFileType::stmt_html)) { + } else if (contains(output_files, OutputFileType::stmt_html) || contains(output_files, OutputFileType::conceptual_stmt_html)) { // We need assembly in order to generate stmt_html, but the user doesn't // want it on its own, so we will generate it to a temp directory, since some // build systems (e.g. Bazel) are strict about what you can generate to the 'expected' @@ -627,10 +644,39 @@ void Module::compile(const std::map &output_files) std::ofstream file(output_files.at(OutputFileType::stmt)); file << *this; } + if (contains(output_files, OutputFileType::conceptual_stmt)) { + debug(1) << "Module.compile(): conceptual_stmt " << output_files.at(OutputFileType::conceptual_stmt) << "\n"; + std::ofstream file(output_files.at(OutputFileType::conceptual_stmt)); + file << get_conceptual_stmt(); + } if (contains(output_files, OutputFileType::stmt_html)) { internal_assert(!assembly_path.empty()); debug(1) << "Module.compile(): stmt_html " << output_files.at(OutputFileType::stmt_html) << "\n"; - Internal::print_to_viz(output_files.at(OutputFileType::stmt_html), *this, assembly_path); + Internal::print_to_stmt_html(output_files.at(OutputFileType::stmt_html), *this, assembly_path, false); + } + if (contains(output_files, OutputFileType::conceptual_stmt_html)) { + internal_assert(!assembly_path.empty()); + debug(1) << "Module.compile(): conceptual_stmt_html " << output_files.at(OutputFileType::stmt_html) << "\n"; + Internal::print_to_conceptual_stmt_html(output_files.at(OutputFileType::conceptual_stmt_html), *this, assembly_path); + } + if (contains(output_files, OutputFileType::ptx_assembly)) { + debug(1) << "Module.compile(): ptx_assembly " << output_files.at(OutputFileType::ptx_assembly) << "\n"; + std::string gpu_kernel_sources; + for (const Buffer<> &buf : buffers()) { + debug(1) << "Looking for GPU sources: " << buf.name() << "\n"; + if (ends_with(buf.name(), "_gpu_source_kernels")) { + internal_assert(gpu_kernel_sources.empty()); // There should be only one! + gpu_kernel_sources = std::string((const char *)buf.data(), buf.size_in_bytes()); + } + } + if (gpu_kernel_sources.empty()) { + debug(1) << "No GPU kernel sources emitted.\n"; + } else { + std::ofstream file(output_files.at(OutputFileType::ptx_assembly)); + file << gpu_kernel_sources << "\n"; + file.close(); + debug(1) << "Saved GPU kernel sources (" << gpu_kernel_sources.size() << " bytes).\n"; + } } if (contains(output_files, OutputFileType::function_info_header)) { debug(1) << "Module.compile(): function_info_header " << output_files.at(OutputFileType::function_info_header) << "\n"; diff --git a/src/Module.h b/src/Module.h index 779c837036e2..a5ee5a7c4ef3 100644 --- a/src/Module.h +++ b/src/Module.h @@ -41,7 +41,10 @@ enum class OutputFileType { schedule, static_library, stmt, + conceptual_stmt, stmt_html, + conceptual_stmt_html, + ptx_assembly, }; /** Type of linkage a function in a lowered Halide module can have. @@ -201,6 +204,13 @@ class Module { /** Set whether this module uses strict floating-point directives anywhere. */ void set_any_strict_float(bool any_strict_float); + + /** Remember the Stmt during lowing which is still 3GL, before device-specific + * offloading. */ + void set_conceptual_code_stmt(const Internal::Stmt &stmt); + + /** Get the remembered Stmt which is supposed to be 3GL. */ + const Internal::Stmt &get_conceptual_stmt() const; }; /** Link a set of modules together into one module. */ diff --git a/src/StmtToViz.cpp b/src/StmtToViz.cpp index f41a74424306..40538bff915c 100644 --- a/src/StmtToViz.cpp +++ b/src/StmtToViz.cpp @@ -17,12 +17,29 @@ #include #include +// Setting this to 0 is meant to speed up the development iteration cycle. +// Not inlining these template files, but just linking them by an absolute path +// causes you to be able to just edit the files without having to recompile Halide +// and then rerun your generator. +// For distribution purposes, they should be inlined, and this define should be on 1. +#define INLINE_TEMPLATES 0 // nocheckin + +#if !INLINE_TEMPLATES +#include +#endif + namespace Halide { namespace Internal { -extern "C" unsigned char halide_html_template_StmtToViz_dependencies[]; -extern "C" unsigned char halide_html_template_StmtToViz_stylesheet[]; -extern "C" unsigned char halide_html_template_StmtToViz_javascript[]; +// Simple HTML specific +extern "C" unsigned char halide_html_template_StmtToHTML_dependencies_html[]; +extern "C" unsigned char halide_html_template_StmtToHTML_css[]; +extern "C" unsigned char halide_html_template_StmtToHTML_js[]; + +// Viz Tree specific +extern "C" unsigned char halide_html_template_StmtToViz_dependencies_html[]; +extern "C" unsigned char halide_html_template_StmtToViz_css[]; +extern "C" unsigned char halide_html_template_StmtToViz_js[]; // Classes defined within this file class CostModel; @@ -39,9 +56,7 @@ class IRVisualizer; */ class IRCostModel : public IRVisitor { public: - IRCostModel() - - = default; + IRCostModel() = default; // Pre-compute all costs to avoid repeated work void compute_all_costs(const Module &m) { @@ -49,7 +64,13 @@ class IRCostModel : public IRVisitor { for (const auto &fn : m.functions()) { fn.body.accept(this); } + } + + void compute_conceptual_costs(const Module &m) { + m.get_conceptual_stmt().accept(this); + } + void finalize_cost_computation() { // Compute the max cost for each category max_compute_cost = -1; for (auto const &entry : compute_cost) { @@ -619,8 +640,10 @@ class AssemblyInfo : public IRVisitor { template class HTMLCodePrinter : public IRVisitor { public: - HTMLCodePrinter(T &os, std::map &nids) - : stream(os), node_ids(nids), context_stack(1, 0) { + HTMLCodePrinter(T &os, std::map &nids, bool enable_viztree_features, bool enable_assembly_features) + : stream(os), node_ids(nids), context_stack(1, 0), + enable_viztree_features(enable_viztree_features), + enable_assembly_features(enable_assembly_features) { } // Make class non-copyable and non-moveable @@ -631,6 +654,49 @@ class HTMLCodePrinter : public IRVisitor { cost_model = std::move(cm); } + void print_conceptual_stmt(const Module &m, AssemblyInfo asm_info) { + assembly_info = std::move(asm_info); + + // Generate a unique ID for this module + int id = gen_unique_id(); + + // Enter new scope for this module + scope.push(m.name(), id); + + // Open div to hold this module + print_opening_tag("div", "Module"); + + // Generate the show hide icon/text buttons + print_show_hide_btn_begin(id); + + // -- print text + print_opening_tag("span", "matched"); + print_html_element("span", "keyword", "module"); + print_text(" name=" + m.name() + ", target=" + m.target().to_string()); + print_closing_tag("span"); + + // Open code block to hold module body + print_html_element("span", "matched", " {"); + print_show_hide_btn_end(); + + // Open indented div to hold body code + print_opening_tag("div", "indent ModuleBody", id); + + print(m.get_conceptual_stmt()); + + // Close indented div holding body code + print_closing_tag("div"); + + // Close code block holding module body + print_html_element("span", "matched ClosingBrace cb-" + std::to_string(id), "}"); + + // Close div holding this module + print_closing_tag("div"); + + // Pop out to outer scope + scope.pop(m.name()); + } + void print(const Module &m, AssemblyInfo asm_info) { assembly_info = std::move(asm_info); @@ -649,10 +715,7 @@ class HTMLCodePrinter : public IRVisitor { print_opening_tag("div", "Module"); // Generate the show hide icon/text buttons - print_toggle_anchor_opening_tag(id); - - // -- print icon - print_show_hide_icon(id); + print_show_hide_btn_begin(id); // -- print text print_opening_tag("span", "matched"); @@ -660,10 +723,9 @@ class HTMLCodePrinter : public IRVisitor { print_text(" name=" + m.name() + ", target=" + m.target().to_string()); print_closing_tag("span"); - print_toggle_anchor_closing_tag(); - // Open code block to hold module body print_html_element("span", "matched", " {"); + print_show_hide_btn_end(); // Open indented div to hold body code print_opening_tag("div", "indent ModuleBody", id); @@ -711,6 +773,8 @@ class HTMLCodePrinter : public IRVisitor { // Holds cost information for visualized program IRCostModel cost_model; AssemblyInfo assembly_info; + bool enable_viztree_features; + bool enable_assembly_features; /* Private print functions to handle various IR types */ void print(const Buffer<> &buf) { @@ -725,22 +789,18 @@ class HTMLCodePrinter : public IRVisitor { if (print_data) { // Generate the show hide icon/text buttons - print_toggle_anchor_opening_tag(id); - - // -- print icon - print_show_hide_icon(id); + print_show_hide_btn_begin(id, true); // -- print text print_html_element("span", "keyword", "buffer "); print_variable(buf.name()); - print_toggle_anchor_closing_tag(); - // Print data print_text(" = "); // Open code block to hold module body print_html_element("span", "matched", " {"); + print_show_hide_btn_end(); // Open indented div to hold buffer data print_opening_tag("div", "indent BufferData", id); @@ -778,28 +838,22 @@ class HTMLCodePrinter : public IRVisitor { print_opening_tag("div", "Function"); // Generate the show hide icon/text buttons - print_toggle_anchor_opening_tag(id); - - // -- print icon - print_show_hide_icon(id); + print_show_hide_btn_begin(id); // -- print text (fn name and args) - // Note: We wrap the show/hide buttons in a navigation anchor - // that lets us sync text and visualization tabs. print_opening_tag("span", "matched"); - print_html_element("span", "keyword nav-anchor", "func ", "lowered-func-" + fn.name); + print_html_element("span", "keyword ", "func ", "lowered-func-" + fn.name); print_text(fn.name + "("); print_closing_tag("span"); print_fndecl_args(fn.args); print_html_element("span", "matched", ")"); - print_toggle_anchor_closing_tag(); - // Add a button to jump to this function in the viz print_visualization_button("lowered-func-viz-" + std::to_string(id)); // Open code block to hold function body print_html_element("span", "matched", "{"); + print_show_hide_btn_end(); // Open indented div to hold body code print_opening_tag("div", "indent FunctionBody", id); @@ -874,12 +928,17 @@ class HTMLCodePrinter : public IRVisitor { } // Prints the opening/closing tags for an anchor that toggles code block view - void print_toggle_anchor_opening_tag(int id) { - stream << ""; + void print_show_hide_btn_begin(int id, bool collapsed = false) { + stream << ""; + stream << ""; + void print_show_hide_btn_end() { + stream << ""; } // Prints newline to stream @@ -912,32 +971,24 @@ class HTMLCodePrinter : public IRVisitor { stream << x; } - // Prints the button to show or hide a code scope - void print_show_hide_icon(int id) { - stream << "
" - << " " - << "
" - << " " - << "
" - << "
"; - } - // Prints a button to sync text with visualization void print_visualization_button(std::string id) { - stream << ""; + if (enable_viztree_features) { + stream << ""; + } } // Prints a button to sync text with visualization void print_assembly_button(const void *op) { - int asm_lno = assembly_info.get_asm_lno((uint64_t)op); - if (asm_lno != -1) { - stream << ""; + if (enable_assembly_features) { + int asm_lno = assembly_info.get_asm_lno((uint64_t)op); + if (asm_lno != -1) { + stream << ""; + } } } @@ -970,21 +1021,19 @@ class HTMLCodePrinter : public IRVisitor { if (parts.size() == 3) { in_func_signature = true; current_id = gen_unique_id(); - print_toggle_anchor_opening_tag(current_id); - print_show_hide_icon(current_id); + print_show_hide_btn_begin(current_id); std::string kernel_name = parts[2].substr(0, parts[2].length() - 1); line = ".visible .entry "; line += variable(kernel_name) + " ("; current_kernel = kernel_name; } } else if (starts_with(line, ")") && in_func_signature) { - print_toggle_anchor_closing_tag(); in_func_signature = false; line = ")" + line.substr(1); } else if (starts_with(line, "{") && !in_braces) { in_braces = true; - print_toggle_anchor_closing_tag(); print_html_element("span", "matched", "{"); + print_show_hide_btn_end(); internal_assert(current_id != -1); print_opening_tag("div", "indent", current_id); current_id = -1; @@ -1150,7 +1199,7 @@ class HTMLCodePrinter : public IRVisitor { } void print_function_call(std::string fn_name, const std::vector &args, int id) { - print_opening_tag("span", "nav-anchor", "fn-call-" + std::to_string(id)); + print_opening_tag("span", "", "fn-call-" + std::to_string(id)); print_function_call(fn_name, args); print_closing_tag("span"); } @@ -1194,15 +1243,12 @@ class HTMLCodePrinter : public IRVisitor { print_opening_tag("div", "ForkTask"); // Generate the show hide icon/text buttons - print_toggle_anchor_opening_tag(id); - - // -- print icon - print_show_hide_icon(id); + print_show_hide_btn_begin(id); // -- print text print_html_element("span", "keyword matched", "task"); - print_toggle_anchor_closing_tag(); + print_show_hide_btn_end(); // Open code block to hold task body print_html_element("span", "matched", " {"); @@ -1272,11 +1318,11 @@ class HTMLCodePrinter : public IRVisitor { block_costc = num_cost_buckets - 1; } - stream << "
"; - stream << "" + stream << "" << prefix << line_cost << ""; @@ -1418,7 +1464,7 @@ class HTMLCodePrinter : public IRVisitor { void visit(const Load *op) override { int id = gen_node_id(op); - print_opening_tag("span", "Load nav-anchor", "load-" + std::to_string(id)); + print_opening_tag("span", "Load", "load-" + std::to_string(id)); print_opening_tag("span", "matched"); print_variable(op->name); print_text("["); @@ -1518,26 +1564,22 @@ class HTMLCodePrinter : public IRVisitor { print_cost_buttons(op, id); // Generate the show hide icon/text buttons - print_toggle_anchor_opening_tag(id); - - // -- print icon - print_show_hide_icon(id); + print_show_hide_btn_begin(id); // -- print text print_opening_tag("span", "matched"); - print_html_element("span", "keyword nav-anchor", op->is_producer ? "produce " : "consume ", + print_html_element("span", "keyword", op->is_producer ? "produce " : "consume ", "prodcons-" + std::to_string(id)); print_variable(op->name); print_closing_tag("span"); - print_toggle_anchor_closing_tag(); - // Add a button to jump to this producer/consumer in the viz print_visualization_button("prodcons-viz-" + std::to_string(id)); print_assembly_button(op); // Open code block to hold function body print_html_element("span", "matched", "{"); + print_show_hide_btn_end(); // Open indented div to hold body code print_opening_tag("div", "indent ProducerConsumerBody", id); @@ -1560,6 +1602,28 @@ class HTMLCodePrinter : public IRVisitor { scope.pop(op->name); } + std::string ForType_to_string(ForType type) { + switch (type) { + case ForType::Serial: + return "serial"; + case ForType::Parallel: + return "parallel"; + case ForType::Unrolled: + return "unrolled"; + case ForType::Vectorized: + return "vectorized"; + case ForType::Extern: + return "extern"; + case ForType::GPUBlock: + return "gpu_block"; + case ForType::GPUThread: + return "gpu_thread"; + case ForType::GPULane: + return "gpu_lane"; + } + return "for"; + } + void visit(const For *op) override { // Give this loop a unique id int id = gen_node_id(op); @@ -1568,20 +1632,17 @@ class HTMLCodePrinter : public IRVisitor { scope.push(op->name, id); // Start a dive to hold code for this allocate - print_opening_tag("div", "For"); + print_opening_tag("div", "For for-type-" + ForType_to_string(op->for_type)); // Print cost buttons print_cost_buttons(op, id); // Generate the show hide icon/text buttons - print_toggle_anchor_opening_tag(id); - - // -- print icon - print_show_hide_icon(id); + print_show_hide_btn_begin(id); // -- print text print_opening_tag("span", "matched"); - print_opening_tag("span", "keyword nav-anchor", "loop-" + std::to_string(id)); + print_opening_tag("span", "keyword", "loop-" + std::to_string(id)); stream << op->for_type << op->device_api; print_closing_tag("span"); print_text(" ("); @@ -1593,14 +1654,13 @@ class HTMLCodePrinter : public IRVisitor { print(op->extent); print_html_element("span", "matched", ")"); - print_toggle_anchor_closing_tag(); - // Add a button to jump to this loop in the viz print_visualization_button("loop-viz-" + std::to_string(id)); print_assembly_button(op); // Open code block to hold function body - print_html_element("span", "matched", "{"); + print_html_element("span", "matched", " {"); + print_show_hide_btn_end(); // Open indented div to hold body code print_opening_tag("div", "indent ForBody", id); @@ -1631,10 +1691,7 @@ class HTMLCodePrinter : public IRVisitor { print_opening_tag("div", "Acquire"); // Generate the show hide icon/text buttons - print_toggle_anchor_opening_tag(id); - - // -- print icon - print_show_hide_icon(id); + print_show_hide_btn_begin(id); // -- print text print_opening_tag("span", "matched"); @@ -1646,13 +1703,12 @@ class HTMLCodePrinter : public IRVisitor { print(op->count); print_html_element("span", "matched", ")"); - print_toggle_anchor_closing_tag(); - // Add a button to jump to this acquire in the viz print_visualization_button("acquire-viz-" + std::to_string(id)); // Open code block to hold function body print_html_element("span", "matched", "{"); + print_show_hide_btn_end(); // Open indented div to hold body code print_opening_tag("div", "indent AcquireBody", id); @@ -1683,7 +1739,7 @@ class HTMLCodePrinter : public IRVisitor { // Print store target print_opening_tag("span", "matched"); - print_opening_tag("span", "nav-anchor", "store-" + std::to_string(id)); + print_opening_tag("span", "", "store-" + std::to_string(id)); print_variable(op->name); print_text("["); print_closing_tag("span"); @@ -1741,7 +1797,7 @@ class HTMLCodePrinter : public IRVisitor { // Print allocation name, type and extents print_opening_tag("span", "matched"); - print_html_element("span", "keyword nav-anchor", "allocate ", "allocate-" + std::to_string(id)); + print_html_element("span", "keyword", "allocate ", "allocate-" + std::to_string(id)); print_variable(op->name); print_text("["); print_closing_tag("span"); @@ -1821,10 +1877,7 @@ class HTMLCodePrinter : public IRVisitor { print_opening_tag("div", "Realize"); // Generate the show hide icon/text buttons - print_toggle_anchor_opening_tag(id); - - // -- print icon - print_show_hide_icon(id); + print_show_hide_btn_begin(id); // -- print text print_opening_tag("span", "matched"); @@ -1849,13 +1902,12 @@ class HTMLCodePrinter : public IRVisitor { print(op->condition); } - print_toggle_anchor_closing_tag(); - // Add a button to jump to this realize in the viz print_visualization_button("realize-viz-" + std::to_string(id)); // Open code block to hold function body print_html_element("span", "matched", " {"); + print_show_hide_btn_end(); // Open indented div to hold body code print_opening_tag("div", "indent RealizeBody", id); @@ -1892,18 +1944,14 @@ class HTMLCodePrinter : public IRVisitor { print_opening_tag("div", "Fork"); // Generate the show hide icon/text buttons - print_toggle_anchor_opening_tag(id); - - // -- print icon - print_show_hide_icon(id); + print_show_hide_btn_begin(id); // -- print text print_html_element("span", "keyword matched", "fork"); - print_toggle_anchor_closing_tag(); - // Open code block to hold fork body print_html_element("span", "matched", " {"); + print_show_hide_btn_end(); // Open indented div to hold body code print_opening_tag("div", "indent ForkBody", id); @@ -1927,29 +1975,25 @@ class HTMLCodePrinter : public IRVisitor { // Give this acquire a unique id int then_block_id = gen_unique_id(); int then_node_id = gen_node_id(op->then_case.get()); + int last_then_block_id = -1; - // Start a dive to hold code for this conditional + // Start a div to hold code for this conditional print_opening_tag("div", "IfThenElse"); // Print cost buttons print_cost_buttons(op, then_block_id); // Generate the show hide icon/text buttons - print_toggle_anchor_opening_tag(then_block_id); - - // -- print icon - print_show_hide_icon(then_block_id); + print_show_hide_btn_begin(then_block_id); - // -- print text + // Print the actual "if (...) {" print_opening_tag("span", "matched"); - print_html_element("span", "keyword nav-anchor IfSpan", "if", "cond-" + std::to_string(then_node_id)); + print_html_element("span", "keyword IfSpan", "if", "cond-" + std::to_string(then_node_id)); print_text(" ("); print_closing_tag("span"); print(op->condition); print_html_element("span", "matched", ")"); - print_toggle_anchor_closing_tag(); - // Add a button to jump to this conditional in the viz print_visualization_button("cond-viz-" + std::to_string(then_node_id)); @@ -1960,22 +2004,21 @@ class HTMLCodePrinter : public IRVisitor { // Open code block to hold `then` case print_html_element("span", "matched", " {"); + print_show_hide_btn_end(); // Open indented div to hold code for the `then` case print_opening_tag("div", "indent ThenBody", then_block_id); - - // Print then case body print(op->then_case); - - // Close indented div holding `then` case print_closing_tag("div"); print_ln(); - - // Close code block holding `then` case - print_html_element("span", "matched ClosingBrace cb-" + std::to_string(then_block_id), "}"); + last_then_block_id = then_block_id; // If there is no `else` case, we are done! if (!op->else_case.defined()) { + + // Close code block holding `then` case + print_html_element("span", "matched ClosingBrace cb-" + std::to_string(then_block_id), "}"); + break; } @@ -1991,27 +2034,26 @@ class HTMLCodePrinter : public IRVisitor { print_cost_buttons(op, then_block_id); // Generate the show hide icon/text buttons - print_toggle_anchor_opening_tag(then_block_id); + print_show_hide_btn_begin(then_block_id); - // -- print icon - print_show_hide_icon(then_block_id); + // Close code block with a "}" from the previous block, *after* we have printed the new collapser button. + internal_assert(last_then_block_id != -1); + print_html_element("span", "matched ClosingBrace cb-" + std::to_string(last_then_block_id), "}"); - // -- print text + // Print the actual "} else if (...) {" condition statement print_opening_tag("span", "matched"); - print_html_element("span", "keyword nav-anchor IfSpan", "else if", "cond-" + std::to_string(then_node_id)); + print_html_element("span", "keyword IfSpan", " else if", "cond-" + std::to_string(then_node_id)); print_text(" ("); print_closing_tag("span"); print(nested_if->condition); print_html_element("span", "matched", ")"); - print_toggle_anchor_closing_tag(); - // Add a button to jump to this conditional branch in the viz print_visualization_button("cond-viz-" + std::to_string(then_node_id)); // Update op to the nested if for next loop iteration op = nested_if; - + last_then_block_id = then_block_id; } else { // Otherwise, print it and we are done! int else_block_id = gen_unique_id(); @@ -2021,23 +2063,23 @@ class HTMLCodePrinter : public IRVisitor { print_cost_buttons(op, else_block_id); // Generate the show hide icon/text buttons - print_toggle_anchor_opening_tag(else_block_id); + print_show_hide_btn_begin(else_block_id); - // -- print icon - print_show_hide_icon(else_block_id); + // Close code block with a "}" from the previous block, *after* we have printed the new collapser button. + internal_assert(last_then_block_id != -1); + print_html_element("span", "matched ClosingBrace cb-" + std::to_string(last_then_block_id), "}"); // -- print text print_opening_tag("span", "matched"); - print_html_element("span", "keyword nav-anchor IfSpan", "else", "cond-" + std::to_string(else_node_id)); + print_html_element("span", "keyword IfSpan", " else", "cond-" + std::to_string(else_node_id)); print_closing_tag("span"); - print_toggle_anchor_closing_tag(); - // Add a button to jump to this conditional branch in the viz print_visualization_button("cond-viz-" + std::to_string(else_node_id)); // Open code block to hold `else` case print_html_element("span", "matched", " {"); + print_show_hide_btn_end(); // Open indented div to hold code for the `then` case print_opening_tag("div", "indent ElseBody", else_block_id); @@ -2062,7 +2104,7 @@ class HTMLCodePrinter : public IRVisitor { } void visit(const Evaluate *op) override { - print_opening_tag("div", "Block"); + print_opening_tag("div", "Block Evaluate"); // Print cost buttons print_cost_buttons(op); print(op->value); @@ -2149,10 +2191,7 @@ class HTMLCodePrinter : public IRVisitor { print_opening_tag("div", "Atomic"); // Generate the show hide icon/text buttons - print_toggle_anchor_opening_tag(id); - - // -- print icon - print_show_hide_icon(id); + print_show_hide_btn_begin(id); // -- print text print_html_element("span", "matched keyword", "atomic"); @@ -2162,10 +2201,9 @@ class HTMLCodePrinter : public IRVisitor { print_html_element("span", "matched", ")"); } - print_toggle_anchor_closing_tag(); - // Open code block to hold atomic body print_html_element("span", "matched", " {"); + print_show_hide_btn_end(); // Open indented div to hold atomic code print_opening_tag("div", "indent AtomicBody", id); @@ -2425,8 +2463,9 @@ class HTMLVisualizationPrinter : public IRVisitor { return "Else"; } + // TODO: this code copies the node_ids over every time... std::ostringstream ss; - HTMLCodePrinter printer(ss, node_ids); + HTMLCodePrinter printer(ss, node_ids, true, true); e.accept(&printer); std::string html_e = ss.str(); @@ -2789,8 +2828,13 @@ class IRVisualizer { // Construct the visualizer and point it to the output file explicit IRVisualizer(const std::string &html_output_filename, const Module &m, - const std::string &assembly_input_filename) - : html_code_printer(stream, node_ids), html_viz_printer(stream, node_ids) { + const std::string &assembly_input_filename, + bool use_conceptual_stmt_ir, + bool include_viztree) + : use_conceptual_stmt_ir(use_conceptual_stmt_ir), + html_code_printer(stream, node_ids, include_viztree, true), + include_viztree(include_viztree), + html_viz_printer(stream, node_ids) { // Open output file stream.open(html_output_filename.c_str()); @@ -2825,9 +2869,16 @@ class IRVisualizer { // Run the cost model over this module to pre-compute all // node costs - cost_model.compute_all_costs(m); + if (use_conceptual_stmt_ir) { + cost_model.compute_conceptual_costs(m); + } else { + cost_model.compute_all_costs(m); + } + cost_model.finalize_cost_computation(); html_code_printer.init_cost_info(cost_model); - html_viz_printer.init_cost_info(cost_model); + if (include_viztree) { + html_viz_printer.init_cost_info(cost_model); + } // Generate html page stream << "\n"; @@ -2851,31 +2902,41 @@ class IRVisualizer { std::map node_ids; // Used to translate IR to code in HTML + bool use_conceptual_stmt_ir; HTMLCodePrinter html_code_printer; // Used to translate IR to visualization in HTML + bool include_viztree; HTMLVisualizationPrinter html_viz_printer; /* Methods for generating the section of the html file */ void generate_head(const Module &m) { stream << "\n"; - stream << "Visualizing Module: " << m.name() << "\n"; - generate_dependency_links(); - generate_stylesheet(); + stream << "Halide Module: " << m.name() << "\n"; + stream << halide_html_template_StmtToHTML_dependencies_html; + if constexpr (INLINE_TEMPLATES) { + stream << "\n"; + if (include_viztree) { + stream << halide_html_template_StmtToViz_dependencies_html; + stream << "\n"; + } + } else { + std::filesystem::path dir = std::filesystem::path(__FILE__).parent_path() / "irvisualizer"; + debug(1) << "Will link CSS in directory: " << dir << "\n"; + internal_assert(std::filesystem::exists(dir)); + stream << "\n"; + if (include_viztree) { + stream << halide_html_template_StmtToViz_dependencies_html; + stream << "\n"; + } + } stream << "\n"; } - // Loads the html code responsible for linking with various js/css libraries from - // `ir_visualizer/dependencies.html` - void generate_dependency_links() { - stream << halide_html_template_StmtToViz_dependencies; - } - - // Loads the stylesheet code from `ir_visualizer/stylesheet.html` - void generate_stylesheet() { - stream << halide_html_template_StmtToViz_stylesheet; - } - /* Methods for generating the section of the html file */ void generate_body(const Module &m) { stream << "\n"; @@ -2883,84 +2944,88 @@ class IRVisualizer { generate_visualization_tabs(m); stream << "
\n"; stream << ""; - generate_javascript(); + if constexpr (INLINE_TEMPLATES) { + stream << ""; + if (include_viztree) { + stream << ""; + } + } else { + std::filesystem::path dir = std::filesystem::path(__FILE__).parent_path() / "irvisualizer"; + debug(1) << "Will link Javascript in directory: " << dir << "\n"; + internal_assert(std::filesystem::exists(dir)); + stream << "\n"; + if (include_viztree) { + stream << "\n"; + } + } } // Generate the three visualization tabs void generate_visualization_tabs(const Module &m) { + int tab_count = 0; stream << "
\n"; generate_ir_tab(m); - generate_resize_bar_1(); - generate_visualization_tab(m); - generate_resize_bar_2(); + generate_resize_bar(tab_count++); + if (include_viztree) { + generate_visualization_tab(m); + generate_resize_bar(tab_count++); + } generate_assembly_tab(m); stream << "
\n"; } // Generate tab 1/3: Lowered IR code with syntax highlighting in HTML void generate_ir_tab(const Module &m) { - stream << "
\n"; - html_code_printer.print(m, asm_info); - stream << "
\n"; + if (use_conceptual_stmt_ir) { + stream << "
\n"; + html_code_printer.print_conceptual_stmt(m, asm_info); + stream << "
\n"; + } else { + stream << "
\n"; + html_code_printer.print(m, asm_info); + stream << "
\n"; + } } // Generate tab 2/3: Lowered IR code with syntax highlighting in HTML void generate_visualization_tab(const Module &m) { - stream << "
\n"; + stream << "
\n"; html_viz_printer.print(m, asm_info); stream << "
\n"; } // Generate tab 3/3: Generated assembly code void generate_assembly_tab(const Module &m) { - stream << "
\n"; + stream << "
\n"; stream << "
\n"; stream << "
\n";
         stream << asm_stream.str();
+        stream << "\n";
         stream << "
\n"; stream << "
\n"; stream << "
\n"; } // Generate a resizing bar to control the width of code and visualization tabs - void generate_resize_bar_1() { - stream << R"(
-
-
- -
-
- -
-
-
)"; - } - - // Generate a resizing bar to control the width of visualization and assembly tabs - void generate_resize_bar_2() { - stream << R"(
-
-
- -
-
- -
-
-
)"; - } - - // Loads and initializes the javascript template from `ir_visualizer / javascript_template.html` - void generate_javascript() { - stream << halide_html_template_StmtToViz_javascript; + void generate_resize_bar(int num) { + stream << "
\n"; + stream << "
\n"; + stream << "
\n"; + stream << " \n"; + stream << "
\n"; + stream << "
\n"; + stream << " \n"; + stream << "
\n"; + stream << "
\n"; + stream << "
\n"; } /* Misc helper methods */ @@ -2984,13 +3049,23 @@ class IRVisualizer { }; // The external interface to this module -void print_to_viz(const std::string &html_output_filename, - const Module &m, - const std::string &assembly_input_filename) { - IRVisualizer visualizer(html_output_filename, m, assembly_input_filename); +void print_to_stmt_html(const std::string &html_output_filename, + const Module &m, + const std::string &assembly_input_filename, + bool include_viz) { + IRVisualizer visualizer(html_output_filename, m, assembly_input_filename, false, include_viz); visualizer.generate_html(m); debug(1) << "Done generating HTML IR Visualization - printed to: " << html_output_filename << "\n"; } +void print_to_conceptual_stmt_html(const std::string &html_output_filename, + const Module &m, + const std::string &assembly_input_filename, + bool include_viz) { + IRVisualizer visualizer(html_output_filename, m, assembly_input_filename, true, include_viz); + visualizer.generate_html(m); + debug(1) << "Done generating HTML Conceptual IR Visualization - printed to: " << html_output_filename << "\n"; +} + } // namespace Internal } // namespace Halide diff --git a/src/StmtToViz.h b/src/StmtToViz.h index 46e3fad0d541..3e2cbd8833b9 100644 --- a/src/StmtToViz.h +++ b/src/StmtToViz.h @@ -20,9 +20,20 @@ struct Stmt; * to assembly output. If empty, the code will attempt to find such a * file based on output_filename (replacing ".stmt.html" with ".s"), * and will assert-fail if no such file is found. */ -void print_to_viz(const std::string &html_output_filename, - const Module &m, - const std::string &assembly_input_filename = ""); +void print_to_stmt_html(const std::string &html_output_filename, + const Module &m, + const std::string &assembly_input_filename = "", + bool include_viz = false); + +/** Dump an HTML-formatted visualization of a Module's conceptual Stmt code to filename. + * If assembly_input_filename is not empty, it is expected to be the path + * to assembly output. If empty, the code will attempt to find such a + * file based on output_filename (replacing ".stmt.html" with ".s"), + * and will assert-fail if no such file is found. */ +void print_to_conceptual_stmt_html(const std::string &html_output_filename, + const Module &m, + const std::string &assembly_input_filename = "", + bool include_viz = false); } // namespace Internal } // namespace Halide diff --git a/src/irvisualizer/StmtToViz_dependencies.template.html b/src/irvisualizer/StmtToViz_dependencies.template.html deleted file mode 100644 index e8122c67ae91..000000000000 --- a/src/irvisualizer/StmtToViz_dependencies.template.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/src/irvisualizer/StmtToViz_javascript.template.html b/src/irvisualizer/StmtToViz_javascript.template.html deleted file mode 100644 index c8d1f4a99275..000000000000 --- a/src/irvisualizer/StmtToViz_javascript.template.html +++ /dev/null @@ -1,415 +0,0 @@ - - diff --git a/src/irvisualizer/html_template_StmtToHTML.css b/src/irvisualizer/html_template_StmtToHTML.css new file mode 100644 index 000000000000..e1dd047109da --- /dev/null +++ b/src/irvisualizer/html_template_StmtToHTML.css @@ -0,0 +1,570 @@ +/* General CSS Rules*/ +body { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 12px; + background: #f8f8f8; + padding: 0; + margin: 0; +} + +div#page-container { + height: 100vh; + display: flex; + flex-direction: column; +} + +a, +a:hover, +a:visited, +a:active { + color: inherit; + text-decoration: none; +} + +b { + font-weight: normal; +} + +table { + font-size: 12px; +} + +/* Visualization tabs */ +div#visualization-tabs { + display: flex; + flex-grow: 1; + width: 100%; + height: 100%; +} + +div.tab { + overflow: scroll; + position: relative; + flex-grow: 1; +} + +div#ir-code-tab { + counter-reset: line; + padding-left: 50px; + padding-top: 20px; +} + +div#assembly-tab { + min-width: 350px; + max-width: 30vw; +} + +button#highlight-button { + margin: 0.4em; + padding: 0.5em; + border-radius: 4px; +} + + +/* Resize bars */ +div.resize-bar { + background: rgb(201, 231, 190); + cursor: col-resize; + border-left: 1px solid rgb(0, 0, 0); + border-right: 1px solid rgb(0, 0, 0); + + > div.collapse-btns { + position: relative; + top: 50%; + margin: 0px; + + & button:hover { + background-color: rgba(255, 255, 255, 0.5); + } + + & i.bi-arrow-bar-left:before { content: "<"; } + & i.bi-arrow-bar-right:before { content: ">"; } + } +} + + +button.resize-btn { + margin: 10px 3px; + font-size: 18px; +} + +/* IR Code Section CSS */ +.ModuleBody { + padding-left: 42px !important; +} +div.conceptual .ModuleBody { + /* With conceptual IR, the indent is not big enough, as we are missing one extra level from the functions. */ + padding-left: 55px !important; +} + +div.Function, div.Buffer { + padding-top: 0.6em; + padding-bottom: 0.6em; + padding-left: 1.6em; + padding-right: 1.6em; + border-radius: 6px; + margin-right: 1.0em; +} +div.Function + div.Function { + margin-top: 1.5em; /* Leave space between two functions. */ +} + +/* Give functions a slightly different background color to visually help navigate quickly. */ +div.Function:nth-child(3n + 1) { background-color: rgba(200, 0, 0, 0.025); } +div.Function:nth-child(3n + 2) { background-color: rgba(0, 200, 0, 0.025); } +div.Function:nth-child(3n + 3) { background-color: rgba(0, 0, 200, 0.025); } + +/* Give Parallel fors a different color */ +div.For.for-type-parallel { background-color: rgba(200, 200, 0, 0.03); margin: 0.5em; } +div.For.for-type-gpu_block { background-color: rgba(200, 200, 0, 0.03); margin: 0.5em; } + +b.Highlight { + font-weight: bold; + background-color: #DDD; +} + +span.Highlight { + font-weight: bold; + background-color: #FF0; +} + +span.OpF32 { + color: hsl(106deg 100% 40%); + font-weight: bold; +} + +span.OpF64 { + color: hsl(106deg 100% 30%); + font-weight: bold; +} + +span.OpB8 { + color: hsl(208deg 100% 80%); + font-weight: bold; +} + +span.OpB16 { + color: hsl(208deg 100% 70%); + font-weight: bold; +} + +span.OpB32 { + color: hsl(208deg 100% 60%); + font-weight: bold; +} + +span.OpB64 { + color: hsl(208deg 100% 50%); + font-weight: bold; +} + +span.OpI8 { + color: hsl(46deg 100% 45%); + font-weight: bold; +} + +span.OpI16 { + color: hsl(46deg 100% 40%); + font-weight: bold; +} + +span.OpI32 { + color: hsl(46deg 100% 34%); + font-weight: bold; +} + +span.OpI64 { + color: hsl(46deg 100% 27%); + font-weight: bold; +} + +span.OpVec2 { + background-color: hsl(100deg 100% 90%); + font-weight: bold; +} + +span.OpVec4 { + background-color: hsl(100deg 100% 80%); + font-weight: bold; +} + +span.Memory { + color: #d22; + font-weight: bold; +} + +span.Pred { + background-color: #ffe8bd; + font-weight: bold; +} + +span.Label { + background-color: #bde4ff; + font-weight: bold; +} + +/* Collapse button and indent div logic */ +input.show-hide-btn { + appearance: none; + margin-left: -17px; + margin-top: 0px; + margin-bottom: 0px; + padding: 0; + height: 14px; + vertical-align: top; + + &:before { + content: "-"; + font-size: 15px; + width: 14px; + height: 14px; + box-sizing: border-box; + text-anchor: middle; + line-height: 9px; + display: inline-block; + border: 1px solid black; + border-radius: 4px; + text-align: center; + padding: 0; + margin: 0; + overflow: hidden; + } + + &:checked:before { + content: "+"; + font-size: 10px; + line-height: 11px; + } +} + + +div.indent { + box-sizing: border-box; + border-left: 2px solid transparent; + padding-left: 25px; + margin-left: -11px; +} + +input.show-hide-btn:hover { + color: #c30000; +} + +/* The structure always has to be "; } } @@ -1032,7 +1053,7 @@ class HTMLCodePrinter : public IRVisitor { line = ")" + line.substr(1); } else if (starts_with(line, "{") && !in_braces) { in_braces = true; - print_html_element("span", "matched", "{"); + print_opening_brace(); print_show_hide_btn_end(); internal_assert(current_id != -1); print_opening_tag("div", "indent", current_id); @@ -1091,8 +1112,8 @@ class HTMLCodePrinter : public IRVisitor { line = "@" + variable(pred) + "" + line.substr(idx); } - // Labels - if (line.front() == 'L' && !indent && (idx = line.find(':')) != std::string::npos) { + // Labels (depending on the LLVM version we get L with or without a dollar) + if (starts_with(line, "$L_") && !indent && (idx = line.find(':')) != std::string::npos) { std::string label = line.substr(0, idx); line = "" + variable(label) + ":" + line.substr(idx + 1); } @@ -1141,7 +1162,7 @@ class HTMLCodePrinter : public IRVisitor { } else if (op.front() == '{') { std::string reg = op.substr(1); operands_str += '{' + variable(reg); - } else if (op.front() == 'L') { + } else if (starts_with(op, "$L_")) { // Labels operands_str += "" + variable(op) + ""; } else { @@ -1251,7 +1272,7 @@ class HTMLCodePrinter : public IRVisitor { print_show_hide_btn_end(); // Open code block to hold task body - print_html_element("span", "matched", " {"); + print_opening_brace(); // Open indented div to hold body code print_opening_tag("div", "indent ForkTask", id); @@ -1288,6 +1309,9 @@ class HTMLCodePrinter : public IRVisitor { int max_line_cost = cost_model.get_max_compute_cost(false); int line_cost = cost_model.get_compute_cost(op, false); int block_cost = cost_model.get_compute_cost(op, true); + if (dynamic_cast(op)) { + block_cost = line_cost; + } std::string _id = "cc-" + std::to_string(id); print_cost_btn(line_cost, block_cost, max_line_cost, _id, "Op Count: "); } @@ -1297,6 +1321,9 @@ class HTMLCodePrinter : public IRVisitor { int max_line_cost = cost_model.get_max_data_movement_cost(false); int line_cost = cost_model.get_data_movement_cost(op, false); int block_cost = cost_model.get_data_movement_cost(op, true); + if (dynamic_cast(op)) { + block_cost = line_cost; + } std::string _id = "dc-" + std::to_string(id); print_cost_btn(line_cost, block_cost, max_line_cost, _id, "Bits Moved: "); } @@ -1318,13 +1345,33 @@ class HTMLCodePrinter : public IRVisitor { block_costc = num_cost_buckets - 1; } - stream << "
"; stream << "" - << prefix << line_cost - << ""; + << prefix << line_cost; + if (line_cost != block_cost) { + stream << "
Total " << prefix << block_cost; + } + stream << ""; stream << "
"; } @@ -1578,7 +1625,7 @@ class HTMLCodePrinter : public IRVisitor { print_assembly_button(op); // Open code block to hold function body - print_html_element("span", "matched", "{"); + print_opening_brace(); print_show_hide_btn_end(); // Open indented div to hold body code @@ -1659,7 +1706,7 @@ class HTMLCodePrinter : public IRVisitor { print_assembly_button(op); // Open code block to hold function body - print_html_element("span", "matched", " {"); + print_opening_brace(); print_show_hide_btn_end(); // Open indented div to hold body code @@ -1707,7 +1754,7 @@ class HTMLCodePrinter : public IRVisitor { print_visualization_button("acquire-viz-" + std::to_string(id)); // Open code block to hold function body - print_html_element("span", "matched", "{"); + print_opening_brace(); print_show_hide_btn_end(); // Open indented div to hold body code @@ -1906,7 +1953,7 @@ class HTMLCodePrinter : public IRVisitor { print_visualization_button("realize-viz-" + std::to_string(id)); // Open code block to hold function body - print_html_element("span", "matched", " {"); + print_opening_brace(); print_show_hide_btn_end(); // Open indented div to hold body code @@ -1950,7 +1997,7 @@ class HTMLCodePrinter : public IRVisitor { print_html_element("span", "keyword matched", "fork"); // Open code block to hold fork body - print_html_element("span", "matched", " {"); + print_opening_brace(); print_show_hide_btn_end(); // Open indented div to hold body code @@ -2003,7 +2050,7 @@ class HTMLCodePrinter : public IRVisitor { /* Handle the `then` case */ // Open code block to hold `then` case - print_html_element("span", "matched", " {"); + print_opening_brace(); print_show_hide_btn_end(); // Open indented div to hold code for the `then` case @@ -2078,7 +2125,7 @@ class HTMLCodePrinter : public IRVisitor { print_visualization_button("cond-viz-" + std::to_string(else_node_id)); // Open code block to hold `else` case - print_html_element("span", "matched", " {"); + print_opening_brace(); print_show_hide_btn_end(); // Open indented div to hold code for the `then` case @@ -2202,7 +2249,7 @@ class HTMLCodePrinter : public IRVisitor { } // Open code block to hold atomic body - print_html_element("span", "matched", " {"); + print_opening_brace(); print_show_hide_btn_end(); // Open indented div to hold atomic code @@ -2342,14 +2389,14 @@ class HTMLVisualizationPrinter : public IRVisitor { // Prints a button to sync visualization with code void print_code_button(const std::string &id) { stream << ""; } // Prints a button to sync visualization with assembly void print_asm_button(const std::string &id) { stream << ""; } @@ -2364,10 +2411,10 @@ class HTMLVisualizationPrinter : public IRVisitor { // Prints a button to collapse or expand a visualization box void print_collapse_expand_btn(int id) { stream << "" << ""; } @@ -3015,13 +3062,11 @@ class IRVisualizer { stream << "
\n"; stream << "
\n"; stream << "
\n"; - stream << " \n"; stream << "
\n"; stream << "
\n"; - stream << " \n"; stream << "
\n"; stream << "
\n"; diff --git a/src/irvisualizer/html_template_StmtToHTML.css b/src/irvisualizer/html_template_StmtToHTML.css index e1dd047109da..b4de94115f10 100644 --- a/src/irvisualizer/html_template_StmtToHTML.css +++ b/src/irvisualizer/html_template_StmtToHTML.css @@ -42,6 +42,9 @@ div.tab { position: relative; flex-grow: 1; } +div.tab.collapsed-tab { + display: none; +} div#ir-code-tab { counter-reset: line; @@ -67,19 +70,41 @@ div.resize-bar { cursor: col-resize; border-left: 1px solid rgb(0, 0, 0); border-right: 1px solid rgb(0, 0, 0); +} + +div.resize-bar > div.collapse-btns { + position: relative; + top: 50%; + margin: 0px; +} - > div.collapse-btns { - position: relative; - top: 50%; - margin: 0px; +div.resize-bar > div.collapse-btns button { + font-size: 11px; + height: 3em; + width: 1.5em; + border-radius: 0; + margin: 1em 0; + border: none; + padding: 0; + background-color: rgba(0, 0, 0, 0.1); +} - & button:hover { - background-color: rgba(255, 255, 255, 0.5); - } +div.resize-bar > div.collapse-btns button:hover { background-color: rgba(255, 255, 255, 0.5); } +div.resize-bar > div.collapse-btns button.collapse-left:before { content: "\21E4"; } +div.resize-bar > div.collapse-btns button.collapse-right:before { content: "\21E5"; } - & i.bi-arrow-bar-left:before { content: "<"; } - & i.bi-arrow-bar-right:before { content: ">"; } - } +/* Revert collapser button that points to the left. */ +div.collapsed-tab + div.resize-bar button.collapse-left { + background-color: rgba(0, 0, 0, 0.2); +} +div.collapsed-tab + div.resize-bar button.collapase-left:before { + content: "\21A6"; +} +div.resize-bar:has(+ div.collapsed-tab) button.collapse-right { + background-color: rgba(0, 0, 0, 0.2); +} +div.resize-bar:has(+ div.collapsed-tab) button.collapse-right:before { + content: "\21A4"; } @@ -90,33 +115,62 @@ button.resize-btn { /* IR Code Section CSS */ .ModuleBody { - padding-left: 42px !important; -} -div.conceptual .ModuleBody { - /* With conceptual IR, the indent is not big enough, as we are missing one extra level from the functions. */ - padding-left: 55px !important; + padding-left: 70px !important; } div.Function, div.Buffer { - padding-top: 0.6em; - padding-bottom: 0.6em; - padding-left: 1.6em; - padding-right: 1.6em; - border-radius: 6px; - margin-right: 1.0em; + margin: 0.2em 0.0em; + padding: 0.1em; + margin-right: 0.8em; + margin-left: calc(-0.2em - 16px); + padding-left: calc(0.2em + 16px); + border-width: 3px; + border-style: solid; + border-radius: 8px; } div.Function + div.Function { margin-top: 1.5em; /* Leave space between two functions. */ } +div.Buffer { background-color: rgba(200, 100, 0, 0.025); border-color: rgba(200, 100, 0, 0.03); } /* Give functions a slightly different background color to visually help navigate quickly. */ -div.Function:nth-child(3n + 1) { background-color: rgba(200, 0, 0, 0.025); } -div.Function:nth-child(3n + 2) { background-color: rgba(0, 200, 0, 0.025); } -div.Function:nth-child(3n + 3) { background-color: rgba(0, 0, 200, 0.025); } +div.Function:nth-child(3n + 1) { background-color: rgba(200, 0, 0, 0.025); border-color: rgba(200, 0, 0, 0.03); } +div.Function:nth-child(3n + 2) { background-color: rgba(0, 200, 0, 0.025); border-color: rgba(0, 200, 0, 0.03); } +div.Function:nth-child(3n + 3) { background-color: rgba(0, 0, 200, 0.025); border-color: rgba(0, 0, 200, 0.03); } /* Give Parallel fors a different color */ -div.For.for-type-parallel { background-color: rgba(200, 200, 0, 0.03); margin: 0.5em; } -div.For.for-type-gpu_block { background-color: rgba(200, 200, 0, 0.03); margin: 0.5em; } +div.For { border-radius: 8px; } +div.For.for-type-parallel, +div.For.for-type-gpu_block { + background-color: rgba(240, 200, 0, 0.03); + border: 3px solid rgba(240, 200, 0, 0.10); + margin: 0.2em 0.0em; + padding: 0.1em; + margin-right: 0.8em; + margin-left: calc(-0.2em - 16px); + padding-left: calc(0.2em + 16px); +} +div.For.for-type-gpu_block div.For.for-type-gpu_block { + background-color: transparent; + border: none; + margin: 0; + padding: 0; +} +div.For.for-type-gpu_thread { + background-color: rgba(240, 100, 50, 0.03); + border: 3px solid rgba(240, 100, 50, 0.10); + margin: 0.2em 0.0em; + padding: 0.1em; + margin-right: 0.8em; + margin-left: calc(-0.2em - 16px); + padding-left: calc(0.2em + 16px); +} +div.For.for-type-gpu_thread div.For.for-type-gpu_thread { + background-color: transparent; + border: none; + margin: 0; + padding: 0; +} b.Highlight { font-weight: bold; @@ -210,31 +264,31 @@ input.show-hide-btn { margin-top: 0px; margin-bottom: 0px; padding: 0; - height: 14px; + height: 12px; vertical-align: top; +} - &:before { - content: "-"; - font-size: 15px; - width: 14px; - height: 14px; - box-sizing: border-box; - text-anchor: middle; - line-height: 9px; - display: inline-block; - border: 1px solid black; - border-radius: 4px; - text-align: center; - padding: 0; - margin: 0; - overflow: hidden; - } - - &:checked:before { - content: "+"; - font-size: 10px; - line-height: 11px; - } +input.show-hide-btn:before { + content: ">"; + font-size: 10px; + width: 12px; + height: 12px; + box-sizing: border-box; + text-anchor: middle; + text-align: center; + line-height: 9px; + display: inline-block; + border: 1px solid black; + border-radius: 4px; + padding: 0; + margin: 0; + overflow: hidden; + transition: transform 0.2s; + transform: rotate(90deg); +} + +input.show-hide-btn:checked:before { + transform: rotate(0deg); } @@ -249,12 +303,11 @@ input.show-hide-btn:hover { color: #c30000; } -/* The structure always has to be "; } } - } - - // CUDA kernels are embedded into modules as PTX assembly. This - // routine pretty - prints that assembly format. - void print_cuda_gpu_source_kernels(const std::string &str) { - print_opening_tag("code", "ptx"); - - int current_id = -1; - bool in_braces = false; - bool in_func_signature = false; - - std::string current_kernel; - std::istringstream ss(str); - - for (std::string line; std::getline(ss, line);) { - if (line.empty()) { - stream << "\n"; - continue; - } - line = replace_all(line, "&", "&"); - line = replace_all(line, "<", "<"); - line = replace_all(line, ">", ">"); - line = replace_all(line, "\"", """); - line = replace_all(line, "/", "/"); - line = replace_all(line, "'", "'"); - - if (starts_with(line, ".visible .entry")) { - std::vector parts = split_string(line, " "); - if (parts.size() == 3) { - in_func_signature = true; - current_id = gen_unique_id(); - print_show_hide_btn_begin(current_id); - std::string kernel_name = parts[2].substr(0, parts[2].length() - 1); - line = ".visible .entry "; - line += variable(kernel_name) + " ("; - current_kernel = kernel_name; - } - } else if (starts_with(line, ")") && in_func_signature) { - in_func_signature = false; - line = ")" + line.substr(1); - } else if (starts_with(line, "{") && !in_braces) { - in_braces = true; - print_opening_brace(); - print_show_hide_btn_end(); - internal_assert(current_id != -1); - print_opening_tag("div", "indent", current_id); - current_id = -1; - line = line.substr(1); - scope.push(current_kernel, gen_unique_id()); - } else if (starts_with(line, "}") && in_braces) { - print_closing_tag("div"); - line = "}" + line.substr(1); - in_braces = false; - scope.pop(current_kernel); - } - - bool indent = false; - - if (line[0] == '\t') { - // Replace first tab with four spaces. - line = line.substr(1); - indent = true; - } - - line = replace_all(line, ".f32", ".f32"); - line = replace_all(line, ".f64", ".f64"); - - line = replace_all(line, ".s8", ".s8"); - line = replace_all(line, ".s16", ".s16"); - line = replace_all(line, ".s32", ".s32"); - line = replace_all(line, ".s64", ".s64"); - - line = replace_all(line, ".u8", ".u8"); - line = replace_all(line, ".u16", ".u16"); - line = replace_all(line, ".u32", ".u32"); - line = replace_all(line, ".u64", ".u64"); - - line = replace_all(line, ".b8", ".b8"); - line = replace_all(line, ".b16", ".b16"); - line = replace_all(line, ".b32", ".b32"); - line = replace_all(line, ".b64", ".b64"); - - line = replace_all(line, ".v2", ".v2"); - line = replace_all(line, ".v4", ".v4"); - - line = replace_all(line, "ld.", "ld."); - line = replace_all(line, "st.", "st."); - - size_t idx; - if ((idx = line.find("//")) != std::string::npos) { - line.insert(idx, ""); - line += ""; - } - - // Predicated instructions - if (line.front() == '@' && indent) { - idx = line.find(' '); - std::string pred = line.substr(1, idx - 1); - line = "@" + variable(pred) + "" + line.substr(idx); - } - - // Labels (depending on the LLVM version we get L with or without a dollar) - if (starts_with(line, "$L_") && !indent && (idx = line.find(':')) != std::string::npos) { - std::string label = line.substr(0, idx); - line = "" + variable(label) + ":" + line.substr(idx + 1); - } - - // Highlight operands - if ((idx = line.find(" \t")) != std::string::npos && line.back() == ';') { - std::string operands_str = line.substr(idx + 2); - operands_str = operands_str.substr(0, operands_str.length() - 1); - std::vector operands = split_string(operands_str, ", "); - operands_str = ""; - for (size_t opidx = 0; opidx < operands.size(); ++opidx) { - std::string op = operands[opidx]; - internal_assert(!op.empty()); - if (opidx != 0) { - operands_str += ", "; - } - if (op.back() == '}') { - std::string reg = op.substr(0, op.size() - 1); - operands_str += variable(reg) + '}'; - } else if (op.front() == '%') { - operands_str += variable(op); - } else if (op.find_first_not_of("-0123456789") == std::string::npos) { - operands_str += ""; - operands_str += op; - operands_str += ""; - } else if (starts_with(op, "0f") && - op.find_first_not_of("0123456789ABCDEF", 2) == std::string::npos) { - operands_str += ""; - operands_str += op; - operands_str += ""; - } else if (op.front() == '[' && op.back() == ']') { - size_t idx = op.find('+'); - if (idx == std::string::npos) { - std::string reg = op.substr(1, op.size() - 2); - operands_str += '[' + variable(reg) + ']'; - } else { - std::string reg = op.substr(1, idx - 1); - std::string offset = op.substr(idx + 1); - offset = offset.substr(0, offset.size() - 1); - operands_str += '[' + variable(reg) + "+"; - operands_str += ""; - operands_str += offset; - operands_str += ""; - operands_str += ']'; - } - } else if (op.front() == '{') { - std::string reg = op.substr(1); - operands_str += '{' + variable(reg); - } else if (starts_with(op, "$L_")) { - // Labels - operands_str += "" + variable(op) + ""; - } else { - operands_str += op; - } - } - operands_str += ";"; - line = line.substr(0, idx + 2) + operands_str; - } - - if (indent) { - stream << " "; + { + int asm_lno = device_assembly_info.get_asm_lno((uint64_t)op); + if (asm_lno != -1) { + stream << ""; } - stream << line << "\n"; } - print_closing_tag("code"); } // Prints the args in a function declaration @@ -2290,8 +2339,9 @@ class HTMLVisualizationPrinter : public IRVisitor { cost_model = std::move(cm); } - void print(const Module &m, AssemblyInfo asm_info) { - assembly_info = std::move(asm_info); + void print(const Module &m, AssemblyInfo host_asm_info, AssemblyInfo device_asm_info) { + host_assembly_info = std::move(host_asm_info); + device_assembly_info = std::move(device_asm_info); for (const auto &fn : m.functions()) { print(fn); } @@ -2305,7 +2355,8 @@ class HTMLVisualizationPrinter : public IRVisitor { std::vector context_stack_tags; // Assembly line number info - AssemblyInfo assembly_info; + AssemblyInfo host_assembly_info; + AssemblyInfo device_assembly_info; // Holds cost information for visualized program IRCostModel cost_model; @@ -2641,7 +2692,7 @@ class HTMLVisualizationPrinter : public IRVisitor { // Print box header std::string aid = std::to_string(id); - int asm_lno = assembly_info.get_asm_lno((uint64_t)op); + int asm_lno = host_assembly_info.get_asm_lno((uint64_t)op); if (asm_lno == -1) { print_box_header(id, op, "loop-viz-" + aid, "loop-" + aid, "For: " + get_as_var(op->name)); } else { @@ -2726,7 +2777,7 @@ class HTMLVisualizationPrinter : public IRVisitor { // Print box header std::string aid = std::to_string(id); std::string prefix = op->is_producer ? "Produce: " : "Consume: "; - int asm_lno = assembly_info.get_asm_lno((uint64_t)op); + int asm_lno = host_assembly_info.get_asm_lno((uint64_t)op); if (asm_lno == -1) { print_box_header(id, op, "prodcons-viz-" + aid, "prodcons-" + aid, prefix + get_as_var(op->name)); } else { @@ -2912,7 +2963,21 @@ class IRVisualizer { // code is based on darya-ver's original implementation. We // use comments in the generated assembly to infer association // between Halide IR and assembly -- unclear how reliable this is. - asm_info.generate(asm_stream.str(), m); + host_asm_info.gather_nodes_from_functions(m); + host_asm_info.generate(asm_stream.str()); + + if (const Buffer<> *device_assembly_buf = m.get_device_code_buffer()) { + std::string device_assembly((char *)device_assembly_buf->data(), + ((char *)device_assembly_buf->data() + device_assembly_buf->size_in_bytes())); + debug(1) << "Generating device AssemblyInfo\n"; + // TODO(mcourteaux): This doesn't generate anything useful, as the + // LLVM comments are only added later in the LLVM CodeGen IRVisitor. + // This conceptual Stmt hasn't seen this seen this + device_asm_info.gather_nodes_from_conceptual_stmt(m); + device_asm_info.generate(device_assembly); + } else { + debug(1) << "No device code buffer found.\n"; + } // Run the cost model over this module to pre-compute all // node costs @@ -2961,26 +3026,26 @@ class IRVisualizer { stream << "\n"; stream << "Halide Module: " << m.name() << "\n"; stream << halide_html_template_StmtToHTML_dependencies_html; - if constexpr (INLINE_TEMPLATES) { +#if INLINE_TEMPLATES + stream << "\n"; + if (include_viztree) { + stream << halide_html_template_StmtToViz_dependencies_html; stream << "\n"; - if (include_viztree) { - stream << halide_html_template_StmtToViz_dependencies_html; - stream << "\n"; - } - } else { - std::filesystem::path dir = std::filesystem::path(__FILE__).parent_path() / "irvisualizer"; - debug(1) << "Will link CSS in directory: " << dir << "\n"; - internal_assert(std::filesystem::exists(dir)); - stream << "\n"; - if (include_viztree) { - stream << halide_html_template_StmtToViz_dependencies_html; - stream << "\n"; - } } +#else + std::filesystem::path dir = std::filesystem::path(__FILE__).parent_path() / "irvisualizer"; + debug(1) << "Will link CSS in directory: " << dir << "\n"; + internal_assert(std::filesystem::exists(dir)); + stream << "\n"; + if (include_viztree) { + stream << halide_html_template_StmtToViz_dependencies_html; + stream << "\n"; + } +#endif stream << "\n"; } @@ -2991,24 +3056,24 @@ class IRVisualizer { generate_visualization_tabs(m); stream << "
\n"; stream << ""; - if constexpr (INLINE_TEMPLATES) { +#if INLINE_TEMPLATES + stream << ""; + if (include_viztree) { stream << ""; - if (include_viztree) { - stream << ""; - } - } else { - std::filesystem::path dir = std::filesystem::path(__FILE__).parent_path() / "irvisualizer"; - debug(1) << "Will link Javascript in directory: " << dir << "\n"; - internal_assert(std::filesystem::exists(dir)); - stream << "\n"; - if (include_viztree) { - stream << "\n"; - } } +#else + std::filesystem::path dir = std::filesystem::path(__FILE__).parent_path() / "irvisualizer"; + debug(1) << "Will link Javascript in directory: " << dir << "\n"; + internal_assert(std::filesystem::exists(dir)); + stream << "\n"; + if (include_viztree) { + stream << "\n"; + } +#endif } // Generate the three visualization tabs @@ -3016,38 +3081,44 @@ class IRVisualizer { int tab_count = 0; stream << "
\n"; generate_ir_tab(m); - generate_resize_bar(tab_count++); if (include_viztree) { + generate_resize_bar(tab_count++); generate_visualization_tab(m); + } + generate_resize_bar(tab_count++); + generate_host_assembly_tab(m); + const Buffer<> *device_assembly = m.get_device_code_buffer(); + if (device_assembly) { generate_resize_bar(tab_count++); + generate_device_code_tab(*device_assembly); } - generate_assembly_tab(m); + stream << "
\n"; } - // Generate tab 1/3: Lowered IR code with syntax highlighting in HTML + // Generate tab: Lowered IR code with syntax highlighting in HTML void generate_ir_tab(const Module &m) { if (use_conceptual_stmt_ir) { stream << "
\n"; - html_code_printer.print_conceptual_stmt(m, asm_info); + html_code_printer.print_conceptual_stmt(m, host_asm_info, device_asm_info); stream << "
\n"; } else { stream << "
\n"; - html_code_printer.print(m, asm_info); + html_code_printer.print(m, host_asm_info, device_asm_info); stream << "
\n"; } } - // Generate tab 2/3: Lowered IR code with syntax highlighting in HTML + // Generate tab: Lowered IR code with syntax highlighting in HTML void generate_visualization_tab(const Module &m) { stream << "
\n"; - html_viz_printer.print(m, asm_info); + html_viz_printer.print(m, host_asm_info, device_asm_info); stream << "
\n"; } - // Generate tab 3/3: Generated assembly code - void generate_assembly_tab(const Module &m) { - stream << "
\n"; + // Generate tab: Generated host assembly code + void generate_host_assembly_tab(const Module &m) { + stream << "
\n"; stream << "
\n"; stream << "
\n";
         stream << asm_stream.str();
@@ -3057,6 +3128,21 @@ class IRVisualizer {
         stream << "
\n"; } + // Generate tab: Generated device code + void generate_device_code_tab(const Buffer<> &buf) { + stream << "
\n"; + std::string str((const char *)buf.data(), buf.size_in_bytes()); + if (starts_with(buf.name(), "cuda_")) { + html_code_printer.print_cuda_gpu_source_kernels(str); + } else { + stream << "
\n";
+            stream << str;
+            stream << "\n";
+            stream << "
\n"; + } + stream << "
\n"; + } + // Generate a resizing bar to control the width of code and visualization tabs void generate_resize_bar(int num) { stream << "
\n"; @@ -3077,7 +3163,8 @@ class IRVisualizer { // Load assembly code from file std::ostringstream asm_stream; - AssemblyInfo asm_info; + AssemblyInfo host_asm_info; + AssemblyInfo device_asm_info; void load_asm_code(const std::string &asm_file) { user_assert(file_exists(asm_file)) << "Unable to open assembly file: " << asm_file << "\n"; diff --git a/src/irvisualizer/html_template_StmtToHTML.css b/src/irvisualizer/html_template_StmtToHTML.css index b4de94115f10..b65e3a88073d 100644 --- a/src/irvisualizer/html_template_StmtToHTML.css +++ b/src/irvisualizer/html_template_StmtToHTML.css @@ -5,6 +5,7 @@ body { background: #f8f8f8; padding: 0; margin: 0; + line-height: 14px; } div#page-container { @@ -41,6 +42,7 @@ div.tab { overflow: scroll; position: relative; flex-grow: 1; + counter-reset: line; } div.tab.collapsed-tab { display: none; @@ -50,11 +52,26 @@ div#ir-code-tab { counter-reset: line; padding-left: 50px; padding-top: 20px; + flex-grow: 2; + flex-shrink: 20; + flex-basis: 50%; } -div#assembly-tab { +div#host-assembly-tab { min-width: 350px; - max-width: 30vw; + width: 30vw; + flex-grow: 1; + flex-shrink: 1; + flex-basis: 20%; +} + +div#device-code-tab { + min-width: 550px; + width: 50vw; + padding-left: 6em; + flex-grow: 2; + flex-shrink: 1; + flex-basis: 30%; } button#highlight-button { @@ -63,6 +80,18 @@ button#highlight-button { border-radius: 4px; } +span.line { + counter-increment: line; +} +span.line:before { + content: counter(line) "."; + color: rgb(175, 175, 175); + position: absolute; + left: 0px; + width: 4em; + text-align: right; +} + /* Resize bars */ div.resize-bar { @@ -97,13 +126,13 @@ div.resize-bar > div.collapse-btns button.collapse-right:before { content: "\21E div.collapsed-tab + div.resize-bar button.collapse-left { background-color: rgba(0, 0, 0, 0.2); } -div.collapsed-tab + div.resize-bar button.collapase-left:before { +div.collapsed-tab + div.resize-bar button.collapse-left:before { content: "\21A6"; } div.resize-bar:has(+ div.collapsed-tab) button.collapse-right { background-color: rgba(0, 0, 0, 0.2); } -div.resize-bar:has(+ div.collapsed-tab) button.collapse-right:before { +div.resize-bar:has(+ div.collapsed-tab) > div.collapse-btns button.collapse-right:before { content: "\21A4"; } @@ -113,6 +142,10 @@ button.resize-btn { font-size: 18px; } +div#device-code-tab code { + line-height: 14px; +} + /* IR Code Section CSS */ .ModuleBody { padding-left: 70px !important; @@ -366,13 +399,18 @@ button.icon-btn :before { display: inline-block; } -button.jump-to-asm-btn { +button.jump-to-host-asm-btn { background: rgba(255,50,0,0.1); - border-color: rgb(255,50,0); - color: rgb(255,50,0); + border-color: rgb( 255,50,0); + color: rgb( 255,50,0); +} +button.jump-to-device-code-btn { + background: rgba(70,170,50,0.1); + border-color: rgb( 70,170,50); + color: rgb( 70,170,50); } -button.jump-to-asm-btn span.tooltip span { +button.jump-to-host-asm-btn span.tooltip span, button.jump-to-device-code-btn span.tooltip span { display: block; margin-top: 0.6em; font-size: 10px; @@ -380,7 +418,7 @@ button.jump-to-asm-btn span.tooltip span { color: green; } -button.jump-to-asm-btn:before, button.jump-to-viz-btn:before { +button.jump-to-host-asm-btn:before, button.jump-to-device-code-btn:before, button.jump-to-viz-btn:before { content: "\279F"; } diff --git a/src/irvisualizer/html_template_StmtToHTML.js b/src/irvisualizer/html_template_StmtToHTML.js index 1822aa1b2587..8d68dabdc878 100644 --- a/src/irvisualizer/html_template_StmtToHTML.js +++ b/src/irvisualizer/html_template_StmtToHTML.js @@ -10,27 +10,33 @@ // Highlighting 'matched' elements in IR code -var matchedElements = document.querySelectorAll('#ir-code-tab .matched'); +function addHighlight(selector) { + var matchedElements = document.querySelectorAll(selector + ' .matched'); -matchedElements.forEach(function(element) { - element.addEventListener('mouseover', function() { - var idPrefix = this.id.split('-')[0]; - var matchingElements = document.querySelectorAll('#ir-code-tab .matched[id^="' + idPrefix + '-"]'); + matchedElements.forEach(function(element) { + element.addEventListener('mouseover', function() { + var idPrefix = this.id.split('-')[0]; + var matchingElements = document.querySelectorAll(selector + ' .matched[id^="' + idPrefix + '-"]'); - matchingElements.forEach(function(matchingElement) { - matchingElement.classList.add('Highlight'); + matchingElements.forEach(function(matchingElement) { + matchingElement.classList.add('Highlight'); + }); }); - }); - element.addEventListener('mouseout', function() { - var idPrefix = this.id.split('-')[0]; - var matchingElements = document.querySelectorAll('#ir-code-tab .matched[id^="' + idPrefix + '-"]'); + element.addEventListener('mouseout', function() { + var idPrefix = this.id.split('-')[0]; + var matchingElements = document.querySelectorAll(selector + ' .matched[id^="' + idPrefix + '-"]'); - matchingElements.forEach(function(matchingElement) { - matchingElement.classList.remove('Highlight'); + matchingElements.forEach(function(matchingElement) { + matchingElement.classList.remove('Highlight'); + }); }); }); -}); +} + +// Example usage: +addHighlight('#ir-code-tab'); +addHighlight('#ptx-assembly-tab'); @@ -149,12 +155,21 @@ function collapse_tab(index) { tab.classList.toggle('collapsed-tab'); } -function scrollToAsm(lno) { +function scrollToHostAsm(lno) { var asmContent = document.getElementById("assemblyContent"); var line_height = window.getComputedStyle(asmContent).getPropertyValue("line-height"); line_height = parseInt(line_height, 10); - document.getElementById("assembly-tab").scrollTo({ + document.getElementById("host-assembly-tab").scrollTo({ behavior: "smooth", top: lno * line_height }); } + +function scrollToDeviceCode(lno) { + var device_code_tab = document.getElementById("device-code-tab"); + const lineSpans = device_code_tab.querySelectorAll('span.line'); + line = lineSpans[lno - 1] + line.scrollIntoView({ + behavior: "smooth", + }); +} From f30e05ef17bea22d87d73dfa0c38e47385ddfea5 Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Mon, 11 Sep 2023 01:02:13 +0200 Subject: [PATCH 04/22] Resizing works decent enough for me. Fix cost-model allocate block costs. --- src/StmtToViz.cpp | 5 +- src/irvisualizer/html_template_StmtToHTML.css | 39 ++++- src/irvisualizer/html_template_StmtToHTML.js | 150 ++++++++---------- 3 files changed, 99 insertions(+), 95 deletions(-) diff --git a/src/StmtToViz.cpp b/src/StmtToViz.cpp index bc0185f8dca0..ed370de4ab4a 100644 --- a/src/StmtToViz.cpp +++ b/src/StmtToViz.cpp @@ -1358,7 +1358,7 @@ class HTMLCodePrinter : public IRVisitor { int max_line_cost = cost_model.get_max_compute_cost(false); int line_cost = cost_model.get_compute_cost(op, false); int block_cost = cost_model.get_compute_cost(op, true); - if (dynamic_cast(op)) { + if (dynamic_cast(op) || dynamic_cast(op)) { block_cost = line_cost; } std::string _id = "cc-" + std::to_string(id); @@ -1370,7 +1370,7 @@ class HTMLCodePrinter : public IRVisitor { int max_line_cost = cost_model.get_max_data_movement_cost(false); int line_cost = cost_model.get_data_movement_cost(op, false); int block_cost = cost_model.get_data_movement_cost(op, true); - if (dynamic_cast(op)) { + if (dynamic_cast(op) || dynamic_cast(op)) { block_cost = line_cost; } std::string _id = "dc-" + std::to_string(id); @@ -3080,6 +3080,7 @@ class IRVisualizer { void generate_visualization_tabs(const Module &m) { int tab_count = 0; stream << "
\n"; + stream << "
\n"; generate_ir_tab(m); if (include_viztree) { generate_resize_bar(tab_count++); diff --git a/src/irvisualizer/html_template_StmtToHTML.css b/src/irvisualizer/html_template_StmtToHTML.css index b65e3a88073d..37fe5d97c951 100644 --- a/src/irvisualizer/html_template_StmtToHTML.css +++ b/src/irvisualizer/html_template_StmtToHTML.css @@ -8,6 +8,11 @@ body { line-height: 14px; } +.no-select { + user-select: none; + -webkit-user-select: none; +} + div#page-container { height: 100vh; display: flex; @@ -36,13 +41,17 @@ div#visualization-tabs { flex-grow: 1; width: 100%; height: 100%; + position: relative; } div.tab { overflow: scroll; position: relative; flex-grow: 1; + flex-shrink: 1; counter-reset: line; + min-width: 5vw; + width: 33vw; } div.tab.collapsed-tab { display: none; @@ -52,26 +61,31 @@ div#ir-code-tab { counter-reset: line; padding-left: 50px; padding-top: 20px; - flex-grow: 2; + width: 50vw; + /*flex-grow: 2; flex-shrink: 20; - flex-basis: 50%; + flex-basis: 50%;*/ } div#host-assembly-tab { + width: 20vw; + /* min-width: 350px; width: 30vw; flex-grow: 1; flex-shrink: 1; - flex-basis: 20%; + flex-basis: 20%;*/ } div#device-code-tab { + padding-left: 6em; + width: 30vw; + /* min-width: 550px; width: 50vw; - padding-left: 6em; flex-grow: 2; flex-shrink: 1; - flex-basis: 30%; + flex-basis: 30%;*/ } button#highlight-button { @@ -136,12 +150,25 @@ div.resize-bar:has(+ div.collapsed-tab) > div.collapse-btns button.collapse-righ content: "\21A4"; } - button.resize-btn { margin: 10px 3px; font-size: 18px; } +/* Resizer Preview */ +div#resizer-preview { + position: absolute; + width: 4px; + height: 100%; + background-color: gray; + padding: 0; + margin: 0; + opacity: 50%; + z-index: 190000; +} + + + div#device-code-tab code { line-height: 14px; } diff --git a/src/irvisualizer/html_template_StmtToHTML.js b/src/irvisualizer/html_template_StmtToHTML.js index 8d68dabdc878..f1252ee74ec3 100644 --- a/src/irvisualizer/html_template_StmtToHTML.js +++ b/src/irvisualizer/html_template_StmtToHTML.js @@ -1,14 +1,3 @@ -// /* Highlighting 'matched' elements in IR code */ -// $('#ir-code-tab .matched').each(function () { -// this.onmouseover = function () { -// $('#ir-code-tab .matched[id^=' + this.id.split('-')[0] + '-]').addClass('Highlight'); -// } -// this.onmouseout = function () { -// $('#ir-code-tab .matched[id^=' + this.id.split('-')[0] + '-]').removeClass('Highlight'); -// } -// }); - - // Highlighting 'matched' elements in IR code function addHighlight(selector) { var matchedElements = document.querySelectorAll(selector + ' .matched'); @@ -36,57 +25,9 @@ function addHighlight(selector) { // Example usage: addHighlight('#ir-code-tab'); -addHighlight('#ptx-assembly-tab'); - - - -/* Expand/Collapse buttons in IR code */ -function toggle(id) { - e = document.getElementById(id); - e_cb = document.getElementsByClassName("cb-" + id)[0]; - show = document.getElementById(id + '-show'); - hide = document.getElementById(id + '-hide'); - ccost_btn = document.getElementById("cc-" + id); - dcost_btn = document.getElementById("dc-" + id); - ccost_tt = document.getElementById("tooltip-cc-" + id); - dcost_tt = document.getElementById("tooltip-dc-" + id); - if (e.classList.contains("collapsed-block")) { - e.classList.remove("collapsed-block"); - e_cb.classList.add("ClosingBrace"); - show.style.display = 'none'; - hide.style.display = 'block'; - if (ccost_btn && dcost_tt) { - // Update cost indicators - ccost_color = ccost_btn.getAttribute('line-cost-color'); - dcost_color = dcost_btn.getAttribute('line-cost-color'); - ccost_btn.className = ccost_btn.className.replace(/CostColor\d+/, 'CostColor' + ccost_color); - dcost_btn.className = dcost_btn.className.replace(/CostColor\d+/, 'CostColor' + dcost_color); - // Update cost tooltips - ccost = ccost_btn.getAttribute('line-cost'); - dcost = dcost_btn.getAttribute('line-cost'); - ccost_tt.innerText = 'Op Count: ' + ccost; - dcost_tt.innerText = 'Bits Moved: ' + dcost; - } - } else { - e.classList.add("collapsed-block"); - e_cb.classList.remove("ClosingBrace"); - show.style.display = 'block'; - hide.style.display = 'none'; - if (ccost_btn && dcost_tt) { - // Update cost indicators - collapsed_ccost_color = ccost_btn.getAttribute('block-cost-color'); - collapsed_dcost_color = dcost_btn.getAttribute('block-cost-color'); - ccost_btn.className = ccost_btn.className.replace(/CostColor\d+/, 'CostColor' + collapsed_ccost_color); - dcost_btn.className = dcost_btn.className.replace(/CostColor\d+/, 'CostColor' + collapsed_dcost_color); - // Update cost tooltips - collapsed_ccost = ccost_btn.getAttribute('block-cost'); - collapsed_dcost = dcost_btn.getAttribute('block-cost'); - ccost_tt.innerText = 'Op Count: ' + collapsed_ccost; - dcost_tt.innerText = 'Bits Moved: ' + collapsed_dcost; - } - } - return false; -} +addHighlight('#device-code-tab'); + + /* Scroll to code from visualization */ function scrollToCode(id) { @@ -103,51 +44,86 @@ function scrollToCode(id) { }, 1000); } -// In case the code we are scrolling to code that sits within -// a collapsed code block, uncollapse it -function makeCodeVisible(element) { - if (!element) return; - if (element == document) return; - if (element.classList.contains("collapsed-block")) { - toggle(element.id); - } - makeCodeVisible(element.parentNode); -} - - var currentResizer; +var currentResizerIndex; var mousedown = false; -var resizeBars = document.querySelectorAll('div.resize-bar'); +var resizeBars = Array.from(document.querySelectorAll('div.resize-bar')); +var resizerInitCenter = 0; +var resizerPreview = document.getElementById('resizer-preview'); +var resizerPreviewX; for (var i = 0; i < resizeBars.length; i++) { resizeBars[i].addEventListener('mousedown', (event) => { - currentResizer = event.target; - mousedown = true; + document.body.classList.add("no-select"); + if (event.target.classList.contains("resize-bar")) { + console.log(event.target); + + currentResizer = event.target; + currentResizerIndex = resizeBars.indexOf(currentResizer); + var rect = currentResizer.getBoundingClientRect(); + mousedown = true; + resizerInitCenter = event.x; + resizerPreviewX = event.x; + resizerPreview.style.left = resizerInitCenter + 'px'; + resizerPreview.style.display = 'block'; + } }); } document.addEventListener('mouseup', (event) => { - currentResizer = null; - mousedown = false; + if (mousedown) { + + currentResizer = null; + mousedown = false; + resizerPreview.style.display = 'none'; + + // Gather tab widths + var tabs = Array.from(document.querySelectorAll('div.tab')); + var widths = tabs.map(function(tab) { + return tab.getBoundingClientRect().width; + }); + + + // Adjust tab widths + var diff = resizerPreviewX - resizerInitCenter; + console.log(diff); + var currentIndex = currentResizerIndex; + while (currentIndex >= 0 && tabs[currentIndex].classList.contains('collapsed-tab')) { + currentIndex-- + } + widths[currentIndex] += diff; + + currentIndex = currentResizerIndex + 1; + while (currentIndex < tabs.length && tabs[currentIndex].classList.contains('collapsed-tab')) { + currentIndex++; + } + widths[currentIndex] -= diff; + + // Apply tab widths + tabs.forEach(function(tab, index) { + if (widths[index] >= 0) { + tab.style.width = widths[index] + 'px'; + } else { + tab.style.width = '0px'; // or any other default value you want to set + } + }); + } + + document.body.classList.remove("no-select"); }); document.addEventListener('mousemove', (event) => { if (mousedown) { - resize(event); + resizerPreview.style.left = event.x + 'px'; + resizerPreviewX = event.x; } }); -function resize(e) { - const size = `${e.x}px`; - var rect = currentResizer.getBoundingClientRect(); - // TODO resize -} - function collapse_tab(index) { var tabs = document.getElementById("visualization-tabs"); - var tab = tabs.firstElementChild; + var tab = tabs.firstElementChild.nextElementSibling; for (var i = 0; i < index; ++i) { tab = tab.nextElementSibling.nextElementSibling; } From 4721018799cef9c35a36a085ea6cdafaa215f206 Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Mon, 11 Sep 2023 01:34:05 +0200 Subject: [PATCH 05/22] Print better vector_reduce calls. --- src/IRPrinter.cpp | 29 +++++++++++++++++++++++++++-- src/IRPrinter.h | 1 + src/StmtToViz.cpp | 35 ++++++++++++++++++++++++++++++----- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/IRPrinter.cpp b/src/IRPrinter.cpp index 0d746e034483..ac891af851e3 100644 --- a/src/IRPrinter.cpp +++ b/src/IRPrinter.cpp @@ -1085,10 +1085,35 @@ void IRPrinter::visit(const Shuffle *op) { } void IRPrinter::visit(const VectorReduce *op) { + std::string op_str; + switch (op->op) { + case VectorReduce::Add: + op_str = "add"; + break; + case VectorReduce::SaturatingAdd: + op_str = "saturating_add"; + break; + case VectorReduce::Mul: + op_str = "mul"; + break; + case VectorReduce::Min: + op_str = "min"; + break; + case VectorReduce::Max: + op_str = "max"; + break; + case VectorReduce::And: + op_str = "and"; + break; + case VectorReduce::Or: + op_str = "or"; + break; + default: + internal_assert(false) << "Not a valid VectorReduce::Operator"; + } stream << "(" << op->type - << ")vector_reduce(" - << op->op + << ")vector_reduce_" << op_str << "(" << ", " << op->value << ")"; diff --git a/src/IRPrinter.h b/src/IRPrinter.h index 666235988cd7..7aaaea8fb4fd 100644 --- a/src/IRPrinter.h +++ b/src/IRPrinter.h @@ -95,6 +95,7 @@ struct Indentation { }; std::ostream &operator<<(std::ostream &stream, const Indentation &); + /** An IRVisitor that emits IR to the given output stream in a human * readable form. Can be subclassed if you want to modify the way in * which it prints. diff --git a/src/StmtToViz.cpp b/src/StmtToViz.cpp index ed370de4ab4a..c93d3ca8ecca 100644 --- a/src/StmtToViz.cpp +++ b/src/StmtToViz.cpp @@ -804,7 +804,6 @@ class HTMLCodePrinter : public IRVisitor { std::string current_kernel; std::istringstream ss(str); - for (std::string line; std::getline(ss, line);) { if (line.empty()) { stream << "\n"; @@ -1358,7 +1357,7 @@ class HTMLCodePrinter : public IRVisitor { int max_line_cost = cost_model.get_max_compute_cost(false); int line_cost = cost_model.get_compute_cost(op, false); int block_cost = cost_model.get_compute_cost(op, true); - if (dynamic_cast(op) || dynamic_cast(op)) { + if (dynamic_cast(op) || dynamic_cast(op)) { block_cost = line_cost; } std::string _id = "cc-" + std::to_string(id); @@ -1370,7 +1369,7 @@ class HTMLCodePrinter : public IRVisitor { int max_line_cost = cost_model.get_max_data_movement_cost(false); int line_cost = cost_model.get_data_movement_cost(op, false); int block_cost = cost_model.get_data_movement_cost(op, true); - if (dynamic_cast(op) || dynamic_cast(op)) { + if (dynamic_cast(op) || dynamic_cast(op)) { block_cost = line_cost; } std::string _id = "dc-" + std::to_string(id); @@ -2237,7 +2236,33 @@ class HTMLCodePrinter : public IRVisitor { print_text("("); print_type(op->type); print_text(")"); - print_function_call("vector_reduce", {op->op, op->value}); + std::string op_str; + switch (op->op) { + case VectorReduce::Add: + op_str = "add"; + break; + case VectorReduce::SaturatingAdd: + op_str = "saturating_add"; + break; + case VectorReduce::Mul: + op_str = "mul"; + break; + case VectorReduce::Min: + op_str = "min"; + break; + case VectorReduce::Max: + op_str = "max"; + break; + case VectorReduce::And: + op_str = "and"; + break; + case VectorReduce::Or: + op_str = "or"; + break; + default: + internal_assert(false) << "Not a valid VectorReduce::Operator"; + } + print_function_call("vector_reduce_" + op_str, {op->value}); print_closing_tag("span"); print_ln(); } @@ -2972,7 +2997,7 @@ class IRVisualizer { debug(1) << "Generating device AssemblyInfo\n"; // TODO(mcourteaux): This doesn't generate anything useful, as the // LLVM comments are only added later in the LLVM CodeGen IRVisitor. - // This conceptual Stmt hasn't seen this seen this + // This conceptual Stmt hasn't seen this seen this device_asm_info.gather_nodes_from_conceptual_stmt(m); device_asm_info.generate(device_assembly); } else { From c1fed176cd67ba3bebb0a52724c6e27f89463a83 Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Tue, 12 Sep 2023 19:28:39 +0200 Subject: [PATCH 06/22] Optionally enable VizTree through an env variable. --- src/Generator.cpp | 4 +++- src/Module.cpp | 14 ++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Generator.cpp b/src/Generator.cpp index 4ea3e4effc54..6cc7eb3c7244 100644 --- a/src/Generator.cpp +++ b/src/Generator.cpp @@ -655,6 +655,8 @@ gengen schedule, static_library, stmt, stmt_html, conceptual_stmt, conceptual_stmt_html, compiler_log, hlpipe, ptx_assembly]. If omitted, default value is [c_header, static_library, registration]. + For the HTML-options optionally setting HL_HTML_VIZTREE=1 will enable the + old VizIR Tree pane in the generated HTML. -p A comma-separated list of shared libraries that will be loaded before the generator is run. Useful for custom auto-schedulers. The generator must @@ -663,7 +665,7 @@ gengen (Note that this does not change the default autoscheduler; use the -s flag to set that value.)" - -r The name of a standalone runtime to generate. Only honors EMIT_OPTIONS 'o' + -r The name of a standalone runtime to generate. Only honors EMIT_OPTIONS 'o' and 'static_library'. When multiple targets are specified, it picks a runtime that is compatible with all of the targets, or fails if it cannot find one. Flags across all of the targets that do not affect runtime code diff --git a/src/Module.cpp b/src/Module.cpp index b897b4cae78b..9fde882f74b5 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -671,13 +671,19 @@ void Module::compile(const std::map &output_files) } if (contains(output_files, OutputFileType::stmt_html)) { internal_assert(!assembly_path.empty()); - debug(1) << "Module.compile(): stmt_html " << output_files.at(OutputFileType::stmt_html) << "\n"; - Internal::print_to_stmt_html(output_files.at(OutputFileType::stmt_html), *this, assembly_path, false); + bool enable_viztree = get_env_variable("HL_HTML_VIZTREE") == "1"; + debug(1) << "Module.compile(): stmt_html " << output_files.at(OutputFileType::stmt_html) + << " (viztree_enabled: " << enable_viztree << ")\n"; + Internal::print_to_stmt_html(output_files.at(OutputFileType::stmt_html), + *this, assembly_path, enable_viztree); } if (contains(output_files, OutputFileType::conceptual_stmt_html)) { internal_assert(!assembly_path.empty()); - debug(1) << "Module.compile(): conceptual_stmt_html " << output_files.at(OutputFileType::stmt_html) << "\n"; - Internal::print_to_conceptual_stmt_html(output_files.at(OutputFileType::conceptual_stmt_html), *this, assembly_path); + bool enable_viztree = get_env_variable("HL_HTML_VIZTREE") == "1"; + debug(1) << "Module.compile(): conceptual_stmt_html " << output_files.at(OutputFileType::stmt_html) + << " (viztree_enabled: " << enable_viztree << ")\n"; + Internal::print_to_conceptual_stmt_html(output_files.at(OutputFileType::conceptual_stmt_html), + *this, assembly_path, enable_viztree); } if (contains(output_files, OutputFileType::ptx_assembly)) { debug(1) << "Module.compile(): ptx_assembly " << output_files.at(OutputFileType::ptx_assembly) << "\n"; From 214d10694f32d2b8aa155039ef6b1f3166e4afc0 Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Tue, 12 Sep 2023 20:32:59 +0200 Subject: [PATCH 07/22] Fix the device code tab for non-PTX. --- src/StmtToViz.cpp | 4 ++-- src/irvisualizer/html_template_StmtToHTML.css | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/StmtToViz.cpp b/src/StmtToViz.cpp index c93d3ca8ecca..51e0ff3394c9 100644 --- a/src/StmtToViz.cpp +++ b/src/StmtToViz.cpp @@ -3161,10 +3161,10 @@ class IRVisualizer { if (starts_with(buf.name(), "cuda_")) { html_code_printer.print_cuda_gpu_source_kernels(str); } else { - stream << "
\n";
+            stream << "\n";
             stream << str;
             stream << "\n";
-            stream << "
\n"; + stream << "\n"; } stream << "
\n"; } diff --git a/src/irvisualizer/html_template_StmtToHTML.css b/src/irvisualizer/html_template_StmtToHTML.css index 37fe5d97c951..9dd4d1d96f3f 100644 --- a/src/irvisualizer/html_template_StmtToHTML.css +++ b/src/irvisualizer/html_template_StmtToHTML.css @@ -171,6 +171,7 @@ div#resizer-preview { div#device-code-tab code { line-height: 14px; + white-space: pre; } /* IR Code Section CSS */ @@ -460,7 +461,6 @@ button.icon-btn:hover { code.ptx { tab-size: 26; - white-space: pre; } span.comment { From 039496366771f9a0a7434970c5f7e68f5a3cc007 Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Thu, 14 Sep 2023 13:44:40 +0200 Subject: [PATCH 08/22] StmtHTML: Tabs renamed to panes. Fix linter warnings. Cut trailing 0 byte from device code buffers. --- src/Generator.cpp | 2 +- src/IRPrinter.h | 1 - src/Module.cpp | 33 +++---- src/Module.h | 3 +- src/StmtToViz.cpp | 68 +++++++------- src/irvisualizer/html_template_StmtToHTML.css | 28 +++--- src/irvisualizer/html_template_StmtToHTML.js | 88 ++++++++++--------- .../html_template_StmtToViz_dependencies.html | 2 +- 8 files changed, 117 insertions(+), 108 deletions(-) diff --git a/src/Generator.cpp b/src/Generator.cpp index 6cc7eb3c7244..b7e7a2c6ec3b 100644 --- a/src/Generator.cpp +++ b/src/Generator.cpp @@ -653,7 +653,7 @@ gengen [assembly, bitcode, c_header, c_source, cpp_stub, featurization, llvm_assembly, object, python_extension, pytorch_wrapper, registration, schedule, static_library, stmt, stmt_html, conceptual_stmt, - conceptual_stmt_html, compiler_log, hlpipe, ptx_assembly]. + conceptual_stmt_html, compiler_log, hlpipe, device_code]. If omitted, default value is [c_header, static_library, registration]. For the HTML-options optionally setting HL_HTML_VIZTREE=1 will enable the old VizIR Tree pane in the generated HTML. diff --git a/src/IRPrinter.h b/src/IRPrinter.h index 7aaaea8fb4fd..666235988cd7 100644 --- a/src/IRPrinter.h +++ b/src/IRPrinter.h @@ -95,7 +95,6 @@ struct Indentation { }; std::ostream &operator<<(std::ostream &stream, const Indentation &); - /** An IRVisitor that emits IR to the given output stream in a human * readable form. Can be subclassed if you want to modify the way in * which it prints. diff --git a/src/Module.cpp b/src/Module.cpp index 9fde882f74b5..41397c25a330 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -52,7 +52,7 @@ std::map get_output_info(const Target &target) {OutputFileType::conceptual_stmt, {"coneptual_stmt", ".conceptual.stmt", IsMulti}}, {OutputFileType::stmt_html, {"stmt_html", ".stmt.html", IsMulti}}, {OutputFileType::conceptual_stmt_html, {"conceptual_stmt_html", ".conceptual.stmt.html", IsMulti}}, - {OutputFileType::ptx_assembly, {"ptx_assembly", ".ptx", IsMulti}}, + {OutputFileType::device_code, {"device_code", ".device_code", IsMulti}}, }; return ext; } @@ -685,23 +685,24 @@ void Module::compile(const std::map &output_files) Internal::print_to_conceptual_stmt_html(output_files.at(OutputFileType::conceptual_stmt_html), *this, assembly_path, enable_viztree); } - if (contains(output_files, OutputFileType::ptx_assembly)) { - debug(1) << "Module.compile(): ptx_assembly " << output_files.at(OutputFileType::ptx_assembly) << "\n"; - std::string gpu_kernel_sources; - for (const Buffer<> &buf : buffers()) { - debug(1) << "Looking for GPU sources: " << buf.name() << "\n"; - if (ends_with(buf.name(), "_gpu_source_kernels")) { - internal_assert(gpu_kernel_sources.empty()); // There should be only one! - gpu_kernel_sources = std::string((const char *)buf.data(), buf.size_in_bytes()); + if (contains(output_files, OutputFileType::device_code)) { + debug(1) << "Module.compile(): device_code " << output_files.at(OutputFileType::device_code) << "\n"; + if (const Buffer<> *buf = get_device_code_buffer()) { + int length = buf->size_in_bytes(); + while (length > 0 && ((const char*)buf->data())[length - 1] == '\0') { + length--; } - } - if (gpu_kernel_sources.empty()) { - debug(1) << "No GPU kernel sources emitted.\n"; - } else { - std::ofstream file(output_files.at(OutputFileType::ptx_assembly)); - file << gpu_kernel_sources << "\n"; + std::string str((const char *)buf->data(), length); + std::string device_code = std::string((const char *)buf->data(), buf->size_in_bytes()); + while (!device_code.empty() && device_code.back() == 0) { + device_code = device_code.substr(0, device_code.length() - 1); + } + std::ofstream file(output_files.at(OutputFileType::device_code)); + file << device_code << "\n"; file.close(); - debug(1) << "Saved GPU kernel sources (" << gpu_kernel_sources.size() << " bytes).\n"; + debug(1) << "Saved GPU kernel sources (" << device_code.size() << " bytes).\n"; + } else { + debug(1) << "No GPU kernel sources emitted.\n"; } } if (contains(output_files, OutputFileType::function_info_header)) { diff --git a/src/Module.h b/src/Module.h index 8678a3520c5b..7e193f0b93ae 100644 --- a/src/Module.h +++ b/src/Module.h @@ -44,7 +44,7 @@ enum class OutputFileType { conceptual_stmt, stmt_html, conceptual_stmt_html, - ptx_assembly, + device_code, }; /** Type of linkage a function in a lowered Halide module can have. @@ -172,7 +172,6 @@ class Module { */ const Buffer<> *get_cuda_ptx_assembly_buffer() const; - /** * Tries to locate the offloaded (GPU) Device assembly contained in this Module. * This can be any of the GPU kernel sources, etc... diff --git a/src/StmtToViz.cpp b/src/StmtToViz.cpp index 51e0ff3394c9..b1dbba23642a 100644 --- a/src/StmtToViz.cpp +++ b/src/StmtToViz.cpp @@ -1021,7 +1021,11 @@ class HTMLCodePrinter : public IRVisitor { // Open indented div to hold buffer data print_opening_tag("div", "indent BufferData", id); - std::string str((const char *)buf.data(), buf.size_in_bytes()); + int length = buf.size_in_bytes(); + while (length > 0 && ((const char*)buf.data())[length - 1] == '\0') { + length--; + } + std::string str((const char *)buf.data(), length); if (starts_with(buf.name(), "cuda_")) { print_cuda_gpu_source_kernels(str); } else { @@ -3078,7 +3082,7 @@ class IRVisualizer { void generate_body(const Module &m) { stream << "\n"; stream << "
\n"; - generate_visualization_tabs(m); + generate_visualization_panes(m); stream << "
\n"; stream << ""; #if INLINE_TEMPLATES @@ -3101,50 +3105,50 @@ class IRVisualizer { #endif } - // Generate the three visualization tabs - void generate_visualization_tabs(const Module &m) { - int tab_count = 0; - stream << "
\n"; + // Generate the three visualization panes + void generate_visualization_panes(const Module &m) { + int pane_count = 0; + stream << "
\n"; stream << "
\n"; - generate_ir_tab(m); + generate_ir_pane(m); if (include_viztree) { - generate_resize_bar(tab_count++); - generate_visualization_tab(m); + generate_resize_bar(pane_count++); + generate_visualization_pane(m); } - generate_resize_bar(tab_count++); - generate_host_assembly_tab(m); + generate_resize_bar(pane_count++); + generate_host_assembly_pane(m); const Buffer<> *device_assembly = m.get_device_code_buffer(); if (device_assembly) { - generate_resize_bar(tab_count++); - generate_device_code_tab(*device_assembly); + generate_resize_bar(pane_count++); + generate_device_code_pane(*device_assembly); } stream << "
\n"; } - // Generate tab: Lowered IR code with syntax highlighting in HTML - void generate_ir_tab(const Module &m) { + // Generate pane: Lowered IR code with syntax highlighting in HTML + void generate_ir_pane(const Module &m) { if (use_conceptual_stmt_ir) { - stream << "
\n"; + stream << "
\n"; html_code_printer.print_conceptual_stmt(m, host_asm_info, device_asm_info); stream << "
\n"; } else { - stream << "
\n"; + stream << "
\n"; html_code_printer.print(m, host_asm_info, device_asm_info); stream << "
\n"; } } - // Generate tab: Lowered IR code with syntax highlighting in HTML - void generate_visualization_tab(const Module &m) { - stream << "
\n"; + // Generate pane: Lowered IR code with syntax highlighting in HTML + void generate_visualization_pane(const Module &m) { + stream << "
\n"; html_viz_printer.print(m, host_asm_info, device_asm_info); stream << "
\n"; } - // Generate tab: Generated host assembly code - void generate_host_assembly_tab(const Module &m) { - stream << "
\n"; + // Generate pane: Generated host assembly code + void generate_host_assembly_pane(const Module &m) { + stream << "
\n"; stream << "
\n"; stream << "
\n";
         stream << asm_stream.str();
@@ -3154,10 +3158,14 @@ class IRVisualizer {
         stream << "
\n"; } - // Generate tab: Generated device code - void generate_device_code_tab(const Buffer<> &buf) { - stream << "
\n"; - std::string str((const char *)buf.data(), buf.size_in_bytes()); + // Generate pane: Generated device code + void generate_device_code_pane(const Buffer<> &buf) { + stream << "
\n"; + int length = buf.size_in_bytes(); + while (length > 0 && ((const char*)buf.data())[length - 1] == '\0') { + length--; + } + std::string str((const char *)buf.data(), length); if (starts_with(buf.name(), "cuda_")) { html_code_printer.print_cuda_gpu_source_kernels(str); } else { @@ -3169,16 +3177,16 @@ class IRVisualizer { stream << "
\n"; } - // Generate a resizing bar to control the width of code and visualization tabs + // Generate a resizing bar to control the width of code and visualization panes void generate_resize_bar(int num) { stream << "
\n"; stream << "
\n"; stream << "
\n"; - stream << " \n"; stream << "
\n"; stream << "
\n"; - stream << " \n"; stream << "
\n"; stream << "
\n"; diff --git a/src/irvisualizer/html_template_StmtToHTML.css b/src/irvisualizer/html_template_StmtToHTML.css index 9dd4d1d96f3f..622e9a2573ff 100644 --- a/src/irvisualizer/html_template_StmtToHTML.css +++ b/src/irvisualizer/html_template_StmtToHTML.css @@ -35,8 +35,8 @@ table { font-size: 12px; } -/* Visualization tabs */ -div#visualization-tabs { +/* Visualization panes */ +div#visualization-panes { display: flex; flex-grow: 1; width: 100%; @@ -44,7 +44,7 @@ div#visualization-tabs { position: relative; } -div.tab { +div.pane { overflow: scroll; position: relative; flex-grow: 1; @@ -53,11 +53,11 @@ div.tab { min-width: 5vw; width: 33vw; } -div.tab.collapsed-tab { +div.pane.collapsed-pane { display: none; } -div#ir-code-tab { +div#ir-code-pane { counter-reset: line; padding-left: 50px; padding-top: 20px; @@ -67,7 +67,7 @@ div#ir-code-tab { flex-basis: 50%;*/ } -div#host-assembly-tab { +div#host-assembly-pane { width: 20vw; /* min-width: 350px; @@ -77,7 +77,7 @@ div#host-assembly-tab { flex-basis: 20%;*/ } -div#device-code-tab { +div#device-code-pane { padding-left: 6em; width: 30vw; /* @@ -137,16 +137,16 @@ div.resize-bar > div.collapse-btns button.collapse-left:before { content: "\21E div.resize-bar > div.collapse-btns button.collapse-right:before { content: "\21E5"; } /* Revert collapser button that points to the left. */ -div.collapsed-tab + div.resize-bar button.collapse-left { +div.collapsed-pane + div.resize-bar button.collapse-left { background-color: rgba(0, 0, 0, 0.2); } -div.collapsed-tab + div.resize-bar button.collapse-left:before { +div.collapsed-pane + div.resize-bar button.collapse-left:before { content: "\21A6"; } -div.resize-bar:has(+ div.collapsed-tab) button.collapse-right { +div.resize-bar:has(+ div.collapsed-pane) button.collapse-right { background-color: rgba(0, 0, 0, 0.2); } -div.resize-bar:has(+ div.collapsed-tab) > div.collapse-btns button.collapse-right:before { +div.resize-bar:has(+ div.collapsed-pane) > div.collapse-btns button.collapse-right:before { content: "\21A4"; } @@ -169,7 +169,7 @@ div#resizer-preview { -div#device-code-tab code { +div#device-code-pane code { line-height: 14px; white-space: pre; } @@ -450,7 +450,7 @@ button.jump-to-host-asm-btn:before, button.jump-to-device-code-btn:before, butto content: "\279F"; } -div#ir-visualization-tab button.icon-btn { +div#ir-visualization-pane button.icon-btn { margin-left: 1px; } @@ -460,7 +460,7 @@ button.icon-btn:hover { } code.ptx { - tab-size: 26; + pane-size: 26; } span.comment { diff --git a/src/irvisualizer/html_template_StmtToHTML.js b/src/irvisualizer/html_template_StmtToHTML.js index f1252ee74ec3..d3db63c960ab 100644 --- a/src/irvisualizer/html_template_StmtToHTML.js +++ b/src/irvisualizer/html_template_StmtToHTML.js @@ -24,22 +24,20 @@ function addHighlight(selector) { } // Example usage: -addHighlight('#ir-code-tab'); -addHighlight('#device-code-tab'); - - +addHighlight('#ir-code-pane'); +addHighlight('#device-code-pane'); /* Scroll to code from visualization */ -function scrollToCode(id) { - var container = document.getElementById('ir-code-tab'); +function scrollToCode(id) { // eslint-disable-line no-unused-vars + var container = document.getElementById('ir-code-pane'); var scrollToObject = document.getElementById(id); makeCodeVisible(scrollToObject); container.scrollTo({ - top: scrollToObject.offsetTop, - behavior: 'smooth' + top : scrollToObject.offsetTop, + behavior : 'smooth' }); scrollToObject.style.backgroundColor = 'lightgray'; - setTimeout(function () { + setTimeout(function() { scrollToObject.style.backgroundColor = 'transparent'; }, 1000); } @@ -57,11 +55,8 @@ for (var i = 0; i < resizeBars.length; i++) { resizeBars[i].addEventListener('mousedown', (event) => { document.body.classList.add("no-select"); if (event.target.classList.contains("resize-bar")) { - console.log(event.target); - currentResizer = event.target; currentResizerIndex = resizeBars.indexOf(currentResizer); - var rect = currentResizer.getBoundingClientRect(); mousedown = true; resizerInitCenter = event.x; resizerPreviewX = event.x; @@ -73,39 +68,36 @@ for (var i = 0; i < resizeBars.length; i++) { document.addEventListener('mouseup', (event) => { if (mousedown) { - currentResizer = null; mousedown = false; resizerPreview.style.display = 'none'; - // Gather tab widths - var tabs = Array.from(document.querySelectorAll('div.tab')); - var widths = tabs.map(function(tab) { - return tab.getBoundingClientRect().width; + // Gather pane widths + var panes = Array.from(document.querySelectorAll('div.pane')); + var widths = panes.map(function(pane) { + return pane.getBoundingClientRect().width; }); - - // Adjust tab widths + // Adjust pane widths var diff = resizerPreviewX - resizerInitCenter; - console.log(diff); var currentIndex = currentResizerIndex; - while (currentIndex >= 0 && tabs[currentIndex].classList.contains('collapsed-tab')) { + while (currentIndex >= 0 && panes[currentIndex].classList.contains('collapsed-pane')) { currentIndex-- } widths[currentIndex] += diff; currentIndex = currentResizerIndex + 1; - while (currentIndex < tabs.length && tabs[currentIndex].classList.contains('collapsed-tab')) { + while (currentIndex < panes.length && panes[currentIndex].classList.contains('collapsed-pane')) { currentIndex++; } widths[currentIndex] -= diff; - // Apply tab widths - tabs.forEach(function(tab, index) { + // Apply pane widths + panes.forEach(function(pane, index) { if (widths[index] >= 0) { - tab.style.width = widths[index] + 'px'; + pane.style.width = widths[index] + 'px'; } else { - tab.style.width = '0px'; // or any other default value you want to set + pane.style.width = '0px'; // or any other default value you want to set } }); } @@ -120,32 +112,42 @@ document.addEventListener('mousemove', (event) => { } }); - -function collapse_tab(index) { - var tabs = document.getElementById("visualization-tabs"); - var tab = tabs.firstElementChild.nextElementSibling; +function collapseTab(index) { // eslint-disable-line no-unused-vars + var panes = document.getElementById("visualization-panes"); + var pane = panes.firstElementChild.nextElementSibling; for (var i = 0; i < index; ++i) { - tab = tab.nextElementSibling.nextElementSibling; + pane = pane.nextElementSibling.nextElementSibling; } - tab.classList.toggle('collapsed-tab'); + pane.classList.toggle('collapsed-pane'); } -function scrollToHostAsm(lno) { +function scrollToHostAsm(lno) { // eslint-disable-line no-unused-vars var asmContent = document.getElementById("assemblyContent"); var line_height = window.getComputedStyle(asmContent).getPropertyValue("line-height"); line_height = parseInt(line_height, 10); - document.getElementById("host-assembly-tab").scrollTo({ - behavior: "smooth", - top: lno * line_height + document.getElementById("host-assembly-pane").scrollTo({ + behavior : "smooth", + top : lno * line_height }); } -function scrollToDeviceCode(lno) { - var device_code_tab = document.getElementById("device-code-tab"); - const lineSpans = device_code_tab.querySelectorAll('span.line'); - line = lineSpans[lno - 1] - line.scrollIntoView({ - behavior: "smooth", - }); +function scrollToDeviceCode(lno) { // eslint-disable-line no-unused-vars + var device_code_pane = document.getElementById("device-code-pane"); + const lineSpans = device_code_pane.querySelectorAll('span.line'); + if (lno - 1 < lineSpans.length) { + var line = lineSpans[lno - 1] + line.scrollIntoView({ + behavior : "smooth" + }); + } else { + // Non-syntax highlighted code does not have the line-spans. + // We will have to calculate based on the line height. + var line_height = window.getComputedStyle(device_code_Tab.firstElementChild).getPropertyValue("line-height"); + line_height = parseInt(line_height, 10); + device_code_pane.scrollTo({ + behavior : "smooth", + top : lno * line_height + }); + } } diff --git a/src/irvisualizer/html_template_StmtToViz_dependencies.html b/src/irvisualizer/html_template_StmtToViz_dependencies.html index 68166eeec540..7de659ca6588 100644 --- a/src/irvisualizer/html_template_StmtToViz_dependencies.html +++ b/src/irvisualizer/html_template_StmtToViz_dependencies.html @@ -1,4 +1,4 @@ - + From 10051e2a98524a1c19f0c07ba522674ad3e66e0b Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Thu, 14 Sep 2023 13:49:55 +0200 Subject: [PATCH 09/22] Fix clang-format. --- src/Module.cpp | 2 +- src/StmtToViz.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 41397c25a330..16adfb1f84b5 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -689,7 +689,7 @@ void Module::compile(const std::map &output_files) debug(1) << "Module.compile(): device_code " << output_files.at(OutputFileType::device_code) << "\n"; if (const Buffer<> *buf = get_device_code_buffer()) { int length = buf->size_in_bytes(); - while (length > 0 && ((const char*)buf->data())[length - 1] == '\0') { + while (length > 0 && ((const char *)buf->data())[length - 1] == '\0') { length--; } std::string str((const char *)buf->data(), length); diff --git a/src/StmtToViz.cpp b/src/StmtToViz.cpp index b1dbba23642a..32eedebfb2e2 100644 --- a/src/StmtToViz.cpp +++ b/src/StmtToViz.cpp @@ -1022,7 +1022,7 @@ class HTMLCodePrinter : public IRVisitor { print_opening_tag("div", "indent BufferData", id); int length = buf.size_in_bytes(); - while (length > 0 && ((const char*)buf.data())[length - 1] == '\0') { + while (length > 0 && ((const char *)buf.data())[length - 1] == '\0') { length--; } std::string str((const char *)buf.data(), length); @@ -3162,7 +3162,7 @@ class IRVisualizer { void generate_device_code_pane(const Buffer<> &buf) { stream << "
\n"; int length = buf.size_in_bytes(); - while (length > 0 && ((const char*)buf.data())[length - 1] == '\0') { + while (length > 0 && ((const char *)buf.data())[length - 1] == '\0') { length--; } std::string str((const char *)buf.data(), length); From de1970f2d63542cc5b49020fc3e1b1472f932498 Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Fri, 15 Sep 2023 11:36:41 +0200 Subject: [PATCH 10/22] Fixed typos and copy paste error. --- src/Module.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 16adfb1f84b5..46c234cde95b 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -49,7 +49,7 @@ std::map get_output_info(const Target &target) {OutputFileType::schedule, {"schedule", ".schedule.h", IsSingle}}, {OutputFileType::static_library, {"static_library", is_windows_coff ? ".lib" : ".a", IsSingle}}, {OutputFileType::stmt, {"stmt", ".stmt", IsMulti}}, - {OutputFileType::conceptual_stmt, {"coneptual_stmt", ".conceptual.stmt", IsMulti}}, + {OutputFileType::conceptual_stmt, {"conceptual_stmt", ".conceptual.stmt", IsMulti}}, {OutputFileType::stmt_html, {"stmt_html", ".stmt.html", IsMulti}}, {OutputFileType::conceptual_stmt_html, {"conceptual_stmt_html", ".conceptual.stmt.html", IsMulti}}, {OutputFileType::device_code, {"device_code", ".device_code", IsMulti}}, @@ -680,7 +680,7 @@ void Module::compile(const std::map &output_files) if (contains(output_files, OutputFileType::conceptual_stmt_html)) { internal_assert(!assembly_path.empty()); bool enable_viztree = get_env_variable("HL_HTML_VIZTREE") == "1"; - debug(1) << "Module.compile(): conceptual_stmt_html " << output_files.at(OutputFileType::stmt_html) + debug(1) << "Module.compile(): conceptual_stmt_html " << output_files.at(OutputFileType::conceptual_stmt_html) << " (viztree_enabled: " << enable_viztree << ")\n"; Internal::print_to_conceptual_stmt_html(output_files.at(OutputFileType::conceptual_stmt_html), *this, assembly_path, enable_viztree); @@ -694,7 +694,7 @@ void Module::compile(const std::map &output_files) } std::string str((const char *)buf->data(), length); std::string device_code = std::string((const char *)buf->data(), buf->size_in_bytes()); - while (!device_code.empty() && device_code.back() == 0) { + while (!device_code.empty() && device_code.back() == '\0') { device_code = device_code.substr(0, device_code.length() - 1); } std::ofstream file(output_files.at(OutputFileType::device_code)); From b6aa957eab90c838a5ad6ffa9e250c92a70069f6 Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Fri, 15 Sep 2023 22:19:53 +0200 Subject: [PATCH 11/22] Fix HL_EXTRA_OUTPUTS behaviour to respect the defaults. --- src/Generator.cpp | 79 ++++++++++++++++++++++++----------------------- src/StmtToViz.cpp | 22 ++++++------- 2 files changed, 51 insertions(+), 50 deletions(-) diff --git a/src/Generator.cpp b/src/Generator.cpp index b7e7a2c6ec3b..46e6770002f6 100644 --- a/src/Generator.cpp +++ b/src/Generator.cpp @@ -776,6 +776,12 @@ gengen std::set output_types; std::string emit_flags_string = flags_info["-e"]; + + // If omitted or empty, assume .a and .h and registration.cpp + if (emit_flags_string.empty()) { + emit_flags_string = "c_header,registration,static_library"; + } + // If HL_EXTRA_OUTPUTS is defined, assume it's extra outputs we want to generate // (usually for temporary debugging purposes) and just tack it on to the -e contents. std::string extra_outputs = get_env_variable("HL_EXTRA_OUTPUTS"); @@ -787,50 +793,45 @@ gengen } const std::vector emit_flags = split_string(emit_flags_string, ","); + internal_assert(!emit_flags.empty()) << "Empty emit flags.\n"; + + // Build a reverse lookup table. Allow some legacy aliases on the command line, + // to allow legacy build systems to work more easily. + std::map output_name_to_enum = { + {"cpp", OutputFileType::c_source}, + {"h", OutputFileType::c_header}, + {"hlpipe", OutputFileType::hlpipe}, + {"html", OutputFileType::stmt_html}, + {"o", OutputFileType::object}, + {"py.c", OutputFileType::python_extension}, + }; + // extensions won't vary across multitarget output + const Target t = args.targets.empty() ? Target() : args.targets[0]; + const std::map output_info = get_output_info(t); + for (const auto &it : output_info) { + output_name_to_enum[it.second.name] = it.first; + } - if (emit_flags.empty() || (emit_flags.size() == 1 && emit_flags[0].empty())) { - // If omitted or empty, assume .a and .h and registration.cpp - output_types.insert(OutputFileType::c_header); - output_types.insert(OutputFileType::registration); - output_types.insert(OutputFileType::static_library); - } else { - // Build a reverse lookup table. Allow some legacy aliases on the command line, - // to allow legacy build systems to work more easily. - std::map output_name_to_enum = { - {"cpp", OutputFileType::c_source}, - {"h", OutputFileType::c_header}, - {"hlpipe", OutputFileType::hlpipe}, - {"html", OutputFileType::stmt_html}, - {"o", OutputFileType::object}, - {"py.c", OutputFileType::python_extension}, - }; - // extensions won't vary across multitarget output - const Target t = args.targets.empty() ? Target() : args.targets[0]; - const std::map output_info = get_output_info(t); - for (const auto &it : output_info) { - output_name_to_enum[it.second.name] = it.first; - } - - for (const std::string &opt : emit_flags) { - auto it = output_name_to_enum.find(opt); - if (it == output_name_to_enum.end()) { - std::ostringstream o; - o << "Unrecognized emit option: " << opt << " is not one of ["; - auto end = output_info.cend(); - auto last = std::prev(end); - for (auto iter = output_info.cbegin(); iter != end; ++iter) { - o << iter->second.name; - if (iter != last) { - o << " "; - } + for (const std::string &opt : emit_flags) { + auto it = output_name_to_enum.find(opt); + if (it == output_name_to_enum.end()) { + std::ostringstream o; + o << "Unrecognized emit option: " << opt << " is not one of ["; + auto end = output_info.cend(); + auto last = std::prev(end); + for (auto iter = output_info.cbegin(); iter != end; ++iter) { + o << iter->second.name; + if (iter != last) { + o << " "; } - o << "], ignoring.\n"; - o << kUsage; - user_error << o.str(); } - output_types.insert(it->second); + o << "], ignoring.\n"; + o << kUsage; + user_error << o.str(); } + output_types.insert(it->second); } + return output_types; }; diff --git a/src/StmtToViz.cpp b/src/StmtToViz.cpp index 32eedebfb2e2..ee3b18622765 100644 --- a/src/StmtToViz.cpp +++ b/src/StmtToViz.cpp @@ -22,7 +22,7 @@ // causes you to be able to just edit the files without having to recompile Halide // and then rerun your generator. // For distribution purposes, they should be inlined, and this define should be on 1. -#define INLINE_TEMPLATES 0 // nocheckin +#define INLINE_TEMPLATES 1 // nocheckin #if !INLINE_TEMPLATES #include @@ -3180,17 +3180,17 @@ class IRVisualizer { // Generate a resizing bar to control the width of code and visualization panes void generate_resize_bar(int num) { stream << "
\n"; - stream << "
\n"; - stream << "
\n"; - stream << " \n"; - stream << "
\n"; - stream << "
\n"; - stream << " \n"; - stream << "
\n"; - stream << "
\n"; + stream << "
\n"; + stream << "
\n"; + stream << " \n"; + stream << "
\n"; + stream << "
\n"; + stream << " \n"; + stream << "
\n"; stream << "
\n"; + stream << "
\n"; } /* Misc helper methods */ From 95230a1c94beea5de7688ac64c50706b246d50b7 Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Fri, 15 Sep 2023 22:47:21 +0200 Subject: [PATCH 12/22] Nuked VizTree --- src/CMakeLists.txt | 3 - src/Generator.cpp | 2 - src/Module.cpp | 12 +- src/StmtToViz.cpp | 717 +----------------- src/StmtToViz.h | 6 +- src/irvisualizer/html_template_StmtToViz.css | 657 ---------------- src/irvisualizer/html_template_StmtToViz.js | 272 ------- .../html_template_StmtToViz_dependencies.html | 4 - 8 files changed, 25 insertions(+), 1648 deletions(-) delete mode 100644 src/irvisualizer/html_template_StmtToViz.css delete mode 100644 src/irvisualizer/html_template_StmtToViz.js delete mode 100644 src/irvisualizer/html_template_StmtToViz_dependencies.html diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eb9e56a7930c..08181948e6aa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -365,9 +365,6 @@ set(HTML_TEMPLATE_FILES StmtToHTML_dependencies.html StmtToHTML.js StmtToHTML.css - StmtToViz_dependencies.html - StmtToViz.js - StmtToViz.css ) ## diff --git a/src/Generator.cpp b/src/Generator.cpp index 46e6770002f6..0075bc1d4be6 100644 --- a/src/Generator.cpp +++ b/src/Generator.cpp @@ -655,8 +655,6 @@ gengen schedule, static_library, stmt, stmt_html, conceptual_stmt, conceptual_stmt_html, compiler_log, hlpipe, device_code]. If omitted, default value is [c_header, static_library, registration]. - For the HTML-options optionally setting HL_HTML_VIZTREE=1 will enable the - old VizIR Tree pane in the generated HTML. -p A comma-separated list of shared libraries that will be loaded before the generator is run. Useful for custom auto-schedulers. The generator must diff --git a/src/Module.cpp b/src/Module.cpp index 46c234cde95b..bf326417180b 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -671,19 +671,15 @@ void Module::compile(const std::map &output_files) } if (contains(output_files, OutputFileType::stmt_html)) { internal_assert(!assembly_path.empty()); - bool enable_viztree = get_env_variable("HL_HTML_VIZTREE") == "1"; - debug(1) << "Module.compile(): stmt_html " << output_files.at(OutputFileType::stmt_html) - << " (viztree_enabled: " << enable_viztree << ")\n"; + debug(1) << "Module.compile(): stmt_html " << output_files.at(OutputFileType::stmt_html) << "\n"; Internal::print_to_stmt_html(output_files.at(OutputFileType::stmt_html), - *this, assembly_path, enable_viztree); + *this, assembly_path); } if (contains(output_files, OutputFileType::conceptual_stmt_html)) { internal_assert(!assembly_path.empty()); - bool enable_viztree = get_env_variable("HL_HTML_VIZTREE") == "1"; - debug(1) << "Module.compile(): conceptual_stmt_html " << output_files.at(OutputFileType::conceptual_stmt_html) - << " (viztree_enabled: " << enable_viztree << ")\n"; + debug(1) << "Module.compile(): conceptual_stmt_html " << output_files.at(OutputFileType::conceptual_stmt_html) << "\n"; Internal::print_to_conceptual_stmt_html(output_files.at(OutputFileType::conceptual_stmt_html), - *this, assembly_path, enable_viztree); + *this, assembly_path); } if (contains(output_files, OutputFileType::device_code)) { debug(1) << "Module.compile(): device_code " << output_files.at(OutputFileType::device_code) << "\n"; diff --git a/src/StmtToViz.cpp b/src/StmtToViz.cpp index ee3b18622765..8c4856a0a8a0 100644 --- a/src/StmtToViz.cpp +++ b/src/StmtToViz.cpp @@ -31,23 +31,16 @@ namespace Halide { namespace Internal { -// Simple HTML specific extern "C" unsigned char halide_html_template_StmtToHTML_dependencies_html[]; extern "C" unsigned char halide_html_template_StmtToHTML_css[]; extern "C" unsigned char halide_html_template_StmtToHTML_js[]; -// Viz Tree specific -extern "C" unsigned char halide_html_template_StmtToViz_dependencies_html[]; -extern "C" unsigned char halide_html_template_StmtToViz_css[]; -extern "C" unsigned char halide_html_template_StmtToViz_js[]; - // Classes defined within this file class CostModel; class AssemblyInfo; template class HTMLCodePrinter; -class HTMLVisualizationPrinter; -class IRVisualizer; +class PipelineHTMLInspector; /** IRCostModel * A basic cost model for Halide IR. Estimates computation @@ -677,9 +670,8 @@ class AssemblyInfo : public IRVisitor { template class HTMLCodePrinter : public IRVisitor { public: - HTMLCodePrinter(T &os, std::map &nids, bool enable_viztree_features, bool enable_assembly_features) + HTMLCodePrinter(T &os, std::map &nids, bool enable_assembly_features) : stream(os), node_ids(nids), context_stack(1, 0), - enable_viztree_features(enable_viztree_features), enable_assembly_features(enable_assembly_features) { } @@ -989,7 +981,6 @@ class HTMLCodePrinter : public IRVisitor { IRCostModel cost_model; AssemblyInfo host_assembly_info; AssemblyInfo device_assembly_info; - bool enable_viztree_features; bool enable_assembly_features; /* Private print functions to handle various IR types */ @@ -1068,9 +1059,6 @@ class HTMLCodePrinter : public IRVisitor { print_fndecl_args(fn.args); print_html_element("span", "matched", ")"); - // Add a button to jump to this function in the viz - print_visualization_button("lowered-func-viz-" + std::to_string(id)); - // Open code block to hold function body print_opening_brace(); print_show_hide_btn_end(); @@ -1199,15 +1187,6 @@ class HTMLCodePrinter : public IRVisitor { stream << x; } - // Prints a button to sync text with visualization - void print_visualization_button(std::string id) { - if (enable_viztree_features) { - stream << ""; - } - } - // Prints a button to sync text with visualization void print_assembly_button(const void *op) { if (!enable_assembly_features) { @@ -1414,9 +1393,9 @@ class HTMLCodePrinter : public IRVisitor { } stream << "
"; + << "line-" << line_cost_class << " block-" << block_cost_class << "' " + << "line-cost='" << line_cost << "' block-cost='" << block_cost << "' " + << "line-cost-color='" << line_costc << "' block-cost-color='" << block_costc << "'>"; stream << "" << prefix << line_cost; @@ -1672,8 +1651,6 @@ class HTMLCodePrinter : public IRVisitor { print_variable(op->name); print_closing_tag("span"); - // Add a button to jump to this producer/consumer in the viz - print_visualization_button("prodcons-viz-" + std::to_string(id)); print_assembly_button(op); // Open code block to hold function body @@ -1753,8 +1730,6 @@ class HTMLCodePrinter : public IRVisitor { print(op->extent); print_html_element("span", "matched", ")"); - // Add a button to jump to this loop in the viz - print_visualization_button("loop-viz-" + std::to_string(id)); print_assembly_button(op); // Open code block to hold function body @@ -1802,9 +1777,6 @@ class HTMLCodePrinter : public IRVisitor { print(op->count); print_html_element("span", "matched", ")"); - // Add a button to jump to this acquire in the viz - print_visualization_button("acquire-viz-" + std::to_string(id)); - // Open code block to hold function body print_opening_brace(); print_show_hide_btn_end(); @@ -1938,9 +1910,6 @@ class HTMLCodePrinter : public IRVisitor { print_html_element("span", "matched", "}"); } - // Add a button to jump to this allocation in the viz - print_visualization_button("allocate-viz-" + std::to_string(id)); - // Print allocation body print_ln(); print_opening_tag("div", "AllocateBody"); @@ -2001,9 +1970,6 @@ class HTMLCodePrinter : public IRVisitor { print(op->condition); } - // Add a button to jump to this realize in the viz - print_visualization_button("realize-viz-" + std::to_string(id)); - // Open code block to hold function body print_opening_brace(); print_show_hide_btn_end(); @@ -2093,9 +2059,6 @@ class HTMLCodePrinter : public IRVisitor { print(op->condition); print_html_element("span", "matched", ")"); - // Add a button to jump to this conditional in the viz - print_visualization_button("cond-viz-" + std::to_string(then_node_id)); - // Flatten nested if's in the else case as an // `if-then-else_if-else` sequence while (true) { @@ -2147,9 +2110,6 @@ class HTMLCodePrinter : public IRVisitor { print(nested_if->condition); print_html_element("span", "matched", ")"); - // Add a button to jump to this conditional branch in the viz - print_visualization_button("cond-viz-" + std::to_string(then_node_id)); - // Update op to the nested if for next loop iteration op = nested_if; last_then_block_id = then_block_id; @@ -2173,9 +2133,6 @@ class HTMLCodePrinter : public IRVisitor { print_html_element("span", "keyword IfSpan", " else", "cond-" + std::to_string(else_node_id)); print_closing_tag("span"); - // Add a button to jump to this conditional branch in the viz - print_visualization_button("cond-viz-" + std::to_string(else_node_id)); - // Open code block to hold `else` case print_opening_brace(); print_show_hide_btn_end(); @@ -2348,620 +2305,20 @@ class HTMLCodePrinter : public IRVisitor { } }; -/** HTMLVisualizationPrinter - * Visualizes the IR in HTML. The visualization is essentially - * an abstracted version of the code, highlighting the higher - * level execution pipeline along with key properties of the - * computation performed at each stage. - */ -class HTMLVisualizationPrinter : public IRVisitor { -public: - HTMLVisualizationPrinter(std::ofstream &os, std::map &nids) - : stream(os), node_ids(nids) { - } - - // Make class non-copyable and non-moveable - HTMLVisualizationPrinter(const HTMLVisualizationPrinter &) = delete; - HTMLVisualizationPrinter &operator=(const HTMLVisualizationPrinter &) = delete; - - void init_cost_info(IRCostModel cm) { - cost_model = std::move(cm); - } - - void print(const Module &m, AssemblyInfo host_asm_info, AssemblyInfo device_asm_info) { - host_assembly_info = std::move(host_asm_info); - device_assembly_info = std::move(device_asm_info); - for (const auto &fn : m.functions()) { - print(fn); - } - } - -private: - // Handle to output file stream - std::ofstream &stream; - - // Used to track the context within generated HTML - std::vector context_stack_tags; - - // Assembly line number info - AssemblyInfo host_assembly_info; - AssemblyInfo device_assembly_info; - - // Holds cost information for visualized program - IRCostModel cost_model; - - // Generate unique ids - int id = 0; - std::map &node_ids; - - int gen_unique_id() { - return id++; - } - - int gen_node_id(const IRNode *node) { - if (node_ids.count(node) == 0) { - node_ids[node] = gen_unique_id(); - } - return node_ids[node]; - } - - /* Private print functions to handle various IR types */ - void print(const LoweredFunc &fn) { - int id = gen_unique_id(); - - // Start a div to hold the function viz - print_opening_tag("div", "center fn-wrapper"); - - // Create the header bar - print_opening_tag("div", "fn-header"); - print_collapse_expand_btn(id); - print_code_button("lowered-func-" + fn.name); - print_html_element("span", "fn-title", "Func: " + fn.name, "lowered-func-viz-" + fn.name); - print_closing_tag("div"); - - // Print function body - print_opening_tag("div", "fn-body", "viz-" + std::to_string(id)); - fn.body.accept(this); - print_closing_tag("div"); - - // Close function div - print_closing_tag("div"); - } - - /* Methods used to emit common HTML patterns */ - - // Prints the opening tag for the specified html element. - void print_opening_tag(const std::string &tag, const std::string &cls) { - stream << "<" << tag << " class='" << cls << "'>"; - context_stack_tags.push_back(tag); - } - - void print_opening_tag(const std::string &tag, const std::string &cls, const std::string &id) { - stream << "<" << tag << " class='" << cls << "' id='" << id << "'>"; - context_stack_tags.push_back(tag); - } - - // Prints the closing tag for the specified html element. - void print_closing_tag(const std::string &tag) { - internal_assert(tag == context_stack_tags.back()); - context_stack_tags.pop_back(); - stream << ""; - } - - // Prints an html element: opening tag, body and closing tag - void print_html_element(const std::string &tag, const std::string &cls, const std::string &body) { - print_opening_tag(tag, cls); - stream << body; - print_closing_tag(tag); - } - - void print_html_element(const std::string &tag, const std::string &cls, const std::string &body, const std::string &id) { - print_opening_tag(tag, cls, id); - stream << body; - print_closing_tag(tag); - } - - // Prints text to stream - void print_text(const std::string &x) { - stream << x; - } - - // Prints a button to sync visualization with code - void print_code_button(const std::string &id) { - stream << ""; - } - - // Prints a button to sync visualization with assembly - void print_asm_button(const std::string &id) { - stream << ""; - } - - // Prints a function-call box - void print_fn_button(const std::string &name, int id) { - print_opening_tag("div", "fn-call"); - print_code_button("fn-call-" + std::to_string(id)); - print_text(get_as_var(name) + "(...)"); - print_closing_tag("div"); - } - - // Prints a button to collapse or expand a visualization box - void print_collapse_expand_btn(int id) { - stream << "" - << ""; - } - - // Prints the box title within the div.box-header - void print_box_title(const std::string &title, const std::string &anchor) { - print_opening_tag("div", "box-title"); - print_html_element("span", "", title, anchor); - print_closing_tag("div"); - } - - // Prints the cost indicator buttons within div.box-header - void print_cost_buttons(int id, const IRNode *op) { - print_opening_tag("div", "viz-cost-btns"); - - // Print compute cost indicator - int max_line_ccost = cost_model.get_max_compute_cost(false); - int line_ccost = cost_model.get_compute_cost(op, false); - int block_ccost = cost_model.get_compute_cost(op, true); - print_cost_button(line_ccost, block_ccost, max_line_ccost, "vcc-" + std::to_string(id), "Op Count: "); - - // Print data movement cost indicator - int max_line_dcost = cost_model.get_max_data_movement_cost(false); - int line_dcost = cost_model.get_data_movement_cost(op, false); - int block_dcost = cost_model.get_data_movement_cost(op, true); - // Special handling for Store nodes; since unlike the code view - // the viz view prints stores and loads seperately, therefore using - // inclusive cost is confusing. - if (op->node_type == IRNodeType::Store) { - const Store *st = static_cast(op); - line_dcost = st->value.type().bits() * st->value.type().lanes(); - block_dcost = line_dcost; - } - print_cost_button(line_dcost, block_dcost, max_line_dcost, "vdc-" + std::to_string(id), "Bits Moved: "); - - print_closing_tag("div"); - } - - void print_cost_button(int line_cost, int block_cost, int max_line_cost, const std::string &id, const std::string &prefix) { - const int num_cost_buckets = 20; - - int line_cost_bin_size = (max_line_cost / num_cost_buckets) + 1; - int block_cost_bin_size = (max_line_cost / num_cost_buckets) + 1; - - int line_costc = line_cost / line_cost_bin_size; - int block_costc = block_cost / block_cost_bin_size; - - if (line_costc >= num_cost_buckets) { - line_costc = num_cost_buckets - 1; - } - if (block_costc >= num_cost_buckets) { - block_costc = num_cost_buckets - 1; - } - - stream << "
"; - - stream << "" - << prefix << line_cost - << ""; - - stream << "
"; - } - - // Prints the box .box-header within div.box - void print_box_header(int id, const IRNode *op, const std::string &anchor, const std::string &code_anchor, const std::string &title) { - print_opening_tag("div", "box-header"); - print_collapse_expand_btn(id); - print_code_button(code_anchor); - print_box_title(title, anchor); - print_cost_buttons(id, op); - print_closing_tag("div"); - } - - // Prints the box .box-header within div.box, contains the asm info button - void print_box_header_asm(int id, const IRNode *op, const std::string &anchor, const std::string &code_anchor, const std::string &asm_anchor, const std::string &title) { - print_opening_tag("div", "box-header"); - print_collapse_expand_btn(id); - print_code_button(code_anchor); - print_asm_button(asm_anchor); - print_box_title(title, anchor); - print_cost_buttons(id, op); - print_closing_tag("div"); - } - - // Converts an expr to a string without printing to stream - std::string get_as_str(const Expr &e) { - return get_as_str(e, ""); - } - - std::string get_as_str(const Expr &e, const std::string &prefix) { - if (prefix == "Else") { - return "Else"; - } - - // TODO: this code copies the node_ids over every time... - std::ostringstream ss; - HTMLCodePrinter printer(ss, node_ids, true, true); - e.accept(&printer); - std::string html_e = ss.str(); - - if (large_expr(e)) { - return prefix + truncate_html(html_e); - } else { - return prefix + html_e; - } - } - - // Return variable name wrapped with html that enables matching - std::string get_as_var(const std::string &name) { - return "" + name + ""; - } - - // Sometimes the expressions are too large to show within the viz. In - // such cases we use tooltips. - bool large_expr(const Expr &e) { - std::ostringstream ss; - ss << e; - return ss.str().size() > 50; - } - - std::string truncate_html(const std::string &cond) { - int id = gen_unique_id(); - - std::ostringstream ss; - - // Show condition expression button - ss << ""; - - return ss.str(); - } - - // Prints a single node in an `if-elseif-...-else` chain - void print_if_tree_node(const Stmt &node, const Expr &cond, const std::string &prefix) { - // Assign unique id to this node - int box_id = gen_unique_id(); - int node_id = gen_node_id(node.get()); - - // Start tree node - print_opening_tag("li", ""); - print_opening_tag("span", "tf-nc if-node"); - - // Start a box to hold viz - print_opening_tag("div", "box center IfBox"); - - // Create viz content - std::string aid = std::to_string(node_id); - print_box_header(box_id, node.get(), "cond-viz-" + aid, "cond-" + aid, get_as_str(cond, prefix)); - - // Print contents of node - print_opening_tag("div", "box-body", "viz-" + std::to_string(box_id)); - node.accept(this); - print_closing_tag("div"); - - // Close box holding viz - print_closing_tag("div"); - - // Close tree node - print_closing_tag("span"); - print_closing_tag("li"); - } - - /* Visitor functions for each IR node */ - using IRVisitor::visit; - - /* Override key visit functions */ - - void visit(const Allocate *op) override { - // Assign unique id to this node - int id = gen_node_id(op); - - // Start a box to hold viz - print_opening_tag("div", "box center AllocateBox"); - - // Print box header - std::string aid = std::to_string(id); - print_box_header(id, op, "allocate-viz-" + aid, "allocate-" + aid, "Allocate: " + op->name); - - // Start a box to hold viz - print_opening_tag("div", "box-body", "viz-" + std::to_string(id)); - - // Generate a table with allocation details - print_opening_tag("table", "allocate-table"); - - // - Memory type - stream << "Memory Type" << op->memory_type << ""; - - // - Allocation condition - if (!is_const_one(op->condition)) { - stream << "Condition" << op->condition << ""; - } - - // - Data type - stream << "Data Type" << op->type << ""; - - // - Dimensions - for (size_t i = 0; i < op->extents.size(); i++) { - stream << "Dim-" << i << "" << get_as_str(op->extents[i]) << ""; - } - - print_closing_tag("table"); - - op->body.accept(this); - - print_closing_tag("div"); - - print_closing_tag("div"); - } - - void visit(const For *op) override { - // Assign unique id to this node - int id = gen_node_id(op); - - // Start a box to hold viz - print_opening_tag("div", "box center ForBox"); - - // Print box header - std::string aid = std::to_string(id); - int asm_lno = host_assembly_info.get_asm_lno((uint64_t)op); - if (asm_lno == -1) { - print_box_header(id, op, "loop-viz-" + aid, "loop-" + aid, "For: " + get_as_var(op->name)); - } else { - print_box_header_asm(id, op, "loop-viz-" + aid, "loop-" + aid, std::to_string(asm_lno), "For: " + get_as_var(op->name)); - } - - // Start a box to hold viz - print_opening_tag("div", "box-body", "viz-" + std::to_string(id)); - - // Generate a table with loop details - print_opening_tag("table", "allocate-table"); - - // - Loop type - if (op->for_type != ForType::Serial) { - stream << "Loop Type" << op->for_type << ""; - } - // - Device API - if (op->device_api != DeviceAPI::None) { - stream << "Device API" << op->device_api << ""; - } - // - Min - stream << "Min" << get_as_str(op->min) << ""; - // - Extent - stream << "Extent" << get_as_str(op->extent) << ""; - - print_closing_tag("table"); - - op->body.accept(this); - - print_closing_tag("div"); - - print_closing_tag("div"); - } - - void visit(const IfThenElse *op) override { - // Open If tree - print_opening_tag("div", "tf-tree tf-gap-sm tf-custom-ir-viz"); - - // Create root 'cond' node - if (op->else_case.defined()) { - print_opening_tag("ul", ""); - print_opening_tag("li", ""); - print_html_element("span", "tf-nc if-node if-root-node", "Control Flow Branching"); - } - - // Create children nodes ('then', 'else if' and 'else' cases) - print_opening_tag("ul", ""); - - // `then` case - print_if_tree_node(op->then_case, op->condition, "If: "); - - // `else if` cases - const IfThenElse *nested_if = op; - while (nested_if->else_case.defined() && (nested_if->else_case.as())) { - nested_if = nested_if->else_case.as(); - print_if_tree_node(nested_if->then_case, nested_if->condition, "Else If: "); - } - - // `else` case - if (nested_if->else_case.defined()) { - print_if_tree_node(nested_if->else_case, UIntImm::make(UInt(1), 1), "Else"); - } - - print_closing_tag("ul"); - - // Close If tree - if (op->else_case.defined()) { - print_closing_tag("li"); - print_closing_tag("ul"); - } - print_closing_tag("div"); - } - - void visit(const ProducerConsumer *op) override { - // Assign unique id to this node - int id = gen_node_id(op); - - // Start a box to hold viz - std::string box_name = op->is_producer ? "ProducerBox" : "ConsumerBox"; - print_opening_tag("div", "box center " + box_name); - - // Print box header - std::string aid = std::to_string(id); - std::string prefix = op->is_producer ? "Produce: " : "Consume: "; - int asm_lno = host_assembly_info.get_asm_lno((uint64_t)op); - if (asm_lno == -1) { - print_box_header(id, op, "prodcons-viz-" + aid, "prodcons-" + aid, prefix + get_as_var(op->name)); - } else { - print_box_header_asm(id, op, "prodcons-viz-" + aid, "prodcons-" + aid, std::to_string(asm_lno), prefix + get_as_var(op->name)); - } - - // Print the body - print_opening_tag("div", "box-body", "viz-" + std::to_string(id)); - op->body.accept(this); - print_closing_tag("div"); - - // Close div holding the producer/consumer - print_closing_tag("div"); - } - - void visit(const Store *op) override { - // Visit the value first. We want to show any loads - // that happen before the store operation - op->value.accept(this); - - // Assign unique id to this node - int id = gen_node_id(op); - - // Start a box to hold viz - print_opening_tag("div", "box center StoreBox"); - - // Print box header - std::string aid = std::to_string(id); - print_box_header(id, op, "store-viz-" + aid, "store-" + aid, "Store: " + get_as_var(op->name)); - - // Start a box to hold viz - print_opening_tag("div", "box-body", "viz-" + std::to_string(id)); - - // Generate a table with store details - print_opening_tag("table", "allocate-table"); - - // - Store predicate - if (!is_const_one(op->predicate)) { - stream << "Predicate" << get_as_str(op->predicate) << ""; - } - - // - Alignment - const bool show_alignment = op->value.type().is_vector() && op->alignment.modulus > 1; - if (show_alignment) { - stream << "Alignment" - << "aligned(" << op->alignment.modulus << ", " << op->alignment.remainder << ")" - << ""; - } - - // - Qualifiers - if (op->value.type().is_vector()) { - const Ramp *idx = op->index.as(); - if (idx && is_const_one(idx->stride)) { - stream << "TypeDense Vector"; - } else { - stream << "TypeStrided Vector"; - } - stream << "Output Tile" << op->value.type() << ""; - } else { - stream << "TypeScalar"; - stream << "Output" << op->value.type() << ""; - } - - print_closing_tag("table"); - - print_closing_tag("div"); - - print_closing_tag("div"); - } - - void visit(const Load *op) override { - // Assign unique id to this node - int id = gen_node_id(op); - - // Start a box to hold viz - print_opening_tag("div", "box center LoadBox"); - - // Print box header - std::string aid = std::to_string(id); - print_box_header(id, op, "load-viz-" + aid, "load-" + aid, "Load: " + get_as_var(op->name)); - - // Start a box to hold viz - print_opening_tag("div", "box-body", "viz-" + std::to_string(id)); - - // Generate a table with load details - print_opening_tag("table", "allocate-table"); - - // - Load predicate - if (!is_const_one(op->predicate)) { - stream << "Predicate" << get_as_str(op->predicate) << ""; - } - - // - Alignment - const bool show_alignment = op->type.is_vector() && op->alignment.modulus > 1; - if (show_alignment) { - stream << "Alignment" - << "aligned(" << op->alignment.modulus << ", " << op->alignment.remainder << ")" - << ""; - } - - // - Qualifiers - if (op->type.is_vector()) { - const Ramp *idx = op->index.as(); - if (idx && is_const_one(idx->stride)) { - stream << "TypeDense Vector"; - } else { - stream << "TypeStrided Vector"; - } - stream << "Output Tile" << op->type << ""; - } else { - stream << "TypeScalar"; - stream << "Output" << op->type << ""; - } - - print_closing_tag("table"); - - print_closing_tag("div"); - - print_closing_tag("div"); - } - - void visit(const Call *op) override { - int id = gen_node_id(op); - // Add viz support for key functions/intrinsics - if (op->name == "halide_do_par_for") { - print_fn_button(op->name, id); - } else if (op->name == "halide_do_par_task") { - print_fn_button(op->name, id); - } else if (op->name == "_halide_buffer_init") { - print_fn_button(op->name, id); - } else if (op->name.rfind("_halide", 0) != 0) { - // Assumption: We want to ignore intrinsics starting with _halide - // but for everything else, generate a warning - debug(2) << "Function call ignored by IRVisualizer: " << op->name << "\n"; - } - } -}; - -/** IRVisualizer Class +/** PipelineHTMLInspector Class * Generates the output html page. Currently the html page has * three key tabs: IR code, Visualized pipeline and the generated * assembly. */ -class IRVisualizer { +class PipelineHTMLInspector { public: // Construct the visualizer and point it to the output file - explicit IRVisualizer(const std::string &html_output_filename, + explicit PipelineHTMLInspector(const std::string &html_output_filename, const Module &m, const std::string &assembly_input_filename, - bool use_conceptual_stmt_ir, - bool include_viztree) + bool use_conceptual_stmt_ir) : use_conceptual_stmt_ir(use_conceptual_stmt_ir), - html_code_printer(stream, node_ids, include_viztree, true), - include_viztree(include_viztree), - html_viz_printer(stream, node_ids) { + html_code_printer(stream, node_ids, true) { // Open output file stream.open(html_output_filename.c_str()); @@ -3017,9 +2374,6 @@ class IRVisualizer { } cost_model.finalize_cost_computation(); html_code_printer.init_cost_info(cost_model); - if (include_viztree) { - html_viz_printer.init_cost_info(cost_model); - } // Generate html page stream << "\n"; @@ -3033,9 +2387,6 @@ class IRVisualizer { // Handle to output file stream std::ofstream stream; - // Handle to assembly file stream - std::ifstream assembly; - // Holds cost information for visualized program IRCostModel cost_model; @@ -3046,10 +2397,6 @@ class IRVisualizer { bool use_conceptual_stmt_ir; HTMLCodePrinter html_code_printer; - // Used to translate IR to visualization in HTML - bool include_viztree; - HTMLVisualizationPrinter html_viz_printer; - /* Methods for generating the section of the html file */ void generate_head(const Module &m) { stream << "\n"; @@ -3059,12 +2406,6 @@ class IRVisualizer { stream << "\n"; - if (include_viztree) { - stream << halide_html_template_StmtToViz_dependencies_html; - stream << "\n"; - } #else std::filesystem::path dir = std::filesystem::path(__FILE__).parent_path() / "irvisualizer"; debug(1) << "Will link CSS in directory: " << dir << "\n"; @@ -3089,19 +2430,11 @@ class IRVisualizer { stream << ""; - if (include_viztree) { - stream << ""; - } #else std::filesystem::path dir = std::filesystem::path(__FILE__).parent_path() / "irvisualizer"; debug(1) << "Will link Javascript in directory: " << dir << "\n"; internal_assert(std::filesystem::exists(dir)); stream << "\n"; - if (include_viztree) { - stream << "\n"; - } #endif } @@ -3111,10 +2444,6 @@ class IRVisualizer { stream << "
\n"; stream << "
\n"; generate_ir_pane(m); - if (include_viztree) { - generate_resize_bar(pane_count++); - generate_visualization_pane(m); - } generate_resize_bar(pane_count++); generate_host_assembly_pane(m); const Buffer<> *device_assembly = m.get_device_code_buffer(); @@ -3139,13 +2468,6 @@ class IRVisualizer { } } - // Generate pane: Lowered IR code with syntax highlighting in HTML - void generate_visualization_pane(const Module &m) { - stream << "
\n"; - html_viz_printer.print(m, host_asm_info, device_asm_info); - stream << "
\n"; - } - // Generate pane: Generated host assembly code void generate_host_assembly_pane(const Module &m) { stream << "
\n"; @@ -3204,6 +2526,7 @@ class IRVisualizer { user_assert(file_exists(asm_file)) << "Unable to open assembly file: " << asm_file << "\n"; // Open assembly file + std::ifstream assembly; assembly.open(asm_file.c_str()); // Slurp the code into asm_stream @@ -3217,20 +2540,18 @@ class IRVisualizer { // The external interface to this module void print_to_stmt_html(const std::string &html_output_filename, const Module &m, - const std::string &assembly_input_filename, - bool include_viz) { - IRVisualizer visualizer(html_output_filename, m, assembly_input_filename, false, include_viz); - visualizer.generate_html(m); - debug(1) << "Done generating HTML IR Visualization - printed to: " << html_output_filename << "\n"; + const std::string &assembly_input_filename) { + PipelineHTMLInspector inspector(html_output_filename, m, assembly_input_filename, false); + inspector.generate_html(m); + debug(1) << "Done generating HTML IR Inspector - printed to: " << html_output_filename << "\n"; } void print_to_conceptual_stmt_html(const std::string &html_output_filename, const Module &m, - const std::string &assembly_input_filename, - bool include_viz) { - IRVisualizer visualizer(html_output_filename, m, assembly_input_filename, true, include_viz); - visualizer.generate_html(m); - debug(1) << "Done generating HTML Conceptual IR Visualization - printed to: " << html_output_filename << "\n"; + const std::string &assembly_input_filename) { + PipelineHTMLInspector inspector(html_output_filename, m, assembly_input_filename, true); + inspector.generate_html(m); + debug(1) << "Done generating HTML Conceptual IR Inspector - printed to: " << html_output_filename << "\n"; } } // namespace Internal diff --git a/src/StmtToViz.h b/src/StmtToViz.h index 3e2cbd8833b9..657a1e5d3cb8 100644 --- a/src/StmtToViz.h +++ b/src/StmtToViz.h @@ -22,8 +22,7 @@ struct Stmt; * and will assert-fail if no such file is found. */ void print_to_stmt_html(const std::string &html_output_filename, const Module &m, - const std::string &assembly_input_filename = "", - bool include_viz = false); + const std::string &assembly_input_filename = ""); /** Dump an HTML-formatted visualization of a Module's conceptual Stmt code to filename. * If assembly_input_filename is not empty, it is expected to be the path @@ -32,8 +31,7 @@ void print_to_stmt_html(const std::string &html_output_filename, * and will assert-fail if no such file is found. */ void print_to_conceptual_stmt_html(const std::string &html_output_filename, const Module &m, - const std::string &assembly_input_filename = "", - bool include_viz = false); + const std::string &assembly_input_filename = ""); } // namespace Internal } // namespace Halide diff --git a/src/irvisualizer/html_template_StmtToViz.css b/src/irvisualizer/html_template_StmtToViz.css deleted file mode 100644 index 45b2b1dfa392..000000000000 --- a/src/irvisualizer/html_template_StmtToViz.css +++ /dev/null @@ -1,657 +0,0 @@ - diff --git a/src/irvisualizer/html_template_StmtToViz.js b/src/irvisualizer/html_template_StmtToViz.js deleted file mode 100644 index adc88ddf326a..000000000000 --- a/src/irvisualizer/html_template_StmtToViz.js +++ /dev/null @@ -1,272 +0,0 @@ -/* Highlighting 'matched' elements in Viz code */ -$('#ir-visualization-tab .matched').each(function () { - this.onmouseover = function () { - $('#ir-visualization-tab .matched[id^=' + this.id.split('-')[0] + '-]').addClass('Highlight'); - } - this.onmouseout = function () { - $('#ir-visualization-tab .matched[id^=' + this.id.split('-')[0] + '-]').removeClass('Highlight'); - } -}); - -/* Cross highlighting 'matched' variables (only) */ -$('#ir-visualization-tab .matched.variable').each(function () { - this.onmouseover = function () { - var name = this.outerText; - $('.matched.variable').filter((idx, val) => { - return val.outerText === name; - }).addClass('Highlight'); - } - this.onmouseout = function () { - var name = this.outerText; - $('.matched.variable').filter((idx, val) => { - return val.outerText === name; - }).removeClass('Highlight'); - } -}); - -/* Expand/Collapse buttons in Viz */ -function toggleVizByElem(body) { - var id = body.id; - var group = body.parentElement; - var header = group.firstElementChild; - const safe_but_slow_code = false; - if (safe_but_slow_code) { - var buttonShow = header.querySelector('#' + id + '-show'); - var buttonHide = header.querySelector('#' + id + '-hide'); - var re = /(?:\-([^-]+))?$/; - var viz_id = re.exec(id)[1]; - var ccost_btn = header.querySelector("#vcc-" + viz_id); - var dcost_btn = header.querySelector("#vdc-" + viz_id); - var ccost_tt = header.querySelector("#tooltip-vcc-" + viz_id); - var dcost_tt = header.querySelector("#tooltip-vdc-" + viz_id); - } else { - var buttonHide = header.firstElementChild; // #id-hide - var buttonShow = header.firstElementChild.nextElementSibling; // #id-show - var cost_div = header.lastElementChild; // #box-header > .viz-cost-btns - var ccost_btn = cost_div.firstElementChild; // # vcc-id - var dcost_btn = cost_div.lastElementChild; // # vdc-id - var ccost_tt = ccost_btn.firstElementChild; // #tooltip-vcc-id - var dcost_tt = dcost_btn.firstElementChild; // #tooltip-vdc-id - } - if (body.classList.contains("collapsed-viz")) { - body.classList.remove("collapsed-viz"); - buttonShow.style.display = 'none'; - buttonHide.style.display = 'block'; - if (ccost_btn && dcost_tt) { - // Update cost indicators - ccost_color = ccost_btn.getAttribute('line-cost-color'); - dcost_color = dcost_btn.getAttribute('line-cost-color'); - ccost_btn.className = ccost_btn.className.replace(/CostColor\d+/, 'CostColor' + ccost_color); - dcost_btn.className = dcost_btn.className.replace(/CostColor\d+/, 'CostColor' + dcost_color); - // Update cost tooltips - ccost = ccost_btn.getAttribute('line-cost'); - dcost = dcost_btn.getAttribute('line-cost'); - ccost_tt.innerText = 'Op Count: ' + ccost; - dcost_tt.innerText = 'Bits Moved: ' + dcost; - } - } else { - body.classList.add("collapsed-viz"); - buttonShow.style.display = 'block'; - buttonHide.style.display = 'none'; - if (ccost_btn && dcost_tt) { - // Update cost indicators - collapsed_ccost_color = ccost_btn.getAttribute('block-cost-color'); - collapsed_dcost_color = dcost_btn.getAttribute('block-cost-color'); - ccost_btn.className = ccost_btn.className.replace(/CostColor\d+/, 'CostColor' + collapsed_ccost_color); - dcost_btn.className = dcost_btn.className.replace(/CostColor\d+/, 'CostColor' + collapsed_dcost_color); - // Update cost tooltips - collapsed_ccost = ccost_btn.getAttribute('block-cost'); - collapsed_dcost = dcost_btn.getAttribute('block-cost'); - ccost_tt.innerText = 'Op Count: ' + collapsed_ccost; - dcost_tt.innerText = 'Bits Moved: ' + collapsed_dcost; - } - } -}; - -function toggleViz(id) { - toggleVizByElem(document.getElementById(id)); -} - -/* Scroll to visualization from IR code */ -function scrollToViz(id) { - var container = document.getElementById('ir-visualization-tab'); - var scrollToObject = document.getElementById(id); - makeVizVisible(scrollToObject); - scrollToObject = scrollToObject.parentElement.parentElement; - container.scrollTo({ - top: getOffsetTop(scrollToObject) - 8, - left: getOffsetLeft(scrollToObject) - 8, - behavior: 'smooth' - }); - scrollToObject.style.backgroundColor = 'white'; - setTimeout(function () { - scrollToObject.style.backgroundColor = 'transparent'; - }, 1000); -} - -function getOffsetTop(element) { - if (!element) return 0; - if (element.id == 'ir-visualization-tab') return 0; - return getOffsetTop(element.offsetParent) + element.offsetTop; -} - -function getOffsetLeft(element) { - if (!element) return 0; - if (element.id == 'ir-visualization-tab') return 0; - return getOffsetLeft(element.offsetParent) + element.offsetLeft; -} - -// In case the code we are scrolling to viz block that sits within -// a collapsed parent block, uncollapse it -function makeVizVisible(element) { - if (!element) return; - if (element == document) return; - if (element.classList.contains("collapsed-viz")) { - toggleViz(element.id); - } - makeVizVisible(element.parentNode); -} - -/* Resizing visualization tabs */ -var codeDiv = document.getElementById('ir-code-tab'); -var resizeBar = document.getElementById('resize-bar-1'); -var irVizDiv = document.getElementById('ir-visualization-tab'); -var resizeBarAssembly = document.getElementById('resize-bar-2'); -var assemblyCodeDiv = document.getElementById('assembly-tab'); - -codeDiv.style.flexGrow = '0'; -resizeBar.style.flexGrow = '0'; -irVizDiv.style.flexGrow = '0'; -resizeBarAssembly.style.flexGrow = '0'; -assemblyCodeDiv.style.flexGrow = '0'; - -codeDiv.style.flexBasis = 'calc(50% - 6px)'; -resizeBar.style.flexBasis = '6px'; -irVizDiv.style.flexBasis = 'calc(50% - 3px)'; -resizeBarAssembly.style.flexBasis = '6px'; - -var currentResizer; -var mousedown = false; -resizeBar.addEventListener('mousedown', (event) => { - currentResizer = resizeBar; - mousedown = true; -}); -resizeBarAssembly.addEventListener('mousedown', (event) => { - currentResizer = resizeBarAssembly; - mousedown = true; -}); -document.addEventListener('mouseup', (event) => { - currentResizer = null; - mousedown = false; -}); - -document.addEventListener('mousemove', (event) => { - if (mousedown) { - if (currentResizer == resizeBar) { - resize(event); - } else if (currentResizer == resizeBarAssembly) { - resizeAssembly(event); - } - } -}); - - -function resize(e) { - if (e.x < 25) { - collapse_code_tab(); - return; - } - - const size = `${e.x}px`; - var rect = resizeBarAssembly.getBoundingClientRect(); - - if (e.x > rect.left) { - collapseR_visualization_tab(); - return; - } - - codeDiv.style.display = 'block'; - irVizDiv.style.display = 'block'; - codeDiv.style.flexBasis = size; - irVizDiv.style.flexBasis = `calc(${rect.left}px - ${size})`; -} - -function resizeAssembly(e) { - if (e.x > screen.width - 25) { - collapse_assembly_tab(); - return; - } - - var rect = resizeBar.getBoundingClientRect(); - - if (e.x < rect.right) { - collapseL_visualization_tab(); - return; - } - - const size = `${e.x}px`; - irVizDiv.style.display = 'block'; - assemblyCodeDiv.style.display = 'block'; - irVizDiv.style.flexBasis = `calc(${size} - ${rect.right}px)`; - assemblyCodeDiv.style.flexBasis = `calc(100% - ${size})`; - -} - -function collapse_code_tab() { - irVizDiv.style.display = 'block'; - var rect = resizeBarAssembly.getBoundingClientRect(); - irVizDiv.style.flexBasis = `${rect.left}px`; - codeDiv.style.display = 'none'; -} - -function collapseR_visualization_tab() { - codeDiv.style.display = 'block'; - var rect = resizeBarAssembly.getBoundingClientRect(); - codeDiv.style.flexBasis = `${rect.left}px`; - irVizDiv.style.display = 'none'; -} - -function collapseL_visualization_tab() { - assemblyCodeDiv.style.display = 'block'; - var rect = resizeBar.getBoundingClientRect(); - assemblyCodeDiv.style.flexBasis = `calc(100% - ${rect.right}px)`; - irVizDiv.style.display = 'none'; -} - -function collapse_assembly_tab() { - irVizDiv.style.display = 'block'; - var rect = resizeBar.getBoundingClientRect(); - irVizDiv.style.flexBasis = `calc(100% - ${rect.right}px)`; - assemblyCodeDiv.style.display = 'none'; -} - -function depth(elem) { - if (elem.id == 'ir-visualization-tab') { - return 0; - } else if (elem.tagName == 'DIV' && elem.classList.contains("box")) { - return 1 + depth(elem.parentNode); - } else { - return depth(elem.parentNode); - } -} - -// Collapse viz boxes beyond at depth > 1 -$('div[id^="viz-"]').filter((idx, val) => { - return depth(val) > 1; -}).each((idx, val) => { - toggleVizByElem(val); -}); - -// Cost model js -var re = /(?:\-([^-]+))?$/; -var cost_btns = $('div[id^="cc-"], div[id^="dc-"]'); -for (var i = 0; i < cost_btns.size(); i++) { - const button = cost_btns[i]; - const highlight_span = document.getElementById("cost-bg-" + re.exec(button.id)[1]); // span# - $(button).mouseover(() => { - $(highlight_span).css("background", "#e5e3e3"); - }); - $(button).mouseout(() => { - $(highlight_span).css("background", "none"); - }); -} diff --git a/src/irvisualizer/html_template_StmtToViz_dependencies.html b/src/irvisualizer/html_template_StmtToViz_dependencies.html deleted file mode 100644 index 7de659ca6588..000000000000 --- a/src/irvisualizer/html_template_StmtToViz_dependencies.html +++ /dev/null @@ -1,4 +0,0 @@ - - - - From 134615cc7a1b289c32afd5780909d1e13bce737a Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Fri, 15 Sep 2023 22:50:10 +0200 Subject: [PATCH 13/22] Finalize StmtToViz nuke and rename StmtToHTML. --- Makefile | 9 +++------ src/CMakeLists.txt | 4 ++-- src/{StmtToViz.cpp => StmtToHTML.cpp} | 8 ++------ src/{StmtToViz.h => StmtToHTML.h} | 4 ++-- 4 files changed, 9 insertions(+), 16 deletions(-) rename src/{StmtToViz.cpp => StmtToHTML.cpp} (99%) rename src/{StmtToViz.h => StmtToHTML.h} (95%) diff --git a/Makefile b/Makefile index f0e7d977b938..f8e51b22320e 100644 --- a/Makefile +++ b/Makefile @@ -615,7 +615,7 @@ SOURCE_FILES = \ SpirvIR.cpp \ SplitTuples.cpp \ StageStridedLoads.cpp \ - StmtToViz.cpp \ + StmtToHTML.cpp \ StorageFlattening.cpp \ StorageFolding.cpp \ StrictifyFloat.cpp \ @@ -643,10 +643,7 @@ SOURCE_FILES = \ HTML_TEMPLATE_FILES = \ StmtToHTML_dependencies.html \ StmtToHTML.js \ - StmtToHTML.css \ - StmtToViz_dependencies.html \ - StmtToViz.js \ - StmtToViz.css + StmtToHTML.css # The externally-visible header files that go into making Halide.h. # Don't include anything here that includes llvm headers. @@ -799,7 +796,7 @@ HEADER_FILES = \ Solve.h \ SplitTuples.h \ StageStridedLoads.h \ - StmtToViz.h \ + StmtToHTML.h \ StorageFlattening.h \ StorageFolding.h \ StrictifyFloat.h \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 08181948e6aa..d5d6a8a3832e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -151,7 +151,7 @@ set(HEADER_FILES Solve.h SplitTuples.h StageStridedLoads.h - StmtToViz.h + StmtToHTML.h StorageFlattening.h StorageFolding.h StrictifyFloat.h @@ -334,7 +334,7 @@ set(SOURCE_FILES SpirvIR.cpp SplitTuples.cpp StageStridedLoads.cpp - StmtToViz.cpp + StmtToHTML.cpp StorageFlattening.cpp StorageFolding.cpp StrictifyFloat.cpp diff --git a/src/StmtToViz.cpp b/src/StmtToHTML.cpp similarity index 99% rename from src/StmtToViz.cpp rename to src/StmtToHTML.cpp index 8c4856a0a8a0..f4ff10b4bc76 100644 --- a/src/StmtToViz.cpp +++ b/src/StmtToHTML.cpp @@ -1,4 +1,4 @@ -#include "StmtToViz.h" +#include "StmtToHTML.h" #include "Debug.h" #include "Error.h" #include "IROperator.h" @@ -740,7 +740,7 @@ class HTMLCodePrinter : public IRVisitor { // The implementation doesn't need to support submodules: // we only call this for Modules that have already had their submodules // resolved. - internal_assert(m.submodules().empty()) << "StmtToViz does not support submodules."; + internal_assert(m.submodules().empty()) << "StmtToHTML does not support submodules."; // Open div to hold this module print_opening_tag("div", "Module"); @@ -2411,10 +2411,6 @@ class PipelineHTMLInspector { debug(1) << "Will link CSS in directory: " << dir << "\n"; internal_assert(std::filesystem::exists(dir)); stream << "\n"; - if (include_viztree) { - stream << halide_html_template_StmtToViz_dependencies_html; - stream << "\n"; - } #endif stream << "\n"; } diff --git a/src/StmtToViz.h b/src/StmtToHTML.h similarity index 95% rename from src/StmtToViz.h rename to src/StmtToHTML.h index 657a1e5d3cb8..fb7b6a06d9ba 100644 --- a/src/StmtToViz.h +++ b/src/StmtToHTML.h @@ -1,5 +1,5 @@ -#ifndef HALIDE_STMT_TO_VIZ -#define HALIDE_STMT_TO_VIZ +#ifndef HALIDE_STMT_TO_HTML +#define HALIDE_STMT_TO_HTML /** \file * Defines a function to dump an HTML-formatted visualization to a file. From 43925bc910b3a16428fd9038700e82065c3076c5 Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Sat, 16 Sep 2023 01:06:13 +0200 Subject: [PATCH 14/22] Improved HTML correctness by running output through an online validator. Quite some bugs fixed. --- src/StmtToHTML.cpp | 128 +++++++----------- src/irvisualizer/html_template_StmtToHTML.css | 77 +++++------ 2 files changed, 91 insertions(+), 114 deletions(-) diff --git a/src/StmtToHTML.cpp b/src/StmtToHTML.cpp index f4ff10b4bc76..72ced43fcd61 100644 --- a/src/StmtToHTML.cpp +++ b/src/StmtToHTML.cpp @@ -22,7 +22,7 @@ // causes you to be able to just edit the files without having to recompile Halide // and then rerun your generator. // For distribution purposes, they should be inlined, and this define should be on 1. -#define INLINE_TEMPLATES 1 // nocheckin +#define INLINE_TEMPLATES 0 #if !INLINE_TEMPLATES #include @@ -784,10 +784,20 @@ class HTMLCodePrinter : public IRVisitor { scope.pop(m.name()); } + inline std::string escape_html(std::string src) { + src = replace_all(src, "&", "&"); + src = replace_all(src, "<", "<"); + src = replace_all(src, ">", ">"); + src = replace_all(src, "\"", """); + src = replace_all(src, "/", "/"); + src = replace_all(src, "'", "'"); + return src; + } + // CUDA kernels are embedded into modules as PTX assembly. This // routine pretty - prints that assembly format. void print_cuda_gpu_source_kernels(const std::string &str) { - print_opening_tag("code", "ptx"); + print_opening_tag("div", "code ptx"); int current_id = -1; bool in_braces = false; @@ -801,12 +811,7 @@ class HTMLCodePrinter : public IRVisitor { stream << "\n"; continue; } - line = replace_all(line, "&", "&"); - line = replace_all(line, "<", "<"); - line = replace_all(line, ">", ">"); - line = replace_all(line, "\"", """); - line = replace_all(line, "/", "/"); - line = replace_all(line, "'", "'"); + line = escape_html(line); bool should_print_open_indent = false; @@ -957,7 +962,7 @@ class HTMLCodePrinter : public IRVisitor { print_opening_tag("div", "indent", current_id); } } - print_closing_tag("code"); + print_closing_tag("div"); } private: @@ -985,54 +990,12 @@ class HTMLCodePrinter : public IRVisitor { /* Private print functions to handle various IR types */ void print(const Buffer<> &buf) { - // Generate a unique ID for this module - int id = gen_unique_id(); - - // Determine whether to print buffer data - bool print_data = ends_with(buf.name(), "_gpu_source_kernels"); - // Open div to hold this buffer print_opening_tag("div", "Buffer"); - if (print_data) { - // Generate the show hide icon/text buttons - print_show_hide_btn_begin(id, true); - - // -- print text - print_html_element("span", "keyword", "buffer "); - print_variable(buf.name()); - - // Print data - print_text(" = "); - - // Open code block to hold module body - print_opening_brace(); - print_show_hide_btn_end(); - - // Open indented div to hold buffer data - print_opening_tag("div", "indent BufferData", id); - - int length = buf.size_in_bytes(); - while (length > 0 && ((const char *)buf.data())[length - 1] == '\0') { - length--; - } - std::string str((const char *)buf.data(), length); - if (starts_with(buf.name(), "cuda_")) { - print_cuda_gpu_source_kernels(str); - } else { - stream << "
\n"
-                       << str << "
\n"; - } - - print_closing_tag("div"); - - // Close code block holding buffer body - print_html_element("span", "matched ClosingBrace cb-" + std::to_string(id), " }"); - } else { - // Print buffer name and move on - print_html_element("span", "keyword", "buffer "); - print_variable(buf.name()); - } + // Print buffer name and move on + print_html_element("span", "keyword", "buffer "); + print_variable(buf.name()); // Close div holding this buffer print_closing_tag("div"); @@ -1195,19 +1158,19 @@ class HTMLCodePrinter : public IRVisitor { { int asm_lno = host_assembly_info.get_asm_lno((uint64_t)op); if (asm_lno != -1) { - stream << ""; + << "
"; } } { int asm_lno = device_assembly_info.get_asm_lno((uint64_t)op); if (asm_lno != -1) { - stream << ""; + << "
"; } } } @@ -1392,10 +1355,11 @@ class HTMLCodePrinter : public IRVisitor { block_cost_class += " NoChildCost"; } - stream << "
"; + stream << "
"; stream << "" << prefix << line_cost; @@ -1508,7 +1472,7 @@ class HTMLCodePrinter : public IRVisitor { } void visit(const LE *op) override { - print_binary_op(op->a, op->b, "<="); + print_binary_op(op->a, op->b, "<="); } void visit(const GT *op) override { @@ -2314,9 +2278,9 @@ class PipelineHTMLInspector { public: // Construct the visualizer and point it to the output file explicit PipelineHTMLInspector(const std::string &html_output_filename, - const Module &m, - const std::string &assembly_input_filename, - bool use_conceptual_stmt_ir) + const Module &m, + const std::string &assembly_input_filename, + bool use_conceptual_stmt_ir) : use_conceptual_stmt_ir(use_conceptual_stmt_ir), html_code_printer(stream, node_ids, true) { // Open output file @@ -2377,7 +2341,7 @@ class PipelineHTMLInspector { // Generate html page stream << "\n"; - stream << "\n"; + stream << "\n"; generate_head(m); generate_body(m); stream << ""; @@ -2421,7 +2385,6 @@ class PipelineHTMLInspector { stream << "
\n"; generate_visualization_panes(m); stream << "
\n"; - stream << ""; #if INLINE_TEMPLATES stream << "\n"; #endif + stream << ""; } // Generate the three visualization panes void generate_visualization_panes(const Module &m) { int pane_count = 0; stream << "
\n"; - stream << "
\n"; + stream << "\n"; generate_ir_pane(m); generate_resize_bar(pane_count++); generate_host_assembly_pane(m); @@ -2469,7 +2433,16 @@ class PipelineHTMLInspector { stream << "
\n"; stream << "
\n"; stream << "
\n";
-        stream << asm_stream.str();
+        std::istringstream ss{asm_stream.str()};
+        for (std::string line; std::getline(ss, line);) {
+            if (line.length() > 500) {
+                // Very long lines in the assembly are typically the _gpu_kernel_sources
+                // as a raw ASCII block in the assembly. Let's chop that off to make
+                // browsers faster when dealing with this.
+                line = line.substr(0, 100) + "\" # omitted the remainder of the ASCII buffer";
+            }
+            stream << html_code_printer.escape_html(line) << "\n";
+        }
         stream << "\n";
         stream << "
\n"; stream << "
\n"; @@ -2487,10 +2460,13 @@ class PipelineHTMLInspector { if (starts_with(buf.name(), "cuda_")) { html_code_printer.print_cuda_gpu_source_kernels(str); } else { - stream << "\n"; - stream << str; - stream << "\n"; - stream << "\n"; + std::istringstream ss{str}; + stream << "
\n"; + for (std::string line; std::getline(ss, line);) { + stream << "" << html_code_printer.escape_html(line) << "\n"; + // stream << html_code_printer.escape_html(line) << "\n"; + } + stream << "\n
\n"; } stream << "
\n"; } @@ -2500,11 +2476,11 @@ class PipelineHTMLInspector { stream << "
\n"; stream << "
\n"; stream << "
\n"; - stream << " \n"; stream << "
\n"; stream << "
\n"; - stream << " \n"; stream << "
\n"; stream << "
\n"; diff --git a/src/irvisualizer/html_template_StmtToHTML.css b/src/irvisualizer/html_template_StmtToHTML.css index 622e9a2573ff..90c47329f4df 100644 --- a/src/irvisualizer/html_template_StmtToHTML.css +++ b/src/irvisualizer/html_template_StmtToHTML.css @@ -1,7 +1,10 @@ /* General CSS Rules*/ -body { +* { font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 12px; +} + +body { background: #f8f8f8; padding: 0; margin: 0; @@ -88,12 +91,6 @@ div#device-code-pane { flex-basis: 30%;*/ } -button#highlight-button { - margin: 0.4em; - padding: 0.5em; - border-radius: 4px; -} - span.line { counter-increment: line; } @@ -138,13 +135,15 @@ div.resize-bar > div.collapse-btns button.collapse-right:before { content: "\21E /* Revert collapser button that points to the left. */ div.collapsed-pane + div.resize-bar button.collapse-left { - background-color: rgba(0, 0, 0, 0.2); + background-color: rgba(0, 0, 0, 0.4); + border: 2px solid rgba(0, 0, 0, 0.4); } div.collapsed-pane + div.resize-bar button.collapse-left:before { content: "\21A6"; } div.resize-bar:has(+ div.collapsed-pane) button.collapse-right { - background-color: rgba(0, 0, 0, 0.2); + background-color: rgba(0, 0, 0, 0.4); + border: 2px solid rgba(0, 0, 0, 0.4); } div.resize-bar:has(+ div.collapsed-pane) > div.collapse-btns button.collapse-right:before { content: "\21A4"; @@ -168,7 +167,6 @@ div#resizer-preview { } - div#device-code-pane code { line-height: 14px; white-space: pre; @@ -179,7 +177,7 @@ div#device-code-pane code { padding-left: 70px !important; } -div.Function, div.Buffer { +div.Function { margin: 0.2em 0.0em; padding: 0.1em; margin-right: 0.8em; @@ -192,7 +190,6 @@ div.Function, div.Buffer { div.Function + div.Function { margin-top: 1.5em; /* Leave space between two functions. */ } -div.Buffer { background-color: rgba(200, 100, 0, 0.025); border-color: rgba(200, 100, 0, 0.03); } /* Give functions a slightly different background color to visually help navigate quickly. */ div.Function:nth-child(3n + 1) { background-color: rgba(200, 0, 0, 0.025); border-color: rgba(200, 0, 0, 0.03); } @@ -327,30 +324,29 @@ input.show-hide-btn { padding: 0; height: 12px; vertical-align: top; + width: 12px; + height: 12px; + border: 1px solid black; + border-radius: 4px; + transition: transform 0.2s; + transform: rotate(0deg); +} +input.show-hide-btn:checked { + transform: rotate(-90deg); } input.show-hide-btn:before { - content: ">"; - font-size: 10px; - width: 12px; - height: 12px; + content: "V"; + font-size: 9px; + width: 100%; box-sizing: border-box; - text-anchor: middle; text-align: center; - line-height: 9px; display: inline-block; - border: 1px solid black; - border-radius: 4px; padding: 0; margin: 0; overflow: hidden; - transition: transform 0.2s; - transform: rotate(90deg); } -input.show-hide-btn:checked:before { - transform: rotate(0deg); -} div.indent { @@ -405,7 +401,7 @@ input.show-hide-btn:checked + label > span:last-child:after { color: gray; } -button.icon-btn { +div.button.icon-btn { padding: 0 3px; margin-left: 2px; margin-right: 0px; @@ -419,7 +415,7 @@ button.icon-btn { border-radius: 4px; } -button.icon-btn :before { +div.button.icon-btn:before { margin: 0; padding: 0; border: 0; @@ -427,18 +423,18 @@ button.icon-btn :before { display: inline-block; } -button.jump-to-host-asm-btn { +div.button.jump-to-host-asm-btn { background: rgba(255,50,0,0.1); border-color: rgb( 255,50,0); color: rgb( 255,50,0); } -button.jump-to-device-code-btn { +div.button.jump-to-device-code-btn { background: rgba(70,170,50,0.1); border-color: rgb( 70,170,50); color: rgb( 70,170,50); } -button.jump-to-host-asm-btn span.tooltip span, button.jump-to-device-code-btn span.tooltip span { +div.button.jump-to-host-asm-btn span.tooltip span, div.button.jump-to-device-code-btn span.tooltip span { display: block; margin-top: 0.6em; font-size: 10px; @@ -446,21 +442,24 @@ button.jump-to-host-asm-btn span.tooltip span, button.jump-to-device-code-btn sp color: green; } -button.jump-to-host-asm-btn:before, button.jump-to-device-code-btn:before, button.jump-to-viz-btn:before { +div.button.jump-to-host-asm-btn:before, div.button.jump-to-device-code-btn:before, div.button.jump-to-viz-btn:before { content: "\279F"; } -div#ir-visualization-pane button.icon-btn { +div#ir-visualization-pane div.button.icon-btn { margin-left: 1px; } -button.icon-btn:hover { +div.button.icon-btn:hover { border-width: 2px; line-height: 10px; } -code.ptx { - pane-size: 26; +div.code { + white-space: pre; +} +div.code.ptx { + tab-size: 26; } span.comment { @@ -711,6 +710,7 @@ div.cost-btn:hover { font: 12px Consolas,Courier New,Monaco,Andale Mono,Ubuntu Mono,monospace; line-height:14px; box-sizing:border-box; + width: fit-content; } .shj-inline{ margin:0; @@ -722,8 +722,9 @@ div.cost-btn:hover { background:#bdf5 } [class*=shj-lang-]>div{ - display:flex; - overflow:auto + display: block; + overflow: visible; + width: fit-content; } [class*=shj-lang-]>div :last-child{ flex:1; @@ -735,7 +736,7 @@ div.cost-btn:hover { } .shj-numbers div{ padding-right:5px; - width:0; + width:0; } .shj-numbers div:before{ color:#999; From c27592c796ff9a22edd7939b13ee4c2e8c235002 Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Sat, 16 Sep 2023 01:40:02 +0200 Subject: [PATCH 15/22] Cost model visualization improvement. Fix button not being allowed in the checkbox/label combination. --- src/StmtToHTML.cpp | 12 +++++---- src/irvisualizer/html_template_StmtToHTML.css | 27 ++++++++----------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/StmtToHTML.cpp b/src/StmtToHTML.cpp index 72ced43fcd61..ac7768848594 100644 --- a/src/StmtToHTML.cpp +++ b/src/StmtToHTML.cpp @@ -22,7 +22,7 @@ // causes you to be able to just edit the files without having to recompile Halide // and then rerun your generator. // For distribution purposes, they should be inlined, and this define should be on 1. -#define INLINE_TEMPLATES 0 +#define INLINE_TEMPLATES 1 #if !INLINE_TEMPLATES #include @@ -1301,33 +1301,35 @@ class HTMLCodePrinter : public IRVisitor { // Prints the button/indicator for the compute cost of a line in the program void print_compute_cost(const IRNode *op, int id) { int max_line_cost = cost_model.get_max_compute_cost(false); + int max_block_cost = cost_model.get_max_compute_cost(true); int line_cost = cost_model.get_compute_cost(op, false); int block_cost = cost_model.get_compute_cost(op, true); if (dynamic_cast(op) || dynamic_cast(op)) { block_cost = line_cost; } std::string _id = "cc-" + std::to_string(id); - print_cost_btn(line_cost, block_cost, max_line_cost, _id, "Op Count: "); + print_cost_btn(line_cost, block_cost, max_line_cost, max_block_cost, _id, "Op Count: "); } // Prints the button/indicator for the data movement cost of a line in the program void print_data_movement_cost(const IRNode *op, int id) { int max_line_cost = cost_model.get_max_data_movement_cost(false); + int max_block_cost = cost_model.get_max_data_movement_cost(true); int line_cost = cost_model.get_data_movement_cost(op, false); int block_cost = cost_model.get_data_movement_cost(op, true); if (dynamic_cast(op) || dynamic_cast(op)) { block_cost = line_cost; } std::string _id = "dc-" + std::to_string(id); - print_cost_btn(line_cost, block_cost, max_line_cost, _id, "Bits Moved: "); + print_cost_btn(line_cost, block_cost, max_line_cost, max_block_cost, _id, "Bits Moved: "); } // Prints a cost button/indicator - void print_cost_btn(int line_cost, int block_cost, int max_line_cost, std::string id, std::string prefix) { + void print_cost_btn(int line_cost, int block_cost, int max_line_cost, int max_block_cost, std::string id, std::string prefix) { const int num_cost_buckets = 20; int line_cost_bin_size = (max_line_cost / num_cost_buckets) + 1; - int block_cost_bin_size = (max_line_cost / num_cost_buckets) + 1; + int block_cost_bin_size = (max_block_cost / num_cost_buckets) + 1; int line_costc = line_cost / line_cost_bin_size; int block_costc = block_cost / block_cost_bin_size; diff --git a/src/irvisualizer/html_template_StmtToHTML.css b/src/irvisualizer/html_template_StmtToHTML.css index 90c47329f4df..87944443d1e9 100644 --- a/src/irvisualizer/html_template_StmtToHTML.css +++ b/src/irvisualizer/html_template_StmtToHTML.css @@ -149,11 +149,6 @@ div.resize-bar:has(+ div.collapsed-pane) > div.collapse-btns button.collapse-rig content: "\21A4"; } -button.resize-btn { - margin: 10px 3px; - font-size: 18px; -} - /* Resizer Preview */ div#resizer-preview { position: absolute; @@ -401,7 +396,7 @@ input.show-hide-btn:checked + label > span:last-child:after { color: gray; } -div.button.icon-btn { +div.icon-btn { padding: 0 3px; margin-left: 2px; margin-right: 0px; @@ -410,31 +405,31 @@ div.button.icon-btn { vertical-align: middle; background: transparent; font-size: 15px; - line-height: 12px; border: 1px solid black; border-radius: 4px; - + display: inline-block; + text-align: center; + box-sizing: border-box; } -div.button.icon-btn:before { +div.icon-btn:before { margin: 0; padding: 0; border: 0; - color: black; display: inline-block; } -div.button.jump-to-host-asm-btn { +div.jump-to-host-asm-btn { background: rgba(255,50,0,0.1); border-color: rgb( 255,50,0); color: rgb( 255,50,0); } -div.button.jump-to-device-code-btn { +div.jump-to-device-code-btn { background: rgba(70,170,50,0.1); border-color: rgb( 70,170,50); color: rgb( 70,170,50); } -div.button.jump-to-host-asm-btn span.tooltip span, div.button.jump-to-device-code-btn span.tooltip span { +div.jump-to-host-asm-btn span.tooltip span, div.jump-to-device-code-btn span.tooltip span { display: block; margin-top: 0.6em; font-size: 10px; @@ -442,15 +437,15 @@ div.button.jump-to-host-asm-btn span.tooltip span, div.button.jump-to-device-cod color: green; } -div.button.jump-to-host-asm-btn:before, div.button.jump-to-device-code-btn:before, div.button.jump-to-viz-btn:before { +div.jump-to-host-asm-btn:before, div.jump-to-device-code-btn:before, div.jump-to-viz-btn:before { content: "\279F"; } -div#ir-visualization-pane div.button.icon-btn { +div#ir-visualization-pane div.icon-btn { margin-left: 1px; } -div.button.icon-btn:hover { +div.icon-btn:hover { border-width: 2px; line-height: 10px; } From e33cf2c153d4a648e3f76f792287241da3aeca29 Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Sat, 16 Sep 2023 02:12:43 +0200 Subject: [PATCH 16/22] Fix collapsing being triggered by jump-to-xxx buttons. --- src/StmtToHTML.cpp | 39 +++++++++---------- src/irvisualizer/html_template_StmtToHTML.css | 20 ++++++---- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/src/StmtToHTML.cpp b/src/StmtToHTML.cpp index ac7768848594..84299083acad 100644 --- a/src/StmtToHTML.cpp +++ b/src/StmtToHTML.cpp @@ -707,7 +707,7 @@ class HTMLCodePrinter : public IRVisitor { // Open code block to hold module body print_opening_brace(); - print_show_hide_btn_end(); + print_show_hide_btn_end(nullptr); // Open indented div to hold body code print_opening_tag("div", "indent ModuleBody", id); @@ -756,7 +756,7 @@ class HTMLCodePrinter : public IRVisitor { // Open code block to hold module body print_opening_brace(); - print_show_hide_btn_end(); + print_show_hide_btn_end(nullptr); // Open indented div to hold body code print_opening_tag("div", "indent ModuleBody", id); @@ -958,7 +958,7 @@ class HTMLCodePrinter : public IRVisitor { // Indent-divs can only be opened after the line is finished. if (should_print_open_indent) { - print_show_hide_btn_end(); + print_show_hide_btn_end(nullptr); print_opening_tag("div", "indent", current_id); } } @@ -1024,7 +1024,7 @@ class HTMLCodePrinter : public IRVisitor { // Open code block to hold function body print_opening_brace(); - print_show_hide_btn_end(); + print_show_hide_btn_end(nullptr); // Open indented div to hold body code print_opening_tag("div", "indent FunctionBody", id); @@ -1116,8 +1116,12 @@ class HTMLCodePrinter : public IRVisitor { stream << ""; + void print_show_hide_btn_end(const IRNode *op) { + stream << "
"; + if (op) { + print_assembly_button(op); + } + stream << "
"; } // Prints newline to stream @@ -1263,10 +1267,9 @@ class HTMLCodePrinter : public IRVisitor { // -- print text print_html_element("span", "keyword matched", "task"); - print_show_hide_btn_end(); - // Open code block to hold task body print_opening_brace(); + print_show_hide_btn_end(nullptr); // Open indented div to hold body code print_opening_tag("div", "indent ForkTask", id); @@ -1617,11 +1620,9 @@ class HTMLCodePrinter : public IRVisitor { print_variable(op->name); print_closing_tag("span"); - print_assembly_button(op); - // Open code block to hold function body print_opening_brace(); - print_show_hide_btn_end(); + print_show_hide_btn_end(op); // Open indented div to hold body code print_opening_tag("div", "indent ProducerConsumerBody", id); @@ -1696,11 +1697,9 @@ class HTMLCodePrinter : public IRVisitor { print(op->extent); print_html_element("span", "matched", ")"); - print_assembly_button(op); - // Open code block to hold function body print_opening_brace(); - print_show_hide_btn_end(); + print_show_hide_btn_end(op); // Open indented div to hold body code print_opening_tag("div", "indent ForBody", id); @@ -1745,7 +1744,7 @@ class HTMLCodePrinter : public IRVisitor { // Open code block to hold function body print_opening_brace(); - print_show_hide_btn_end(); + print_show_hide_btn_end(op); // Open indented div to hold body code print_opening_tag("div", "indent AcquireBody", id); @@ -1938,7 +1937,7 @@ class HTMLCodePrinter : public IRVisitor { // Open code block to hold function body print_opening_brace(); - print_show_hide_btn_end(); + print_show_hide_btn_end(op); // Open indented div to hold body code print_opening_tag("div", "indent RealizeBody", id); @@ -1982,7 +1981,7 @@ class HTMLCodePrinter : public IRVisitor { // Open code block to hold fork body print_opening_brace(); - print_show_hide_btn_end(); + print_show_hide_btn_end(op); // Open indented div to hold body code print_opening_tag("div", "indent ForkBody", id); @@ -2032,7 +2031,7 @@ class HTMLCodePrinter : public IRVisitor { // Open code block to hold `then` case print_opening_brace(); - print_show_hide_btn_end(); + print_show_hide_btn_end(op); // Open indented div to hold code for the `then` case print_opening_tag("div", "indent ThenBody", then_block_id); @@ -2101,7 +2100,7 @@ class HTMLCodePrinter : public IRVisitor { // Open code block to hold `else` case print_opening_brace(); - print_show_hide_btn_end(); + print_show_hide_btn_end(op); // Open indented div to hold code for the `then` case print_opening_tag("div", "indent ElseBody", else_block_id); @@ -2251,7 +2250,7 @@ class HTMLCodePrinter : public IRVisitor { // Open code block to hold atomic body print_opening_brace(); - print_show_hide_btn_end(); + print_show_hide_btn_end(op); // Open indented div to hold atomic code print_opening_tag("div", "indent AtomicBody", id); diff --git a/src/irvisualizer/html_template_StmtToHTML.css b/src/irvisualizer/html_template_StmtToHTML.css index 87944443d1e9..db585c30a58f 100644 --- a/src/irvisualizer/html_template_StmtToHTML.css +++ b/src/irvisualizer/html_template_StmtToHTML.css @@ -355,10 +355,16 @@ input.show-hide-btn:hover { color: #c30000; } -/* The structure always has to be
\n"; From d14e4ea5b94b424be4d306031d2ea9da858d220a Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Thu, 5 Oct 2023 18:35:44 +0200 Subject: [PATCH 20/22] Process Andrew's feedback, part 3. --- src/IRPrinter.cpp | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/src/IRPrinter.cpp b/src/IRPrinter.cpp index ad0c6db36555..96c472698011 100644 --- a/src/IRPrinter.cpp +++ b/src/IRPrinter.cpp @@ -1085,35 +1085,9 @@ void IRPrinter::visit(const Shuffle *op) { } void IRPrinter::visit(const VectorReduce *op) { - std::string op_str; - switch (op->op) { - case VectorReduce::Add: - op_str = "add"; - break; - case VectorReduce::SaturatingAdd: - op_str = "saturating_add"; - break; - case VectorReduce::Mul: - op_str = "mul"; - break; - case VectorReduce::Min: - op_str = "min"; - break; - case VectorReduce::Max: - op_str = "max"; - break; - case VectorReduce::And: - op_str = "and"; - break; - case VectorReduce::Or: - op_str = "or"; - break; - default: - internal_assert(false) << "Not a valid VectorReduce::Operator"; - } stream << "(" << op->type - << ")vector_reduce_" << op_str << "(" + << ")vector_reduce_" << op->op << "(" << ", " << op->value << ")"; From 5d32813e3deeb31a207f2c38399ce6b2eabd01e6 Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Fri, 6 Oct 2023 12:05:48 +0200 Subject: [PATCH 21/22] Improve color palette. Few minor improvements. --- src/StmtToHTML.cpp | 12 +- src/irvisualizer/generate_palettes.py | 34 +++ src/irvisualizer/html_template_StmtToHTML.css | 235 +++++++++--------- src/irvisualizer/html_template_StmtToHTML.js | 22 ++ 4 files changed, 175 insertions(+), 128 deletions(-) create mode 100644 src/irvisualizer/generate_palettes.py diff --git a/src/StmtToHTML.cpp b/src/StmtToHTML.cpp index 418cc4689027..e5a0a095c507 100644 --- a/src/StmtToHTML.cpp +++ b/src/StmtToHTML.cpp @@ -1330,12 +1330,14 @@ class HTMLCodePrinter : public IRVisitor { // Prints a cost button/indicator void print_cost_btn(int line_cost, int block_cost, int max_line_cost, int max_block_cost, std::string id, std::string prefix) { const int num_cost_buckets = 20; + const auto compand = [](int v) -> int { return (int) std::sqrt(v * 10); }; - int line_cost_bin_size = (max_line_cost / num_cost_buckets) + 1; - int block_cost_bin_size = (max_block_cost / num_cost_buckets) + 1; + int max_cost = std::max(max_line_cost, max_block_cost); // This should always be the block cost. + int line_cost_bin_size = (compand(max_cost) / num_cost_buckets) + 1; + int block_cost_bin_size = (compand(max_cost) / num_cost_buckets) + 1; - int line_costc = line_cost / line_cost_bin_size; - int block_costc = block_cost / block_cost_bin_size; + int line_costc = compand(line_cost) / line_cost_bin_size; + int block_costc = compand(block_cost) / block_cost_bin_size; if (line_costc >= num_cost_buckets) { line_costc = num_cost_buckets - 1; @@ -1362,8 +1364,6 @@ class HTMLCodePrinter : public IRVisitor { stream << "
"; stream << "" diff --git a/src/irvisualizer/generate_palettes.py b/src/irvisualizer/generate_palettes.py new file mode 100644 index 000000000000..7c6f43d23704 --- /dev/null +++ b/src/irvisualizer/generate_palettes.py @@ -0,0 +1,34 @@ +def make_oklch(l, c, h): + return ("oklch(%.1f%% %.2f %.0f)" % (l * 100, c, h)) + + +STEPS = 20 + +for i in range(STEPS): + f = i / (STEPS - 1) + col = make_oklch(0.9 - f * 0.5, 0.05 + 0.1 * f, 140) + print(".block-CostColor%d:first-child { border-left: 8px solid %s; }" % (i, col)) +print(".block-CostColorNone:first-child { border-left: transparent; }") +print() + +for i in range(STEPS): + f = i / (STEPS - 1) + col = make_oklch(0.9 - f * 0.5, 0.05 + 0.1 * f, 140) + print(".line-CostColor%d:first-child { border-right: 8px solid %s; }" % (i, col)) +print(".line-CostColorNone:first-child { border-right: transparent; }") +print() + + +for i in range(STEPS): + f = i / (STEPS - 1) + col = make_oklch(0.9 - f * 0.5, 0.05 + 0.1 * f, 300) + print(".block-CostColor%d:last-child { border-left: 8px solid %s; }" % (i, col)) +print(".block-CostColorNone:last-child { border-left: transparent; }") +print() + +for i in range(STEPS): + f = i / (STEPS - 1) + col = make_oklch(0.9 - f * 0.5, 0.05 + 0.1 * f, 300) + print(".line-CostColor%d:last-child { border-right: 8px solid %s; }" % (i, col)) +print(".line-CostColorNone:last-child { border-right: transparent; }") +print() diff --git a/src/irvisualizer/html_template_StmtToHTML.css b/src/irvisualizer/html_template_StmtToHTML.css index db585c30a58f..d76bda15710a 100644 --- a/src/irvisualizer/html_template_StmtToHTML.css +++ b/src/irvisualizer/html_template_StmtToHTML.css @@ -5,7 +5,6 @@ } body { - background: #f8f8f8; padding: 0; margin: 0; line-height: 14px; @@ -61,34 +60,18 @@ div.pane.collapsed-pane { } div#ir-code-pane { - counter-reset: line; padding-left: 50px; padding-top: 20px; width: 50vw; - /*flex-grow: 2; - flex-shrink: 20; - flex-basis: 50%;*/ } div#host-assembly-pane { width: 20vw; - /* - min-width: 350px; - width: 30vw; - flex-grow: 1; - flex-shrink: 1; - flex-basis: 20%;*/ } div#device-code-pane { padding-left: 6em; width: 30vw; - /* - min-width: 550px; - width: 50vw; - flex-grow: 2; - flex-shrink: 1; - flex-basis: 30%;*/ } span.line { @@ -130,23 +113,27 @@ div.resize-bar > div.collapse-btns button { } div.resize-bar > div.collapse-btns button:hover { background-color: rgba(255, 255, 255, 0.5); } -div.resize-bar > div.collapse-btns button.collapse-left:before { content: "\21E4"; } -div.resize-bar > div.collapse-btns button.collapse-right:before { content: "\21E5"; } +/*div.resize-bar > div.collapse-btns button.collapse-left:before { content: "\21E4"; }*/ +/*div.resize-bar > div.collapse-btns button.collapse-right:before { content: "\21E5"; }*/ +div.resize-bar > div.collapse-btns button.collapse-left:before { content: "<"; } +div.resize-bar > div.collapse-btns button.collapse-right:before { content: ">"; } /* Revert collapser button that points to the left. */ -div.collapsed-pane + div.resize-bar button.collapse-left { +div.resize-bar > div.collapse-btns button.collapse-left.active { background-color: rgba(0, 0, 0, 0.4); border: 2px solid rgba(0, 0, 0, 0.4); } -div.collapsed-pane + div.resize-bar button.collapse-left:before { - content: "\21A6"; +div.resize-bar > div.collapse-btns button.collapse-left.active:before { + /*content: "\21A6";*/ + content: ">>"; } -div.resize-bar:has(+ div.collapsed-pane) button.collapse-right { +div.resize-bar > div.collapse-btns button.collapse-right.active { background-color: rgba(0, 0, 0, 0.4); border: 2px solid rgba(0, 0, 0, 0.4); } -div.resize-bar:has(+ div.collapsed-pane) > div.collapse-btns button.collapse-right:before { - content: "\21A4"; +div.resize-bar > div.collapse-btns button.collapse-right.active:before { + /*content: "\21A4";*/ + content: "<<"; } /* Resizer Preview */ @@ -181,6 +168,7 @@ div.Function { border-width: 3px; border-style: solid; border-radius: 8px; + min-width: fit-content; } div.Function + div.Function { margin-top: 1.5em; /* Leave space between two functions. */ @@ -195,6 +183,7 @@ div.Function:nth-child(3n + 3) { background-color: rgba(0, 0, 200, 0.025); borde div.For { border-radius: 8px; } div.For.for-type-parallel, div.For.for-type-gpu_block { + min-width: fit-content; background-color: rgba(240, 200, 0, 0.03); border: 3px solid rgba(240, 200, 0, 0.10); margin: 0.2em 0.0em; @@ -407,11 +396,13 @@ div.icon-btn { margin-left: 2px; margin-right: 0px; width: 24px; - height: 14px; + height: 12px; + line-height: 16px; vertical-align: middle; background: transparent; - font-size: 15px; - border: 1px solid black; + font-size: 22px; + outline: 1px solid black; + top: -1px; border-radius: 4px; display: inline-block; text-align: center; @@ -426,12 +417,12 @@ div.icon-btn:before { div.jump-to-host-asm-btn { background: rgba(255,50,0,0.1); - border-color: rgb( 255,50,0); + outline-color: rgb( 255,50,0); color: rgb( 255,50,0); } div.jump-to-device-code-btn { background: rgba(70,170,50,0.1); - border-color: rgb( 70,170,50); + outline-color: rgb( 70,170,50); color: rgb( 70,170,50); } @@ -452,8 +443,7 @@ div#ir-visualization-pane div.icon-btn { } div.icon-btn:hover { - border-width: 2px; - line-height: 10px; + outline-width: 2px; } div.code { @@ -530,6 +520,9 @@ div.Buffer, div.Evaluate { counter-increment: line; } +span.ClosingBrace + span span.IfSpan { + counter-increment: none; +} span.IfSpan:before, span.ClosingBrace:before, div.WrapLine:before, @@ -605,100 +598,98 @@ div.cost-btn:hover { /*border: 1px solid lightgray;*/ } - -.line-CostColor19 { border-right: 8px solid rgb(130, 31, 27); } -.line-CostColor18 { border-right: 8px solid rgb(145, 33, 30); } -.line-CostColor17 { border-right: 8px solid rgb(160, 33, 32); } -.line-CostColor16 { border-right: 8px solid rgb(176, 34, 34); } -.line-CostColor15 { border-right: 8px solid rgb(185, 47, 32); } -.line-CostColor14 { border-right: 8px solid rgb(193, 59, 30); } -.line-CostColor13 { border-right: 8px solid rgb(202, 71, 27); } -.line-CostColor12 { border-right: 8px solid rgb(210, 82, 22); } -.line-CostColor11 { border-right: 8px solid rgb(218, 93, 16); } -.line-CostColor10 { border-right: 8px solid rgb(226, 104, 6); } -.line-CostColor9 { border-right: 8px solid rgb(229, 118, 9); } -.line-CostColor8 { border-right: 8px solid rgb(230, 132, 15); } -.line-CostColor7 { border-right: 8px solid rgb(231, 146, 20); } -.line-CostColor6 { border-right: 8px solid rgb(232, 159, 25); } -.line-CostColor5 { border-right: 8px solid rgb(233, 172, 30); } -.line-CostColor4 { border-right: 8px solid rgb(233, 185, 35); } -.line-CostColor3 { border-right: 8px solid rgb(233, 198, 40); } -.line-CostColor2 { border-right: 8px solid rgb(232, 211, 45); } -.line-CostColor1 { border-right: 8px solid rgb(231, 223, 50); } -.line-CostColor0 { border-right: 8px solid rgb(236, 233, 89); } -.line-CostColorNone { border-right: transparent; } - -.block-CostColor19 { border-left: 8px solid rgb(130, 31, 27); } -.block-CostColor18 { border-left: 8px solid rgb(145, 33, 30); } -.block-CostColor17 { border-left: 8px solid rgb(160, 33, 32); } -.block-CostColor16 { border-left: 8px solid rgb(176, 34, 34); } -.block-CostColor15 { border-left: 8px solid rgb(185, 47, 32); } -.block-CostColor14 { border-left: 8px solid rgb(193, 59, 30); } -.block-CostColor13 { border-left: 8px solid rgb(202, 71, 27); } -.block-CostColor12 { border-left: 8px solid rgb(210, 82, 22); } -.block-CostColor11 { border-left: 8px solid rgb(218, 93, 16); } -.block-CostColor10 { border-left: 8px solid rgb(226, 104, 6); } -.block-CostColor9 { border-left: 8px solid rgb(229, 118, 9); } -.block-CostColor8 { border-left: 8px solid rgb(230, 132, 15); } -.block-CostColor7 { border-left: 8px solid rgb(231, 146, 20); } -.block-CostColor6 { border-left: 8px solid rgb(232, 159, 25); } -.block-CostColor5 { border-left: 8px solid rgb(233, 172, 30); } -.block-CostColor4 { border-left: 8px solid rgb(233, 185, 35); } -.block-CostColor3 { border-left: 8px solid rgb(233, 198, 40); } -.block-CostColor2 { border-left: 8px solid rgb(232, 211, 45); } -.block-CostColor1 { border-left: 8px solid rgb(231, 223, 50); } -.block-CostColor0 { border-left: 8px solid rgb(236, 233, 89); } -.block-CostColorNone { border-color: transparent; } - - - -.line-CostColor19:last-child { border-right: 8px solid rgb( 31, 27, 130); } -.line-CostColor18:last-child { border-right: 8px solid rgb( 33, 30, 145); } -.line-CostColor17:last-child { border-right: 8px solid rgb( 33, 32, 160); } -.line-CostColor16:last-child { border-right: 8px solid rgb( 34, 34, 176); } -.line-CostColor15:last-child { border-right: 8px solid rgb( 47, 32, 185); } -.line-CostColor14:last-child { border-right: 8px solid rgb( 59, 30, 193); } -.line-CostColor13:last-child { border-right: 8px solid rgb( 71, 27, 202); } -.line-CostColor12:last-child { border-right: 8px solid rgb( 82, 22, 210); } -.line-CostColor11:last-child { border-right: 8px solid rgb( 93, 16, 218); } -.line-CostColor10:last-child { border-right: 8px solid rgb(104, 6, 226); } -.line-CostColor9:last-child { border-right: 8px solid rgb(118, 9, 229); } -.line-CostColor8:last-child { border-right: 8px solid rgb(132, 15, 230); } -.line-CostColor7:last-child { border-right: 8px solid rgb(146, 20, 231); } -.line-CostColor6:last-child { border-right: 8px solid rgb(159, 25, 232); } -.line-CostColor5:last-child { border-right: 8px solid rgb(172, 30, 233); } -.line-CostColor4:last-child { border-right: 8px solid rgb(185, 35, 233); } -.line-CostColor3:last-child { border-right: 8px solid rgb(198, 40, 233); } -.line-CostColor2:last-child { border-right: 8px solid rgb(211, 45, 232); } -.line-CostColor1:last-child { border-right: 8px solid rgb(223, 50, 231); } -.line-CostColor0:last-child { border-right: 8px solid rgb(233, 89, 236); } -.line-CostColorNone { border-right: transparent; } - -.block-CostColor19:last-child { border-left: 8px solid rgb( 31, 27, 130); } -.block-CostColor18:last-child { border-left: 8px solid rgb( 33, 30, 145); } -.block-CostColor17:last-child { border-left: 8px solid rgb( 33, 32, 160); } -.block-CostColor16:last-child { border-left: 8px solid rgb( 34, 34, 176); } -.block-CostColor15:last-child { border-left: 8px solid rgb( 47, 32, 185); } -.block-CostColor14:last-child { border-left: 8px solid rgb( 59, 30, 193); } -.block-CostColor13:last-child { border-left: 8px solid rgb( 71, 27, 202); } -.block-CostColor12:last-child { border-left: 8px solid rgb( 82, 22, 210); } -.block-CostColor11:last-child { border-left: 8px solid rgb( 93, 16, 218); } -.block-CostColor10:last-child { border-left: 8px solid rgb(104, 6, 226); } -.block-CostColor9:last-child { border-left: 8px solid rgb(118, 9, 229); } -.block-CostColor8:last-child { border-left: 8px solid rgb(132, 15, 230); } -.block-CostColor7:last-child { border-left: 8px solid rgb(146, 20, 231); } -.block-CostColor6:last-child { border-left: 8px solid rgb(159, 25, 232); } -.block-CostColor5:last-child { border-left: 8px solid rgb(172, 30, 233); } -.block-CostColor4:last-child { border-left: 8px solid rgb(185, 35, 233); } -.block-CostColor3:last-child { border-left: 8px solid rgb(198, 40, 233); } -.block-CostColor2:last-child { border-left: 8px solid rgb(211, 45, 232); } -.block-CostColor1:last-child { border-left: 8px solid rgb(223, 50, 231); } -.block-CostColor0:last-child { border-left: 8px solid rgb(233, 89, 236); } -.block-CostColorNone { border-color: transparent; } +.block-CostColor0:first-child { border-left: 8px solid oklch(90.0% 0.05 140); } +.block-CostColor1:first-child { border-left: 8px solid oklch(87.4% 0.06 140); } +.block-CostColor2:first-child { border-left: 8px solid oklch(84.7% 0.06 140); } +.block-CostColor3:first-child { border-left: 8px solid oklch(82.1% 0.07 140); } +.block-CostColor4:first-child { border-left: 8px solid oklch(79.5% 0.07 140); } +.block-CostColor5:first-child { border-left: 8px solid oklch(76.8% 0.08 140); } +.block-CostColor6:first-child { border-left: 8px solid oklch(74.2% 0.08 140); } +.block-CostColor7:first-child { border-left: 8px solid oklch(71.6% 0.09 140); } +.block-CostColor8:first-child { border-left: 8px solid oklch(68.9% 0.09 140); } +.block-CostColor9:first-child { border-left: 8px solid oklch(66.3% 0.10 140); } +.block-CostColor10:first-child { border-left: 8px solid oklch(63.7% 0.10 140); } +.block-CostColor11:first-child { border-left: 8px solid oklch(61.1% 0.11 140); } +.block-CostColor12:first-child { border-left: 8px solid oklch(58.4% 0.11 140); } +.block-CostColor13:first-child { border-left: 8px solid oklch(55.8% 0.12 140); } +.block-CostColor14:first-child { border-left: 8px solid oklch(53.2% 0.12 140); } +.block-CostColor15:first-child { border-left: 8px solid oklch(50.5% 0.13 140); } +.block-CostColor16:first-child { border-left: 8px solid oklch(47.9% 0.13 140); } +.block-CostColor17:first-child { border-left: 8px solid oklch(45.3% 0.14 140); } +.block-CostColor18:first-child { border-left: 8px solid oklch(42.6% 0.14 140); } +.block-CostColor19:first-child { border-left: 8px solid oklch(40.0% 0.15 140); } +.block-CostColorNone:first-child { border-left: transparent; } + +.line-CostColor0:first-child { border-right: 8px solid oklch(90.0% 0.05 140); } +.line-CostColor1:first-child { border-right: 8px solid oklch(87.4% 0.06 140); } +.line-CostColor2:first-child { border-right: 8px solid oklch(84.7% 0.06 140); } +.line-CostColor3:first-child { border-right: 8px solid oklch(82.1% 0.07 140); } +.line-CostColor4:first-child { border-right: 8px solid oklch(79.5% 0.07 140); } +.line-CostColor5:first-child { border-right: 8px solid oklch(76.8% 0.08 140); } +.line-CostColor6:first-child { border-right: 8px solid oklch(74.2% 0.08 140); } +.line-CostColor7:first-child { border-right: 8px solid oklch(71.6% 0.09 140); } +.line-CostColor8:first-child { border-right: 8px solid oklch(68.9% 0.09 140); } +.line-CostColor9:first-child { border-right: 8px solid oklch(66.3% 0.10 140); } +.line-CostColor10:first-child { border-right: 8px solid oklch(63.7% 0.10 140); } +.line-CostColor11:first-child { border-right: 8px solid oklch(61.1% 0.11 140); } +.line-CostColor12:first-child { border-right: 8px solid oklch(58.4% 0.11 140); } +.line-CostColor13:first-child { border-right: 8px solid oklch(55.8% 0.12 140); } +.line-CostColor14:first-child { border-right: 8px solid oklch(53.2% 0.12 140); } +.line-CostColor15:first-child { border-right: 8px solid oklch(50.5% 0.13 140); } +.line-CostColor16:first-child { border-right: 8px solid oklch(47.9% 0.13 140); } +.line-CostColor17:first-child { border-right: 8px solid oklch(45.3% 0.14 140); } +.line-CostColor18:first-child { border-right: 8px solid oklch(42.6% 0.14 140); } +.line-CostColor19:first-child { border-right: 8px solid oklch(40.0% 0.15 140); } +.line-CostColorNone:first-child { border-right: transparent; } +.block-CostColor0:last-child { border-left: 8px solid oklch(90.0% 0.05 300); } +.block-CostColor1:last-child { border-left: 8px solid oklch(87.4% 0.06 300); } +.block-CostColor2:last-child { border-left: 8px solid oklch(84.7% 0.06 300); } +.block-CostColor3:last-child { border-left: 8px solid oklch(82.1% 0.07 300); } +.block-CostColor4:last-child { border-left: 8px solid oklch(79.5% 0.07 300); } +.block-CostColor5:last-child { border-left: 8px solid oklch(76.8% 0.08 300); } +.block-CostColor6:last-child { border-left: 8px solid oklch(74.2% 0.08 300); } +.block-CostColor7:last-child { border-left: 8px solid oklch(71.6% 0.09 300); } +.block-CostColor8:last-child { border-left: 8px solid oklch(68.9% 0.09 300); } +.block-CostColor9:last-child { border-left: 8px solid oklch(66.3% 0.10 300); } +.block-CostColor10:last-child { border-left: 8px solid oklch(63.7% 0.10 300); } +.block-CostColor11:last-child { border-left: 8px solid oklch(61.1% 0.11 300); } +.block-CostColor12:last-child { border-left: 8px solid oklch(58.4% 0.11 300); } +.block-CostColor13:last-child { border-left: 8px solid oklch(55.8% 0.12 300); } +.block-CostColor14:last-child { border-left: 8px solid oklch(53.2% 0.12 300); } +.block-CostColor15:last-child { border-left: 8px solid oklch(50.5% 0.13 300); } +.block-CostColor16:last-child { border-left: 8px solid oklch(47.9% 0.13 300); } +.block-CostColor17:last-child { border-left: 8px solid oklch(45.3% 0.14 300); } +.block-CostColor18:last-child { border-left: 8px solid oklch(42.6% 0.14 300); } +.block-CostColor19:last-child { border-left: 8px solid oklch(40.0% 0.15 300); } +.block-CostColorNone:last-child { border-left: transparent; } + +.line-CostColor0:last-child { border-right: 8px solid oklch(90.0% 0.05 300); } +.line-CostColor1:last-child { border-right: 8px solid oklch(87.4% 0.06 300); } +.line-CostColor2:last-child { border-right: 8px solid oklch(84.7% 0.06 300); } +.line-CostColor3:last-child { border-right: 8px solid oklch(82.1% 0.07 300); } +.line-CostColor4:last-child { border-right: 8px solid oklch(79.5% 0.07 300); } +.line-CostColor5:last-child { border-right: 8px solid oklch(76.8% 0.08 300); } +.line-CostColor6:last-child { border-right: 8px solid oklch(74.2% 0.08 300); } +.line-CostColor7:last-child { border-right: 8px solid oklch(71.6% 0.09 300); } +.line-CostColor8:last-child { border-right: 8px solid oklch(68.9% 0.09 300); } +.line-CostColor9:last-child { border-right: 8px solid oklch(66.3% 0.10 300); } +.line-CostColor10:last-child { border-right: 8px solid oklch(63.7% 0.10 300); } +.line-CostColor11:last-child { border-right: 8px solid oklch(61.1% 0.11 300); } +.line-CostColor12:last-child { border-right: 8px solid oklch(58.4% 0.11 300); } +.line-CostColor13:last-child { border-right: 8px solid oklch(55.8% 0.12 300); } +.line-CostColor14:last-child { border-right: 8px solid oklch(53.2% 0.12 300); } +.line-CostColor15:last-child { border-right: 8px solid oklch(50.5% 0.13 300); } +.line-CostColor16:last-child { border-right: 8px solid oklch(47.9% 0.13 300); } +.line-CostColor17:last-child { border-right: 8px solid oklch(45.3% 0.14 300); } +.line-CostColor18:last-child { border-right: 8px solid oklch(42.6% 0.14 300); } +.line-CostColor19:last-child { border-right: 8px solid oklch(40.0% 0.15 300); } +.line-CostColorNone:last-child { border-right: transparent; } .NoChildCost { border-left: none !important; } +.line-CostColorNone.block-CostColorNone { outline: none; } + /* Below is the style for the Syntax Highlighting with speed-highlight. * It's adapted from the default style from: https://unpkg.com/@speed-highlight/core@1.1.11/dist/themes/default.css */ diff --git a/src/irvisualizer/html_template_StmtToHTML.js b/src/irvisualizer/html_template_StmtToHTML.js index d3db63c960ab..0a74d25c4b66 100644 --- a/src/irvisualizer/html_template_StmtToHTML.js +++ b/src/irvisualizer/html_template_StmtToHTML.js @@ -120,6 +120,28 @@ function collapseTab(index) { // eslint-disable-line no-unused-vars } pane.classList.toggle('collapsed-pane'); + if (index > 0) { // left resizer + var resizer = panes.firstElementChild; + for (var i = 0; i < index; ++i) { + resizer = resizer.nextElementSibling.nextElementSibling; + } + if (resizer !== null) { + var colRightBtn = resizer.firstElementChild.firstElementChild.nextElementSibling.firstElementChild; + colRightBtn.classList.toggle('active'); + } + } + + { // right resizer + var resizer = panes.firstElementChild; + for (var i = 0; i <= index; ++i) { + if (resizer !== null) resizer = resizer.nextElementSibling; + if (resizer !== null) resizer = resizer.nextElementSibling; + } + if (resizer !== null) { + var colLeftBtn = resizer.firstElementChild.firstElementChild.firstElementChild; + colLeftBtn.classList.toggle('active'); + } + } } function scrollToHostAsm(lno) { // eslint-disable-line no-unused-vars From 014a232fc1291ee69e61ebd701128c09bcf87196 Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Fri, 6 Oct 2023 14:09:45 +0200 Subject: [PATCH 22/22] Clang-format... --- src/StmtToHTML.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/StmtToHTML.cpp b/src/StmtToHTML.cpp index e5a0a095c507..ce90d645104b 100644 --- a/src/StmtToHTML.cpp +++ b/src/StmtToHTML.cpp @@ -1330,9 +1330,9 @@ class HTMLCodePrinter : public IRVisitor { // Prints a cost button/indicator void print_cost_btn(int line_cost, int block_cost, int max_line_cost, int max_block_cost, std::string id, std::string prefix) { const int num_cost_buckets = 20; - const auto compand = [](int v) -> int { return (int) std::sqrt(v * 10); }; + const auto compand = [](int v) -> int { return (int)std::sqrt(v * 10); }; - int max_cost = std::max(max_line_cost, max_block_cost); // This should always be the block cost. + int max_cost = std::max(max_line_cost, max_block_cost); // This should always be the block cost. int line_cost_bin_size = (compand(max_cost) / num_cost_buckets) + 1; int block_cost_bin_size = (compand(max_cost) / num_cost_buckets) + 1;