From dba94873246ba71c40fbe98e6a06e23d6d59ee86 Mon Sep 17 00:00:00 2001 From: drisspg Date: Mon, 20 Mar 2023 01:27:44 +0000 Subject: [PATCH] Add helpful pretty pretting summaries to torch for lldb debugging (#97101) # Summary Add support for pretty printing of tensors when using lldb similiar to what is currently available for gdb Screenshot 2023-03-18 at 6 20 34 PM Screenshot 2023-03-18 at 6 20 43 PM I changed it so to override the variable formatting instead of having to call a seperate command you can just do `print ` I also add one for sizes Screenshot 2023-03-19 at 1 05 49 PM Last one: Screenshot 2023-03-19 at 1 39 23 PM If you use the codelldb extension be sure to add: `"lldb.launch.initCommands": ["command source ${env:HOME}/.lldbinit"]` To your setttings .json Pull Request resolved: https://github.com/pytorch/pytorch/pull/97101 Approved by: https://github.com/ngimel --- .lldbinit | 17 +++++++ tools/lldb/pytorch_lldb.py | 97 ++++++++++++++++++++++++++++++++++++++ torch/csrc/utils.cpp | 12 +++++ 3 files changed, 126 insertions(+) create mode 100644 .lldbinit create mode 100644 tools/lldb/pytorch_lldb.py diff --git a/.lldbinit b/.lldbinit new file mode 100644 index 000000000000..8af4aae10c3c --- /dev/null +++ b/.lldbinit @@ -0,0 +1,17 @@ +# automatically load the pytorch_lldb extension. +# +# lldb automatically tries to load this file whenever it is executed from the +# root of the pytorch repo, but by default it is not allowed to do so due to +# security reasons. If you want to use pytorch_lldb, please add the following +# line to your ~/.lldbinit (i.e., the .lldbinit file which is in your home +# directory, NOT this file): +# settings set target.load-cwd-lldbinit true +# setting set escape-non-printables false +# +# Alternatively, you can manually load the pytorch_lldb commands into your +# existing lldb session by doing the following: +# (lldb) command script import tools/lldb/pytorch_lldb.py + +command script import tools/lldb/pytorch_lldb.py +setting set escape-non-printables false +type category enable torch diff --git a/tools/lldb/pytorch_lldb.py b/tools/lldb/pytorch_lldb.py new file mode 100644 index 000000000000..4907bc1e6854 --- /dev/null +++ b/tools/lldb/pytorch_lldb.py @@ -0,0 +1,97 @@ +from typing import Any + +import lldb # type: ignore[import] + + +def get_target() -> Any: + target = lldb.debugger.GetSelectedTarget() + if not target: + print("[-] error: no target available. please add a target to lldb.") + return None + return target + + +class DisableBreakpoints: + """ + Context-manager to temporarily disable all lldb breakpoints, useful if + there is a risk to hit one during the evaluation of one of our custom + commands + """ + + def __enter__(self) -> None: + target = get_target() + + if target.DisableAllBreakpoints() is False: + print("[-] error: failed to disable all breakpoints.") + + def __exit__(self, etype: Any, evalue: Any, tb: Any) -> None: + target = get_target() + + if target.EnableAllBreakpoints() is False: + print("[-] error: failed to enable all breakpoints.") + + +def IntArrayRef_summary(valobj: Any, internal_dict: Any, options: Any) -> str: + """Print human readable representation of c10::IntArrayRef""" + with DisableBreakpoints(): + target = get_target() + tensor = valobj.GetName() + result = target.EvaluateExpression( + f"torch::gdb::int_array_ref_string({tensor})" + ) + str_result = str(result) + str_result = str_result[str_result.find('"') + 1 : -1] + return str_result + + +def DispatchKeyset_summary(valobj: Any, internal_dict: Any, options: Any) -> str: + """Print human readable representation of c10::DispatchKeyset""" + with DisableBreakpoints(): + target = get_target() + keyset = valobj.GetName() + result = target.EvaluateExpression( + f"torch::gdb::dispatch_keyset_string({keyset})" + ) + str_result = str(result) + str_result = str_result[str_result.find('"') + 1 : -1] + return str_result + + +def Tensor_summary(valobj: Any, internal_dict: Any, options: Any) -> str: + """Print a human readable representation of the given at::Tensor. + + at::Tensor instances do not have a C++ implementation of a repr method: in + pytorch, this is done by pure-Python code. As such, print + internally creates a Python wrapper for the given tensor and call repr() + on it. + Usage: + print self + """ + with DisableBreakpoints(): + target = get_target() + tensor = valobj.GetName() + result = target.EvaluateExpression(f"torch::gdb::tensor_repr({tensor})") + str_result = str(result) + target.EvaluateExpression(f"(void)free({result.GetValue()})") + str_result = "\n" + str_result[str_result.find("tensor") : -1] + return str_result + + +# And the initialization code to add your commands +def __lldb_init_module(debugger: Any, internal_dict: Any) -> Any: + debugger.HandleCommand( + "type summary add c10::IntArrayRef -F pytorch_lldb.IntArrayRef_summary -w torch" + ) + debugger.HandleCommand( + "type summary add c10::DispatchKeySet -F pytorch_lldb.DispatchKeyset_summary -w torch" + ) + debugger.HandleCommand( + "type summary add at::Tensor -F pytorch_lldb.Tensor_summary -w torch" + ) + print( + "Pretty Printing lldb summary for PyTorch AT types has been installed and is ready for use. " + "This category is enabled by default. To disable run: `type category disable torch`" + ) + print( + "Usage:\n\tprint \n\tprint \n\tprint " + ) diff --git a/torch/csrc/utils.cpp b/torch/csrc/utils.cpp index ec2762de53e7..8b8a3d668d01 100644 --- a/torch/csrc/utils.cpp +++ b/torch/csrc/utils.cpp @@ -305,6 +305,18 @@ error: return nullptr; } +std::string int_array_ref_string(at::IntArrayRef sizes) { + std::stringstream ss; + ss << sizes; + return ss.str(); +} + +std::string dispatch_keyset_string(c10::DispatchKeySet keyset) { + std::stringstream ss; + ss << keyset; + return ss.str(); +} + } // namespace gdb } // namespace torch