Skip to content

Commit 072a5c1

Browse files
authored
[TVMScript] Optionally output the address as part of variable names (apache#15579)
* [TVMScript] Optionally output the address as part of variable names When debugging IRModule transformations, it can be useful to know the exact C++ address of an object. For example, to determine whether an undefined TIR variable was caused by erroneous insertion of a new variable, or from failing to remove a previous variable. While TVMScript does de-duplicate all names within a single print statement, there isn't a convenient way to identify which variable in TVMScript corresponds to a specific variable in C++ logging statements. This commit adds `show_object_address` to the `PrinterConfig`. If false (the default), no change is made to the TVMScript variable names. If true, the address of the C++ object is appended to the variable name. For example, printing a `tir.Var('my_name','int64')` as `"my_name_0x1234abcd"`. * Updated unit test to target TVM main The `private=True` branch is only on the unity branch.
1 parent 63b0c8f commit 072a5c1

File tree

5 files changed

+68
-1
lines changed

5 files changed

+68
-1
lines changed

include/tvm/node/script_printer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ class PrinterConfigNode : public Object {
6868
int num_context_lines = -1;
6969
/*! \brief Whether to output with syntax sugar, set false for complete printing. */
7070
bool syntax_sugar = true;
71+
/*! \brief Whether variable names should include the object's address */
72+
bool show_object_address = false;
7173
/* \brief Object path to be underlined */
7274
Array<ObjectPath> path_to_underline = Array<ObjectPath>();
7375
/*! \brief Object path to be annotated. */
@@ -91,6 +93,7 @@ class PrinterConfigNode : public Object {
9193
v->Visit("print_line_numbers", &print_line_numbers);
9294
v->Visit("num_context_lines", &num_context_lines);
9395
v->Visit("syntax_sugar", &syntax_sugar);
96+
v->Visit("show_object_address", &show_object_address);
9497
v->Visit("path_to_underline", &path_to_underline);
9598
v->Visit("path_to_annotate", &path_to_annotate);
9699
v->Visit("obj_to_underline", &obj_to_underline);

python/tvm/runtime/script_printer.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class PrinterConfig(Object):
4040
print_line_numbers: bool
4141
num_context_lines: int
4242
syntax_sugar: bool
43+
show_object_address: bool
4344
path_to_underline: Optional[List[ObjectPath]]
4445
path_to_annotate: Optional[Dict[ObjectPath, str]]
4546
obj_to_underline: Optional[List[Object]]
@@ -60,6 +61,7 @@ def __init__(
6061
print_line_numbers: bool = False,
6162
num_context_lines: Optional[int] = None,
6263
syntax_sugar: bool = True,
64+
show_object_address: bool = True,
6365
path_to_underline: Optional[List[ObjectPath]] = None,
6466
path_to_annotate: Optional[Dict[ObjectPath, str]] = None,
6567
obj_to_underline: Optional[List[Object]] = None,
@@ -79,6 +81,7 @@ def __init__(
7981
"print_line_numbers": print_line_numbers,
8082
"num_context_lines": num_context_lines,
8183
"syntax_sugar": syntax_sugar,
84+
"show_object_address": show_object_address,
8285
"path_to_underline": path_to_underline,
8386
"path_to_annotate": path_to_annotate,
8487
"obj_to_underline": obj_to_underline,
@@ -119,6 +122,7 @@ def script(
119122
print_line_numbers: bool = False,
120123
num_context_lines: int = -1,
121124
syntax_sugar: bool = True,
125+
show_object_address: bool = False,
122126
path_to_underline: Optional[List[ObjectPath]] = None,
123127
path_to_annotate: Optional[Dict[ObjectPath, str]] = None,
124128
obj_to_underline: Optional[List[Object]] = None,
@@ -153,6 +157,8 @@ def script(
153157
The number of lines of context to print before and after the line to underline.
154158
syntax_sugar: bool = True
155159
Whether to output with syntax sugar, set false for complete printing.
160+
show_object_address: bool = False
161+
Whether to include the object's adddress as part of the TVMScript name
156162
path_to_underline : Optional[List[ObjectPath]] = None
157163
Object path to be underlined
158164
path_to_annotate : Optional[Dict[ObjectPath, str]] = None
@@ -182,6 +188,7 @@ def script(
182188
print_line_numbers=print_line_numbers,
183189
num_context_lines=num_context_lines,
184190
syntax_sugar=syntax_sugar,
191+
show_object_address=show_object_address,
185192
path_to_underline=path_to_underline,
186193
path_to_annotate=path_to_annotate,
187194
obj_to_underline=obj_to_underline,
@@ -206,6 +213,7 @@ def show(
206213
print_line_numbers: bool = False,
207214
num_context_lines: int = -1,
208215
syntax_sugar: bool = True,
216+
show_object_address: bool = True,
209217
path_to_underline: Optional[List[ObjectPath]] = None,
210218
path_to_annotate: Optional[Dict[ObjectPath, str]] = None,
211219
obj_to_underline: Optional[List[Object]] = None,
@@ -245,6 +253,8 @@ def show(
245253
The number of lines of context to print before and after the line to underline.
246254
syntax_sugar: bool = True
247255
Whether to output with syntax sugar, set false for complete printing.
256+
show_object_address: bool = False
257+
Whether to include the object's adddress as part of the TVMScript name
248258
path_to_underline : Optional[List[ObjectPath]] = None
249259
Object path to be underlined
250260
path_to_annotate : Optional[Dict[ObjectPath, str]] = None
@@ -272,6 +282,7 @@ def show(
272282
print_line_numbers=print_line_numbers,
273283
num_context_lines=num_context_lines,
274284
syntax_sugar=syntax_sugar,
285+
show_object_address=show_object_address,
275286
path_to_underline=path_to_underline,
276287
path_to_annotate=path_to_annotate,
277288
obj_to_underline=obj_to_underline,

src/node/script_printer.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ PrinterConfig::PrinterConfig(Map<String, ObjectRef> config_dict) {
8888
if (auto v = config_dict.Get("syntax_sugar")) {
8989
n->syntax_sugar = Downcast<IntImm>(v)->value;
9090
}
91+
if (auto v = config_dict.Get("show_object_address")) {
92+
n->show_object_address = Downcast<IntImm>(v)->value;
93+
}
94+
9195
this->data_ = std::move(n);
9296
}
9397

src/script/printer/ir_docsifier.cc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include <tvm/runtime/registry.h>
2222
#include <tvm/script/printer/ir_docsifier.h>
2323

24+
#include <sstream>
25+
2426
#include "./utils.h"
2527

2628
namespace tvm {
@@ -29,7 +31,13 @@ namespace printer {
2931

3032
IdDoc IRDocsifierNode::Define(const ObjectRef& obj, const Frame& frame, const String& name_hint) {
3133
ICHECK(obj2info.find(obj) == obj2info.end()) << "Duplicated object: " << obj;
32-
String name = GenerateUniqueName(name_hint, this->defined_names);
34+
String name = name_hint;
35+
if (cfg->show_object_address) {
36+
std::stringstream stream;
37+
stream << name << "_" << obj.get();
38+
name = stream.str();
39+
}
40+
name = GenerateUniqueName(name, this->defined_names);
3341
this->defined_names.insert(name);
3442
DocCreator doc_factory = [name]() { return IdDoc(name); };
3543
obj2info.insert({obj, VariableInfo{std::move(doc_factory), name}});

tests/python/unittest/test_tvmscript_printer_tir.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717
# pylint: disable=missing-docstring
18+
19+
import re
20+
1821
import tvm.testing
1922
from tvm import ir, tir
2023
from tvm.ir import Range
@@ -841,5 +844,43 @@ def func(A: T.Buffer((128, 128), "float32"), B: T.Buffer((256, 256), "float32"))
841844
_assert_print(main, expected_output)
842845

843846

847+
def test_variable_with_cpp_address():
848+
"""The show_object_address option displays the C++ addressess
849+
850+
Because the C++ address may vary with each execution, the output
851+
produced with this option cannot be compared to a fixed string.
852+
Instead, this test uses the normal script output to generate a
853+
regular expression against with the test output must match. The
854+
regular expression validates that all names have been appended
855+
with "_0x" followed by a hexadecimal number, and that the address
856+
is the same for each variable.
857+
"""
858+
from tvm.script import tir as T
859+
860+
# The test function has all named objects suffixed with "_name",
861+
# to avoid spurious replacement when generating the expected
862+
# regex.
863+
@T.prim_func
864+
def func(a_name: T.handle):
865+
N_name = T.int64()
866+
A_name = T.match_buffer(a_name, N_name, "float32")
867+
for i_name in range(N_name):
868+
A_name[i_name] = A_name[i_name] + 1.0
869+
870+
without_address = func.script(show_object_address=False)
871+
script = func.script(show_object_address=True)
872+
873+
expected_regex = re.escape(without_address)
874+
for name in ["a_name", "A_name", "N_name", "i_name"]:
875+
# Replace all occurrences with a backref to an earlier match
876+
expected_regex = expected_regex.replace(name, rf"(?P={name})")
877+
# Then replace the first such backref with a capturing group.
878+
expected_regex = expected_regex.replace(
879+
rf"(?P={name})", rf"(?P<{name}>{name}_0x[A-Fa-f0-9]+)", 1
880+
)
881+
882+
assert re.match(expected_regex, script)
883+
884+
844885
if __name__ == "__main__":
845886
tvm.testing.main()

0 commit comments

Comments
 (0)