diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2024-04-18 16:07:52 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2024-04-22 18:58:26 +0000 |
commit | 6c02ef8fc04b76ec3a4fb13e3f24f4fc30fb4c86 (patch) | |
tree | 2857b4f963cbc5ba235d808b79de8841fe99fa52 | |
parent | a85e7f01864ddc77e095ac3eeb668c530db00aad (diff) |
shibokenmodule: Expose dumpTypeGraph(), dumpWrapperMap() from the binding manager
This is helpful for gaining some insight into the instantiated
wrappers and registered types.
Move the existing graph generating code out of the graph class
and format the nodes with a short name and tooltip and expose it
as dumpTypeGraph().
Similarly, rewrite expose showWrapperMap() to use streams and
expose it as dumpWrapperMap().
Change-Id: I5cff442b7285388403dcf1c9f96fa8808c7b2d05
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
(cherry picked from commit 193769216f60f87feb20bbffa832cc159bbe525c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | sources/shiboken6/doc/shibokenmodule.rst | 9 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/bindingmanager.cpp | 107 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/bindingmanager.h | 3 | ||||
-rw-r--r-- | sources/shiboken6/shibokenmodule/shibokenmodule.cpp | 9 | ||||
-rw-r--r-- | sources/shiboken6/shibokenmodule/typesystem_shiboken.xml | 8 |
5 files changed, 102 insertions, 34 deletions
diff --git a/sources/shiboken6/doc/shibokenmodule.rst b/sources/shiboken6/doc/shibokenmodule.rst index b31efbcd1..2f1c6d166 100644 --- a/sources/shiboken6/doc/shibokenmodule.rst +++ b/sources/shiboken6/doc/shibokenmodule.rst @@ -116,6 +116,15 @@ To import the module: This method should be used **only** for debug purposes by developers. + .. function:: dumpTypeGraph(file_name) + + Dumps the inheritance graph of the types existing in libshiboken + to ``.dot`` file for use with `Graphviz <https://graphviz.org/>`_. + +.. function:: dumpWrapperMap() + + Dumps the map of wrappers existing in libshiboken to standard error. + .. py:class:: VoidPtr(address, size = -1, writeable = 0) :param address: (PyBuffer, SbkObject, int, VoidPtr) diff --git a/sources/shiboken6/libshiboken/bindingmanager.cpp b/sources/shiboken6/libshiboken/bindingmanager.cpp index a0acc4e4b..7542e60b8 100644 --- a/sources/shiboken6/libshiboken/bindingmanager.cpp +++ b/sources/shiboken6/libshiboken/bindingmanager.cpp @@ -15,8 +15,11 @@ #include <cstddef> #include <cstring> #include <fstream> +#include <iostream> #include <mutex> +#include <string_view> #include <unordered_map> +#include <unordered_set> namespace Shiboken { @@ -27,6 +30,8 @@ class Graph { public: using NodeList = std::vector<PyTypeObject *>; + using NodeSet = std::unordered_set<const PyTypeObject *>; + using Edges = std::unordered_map<PyTypeObject *, NodeList>; Edges m_edges; @@ -38,25 +43,8 @@ public: m_edges[from].push_back(to); } -#ifndef NDEBUG - void dumpDotGraph() const - { - std::ofstream file("/tmp/shiboken_graph.dot"); - - file << "digraph D {\n"; - - for (const auto &p : m_edges) { - auto *node1 = p.first; - const NodeList &nodeList = p.second; - for (const PyTypeObject *o : nodeList) { - auto *node2 = o; - file << '"' << node2->tp_name << "\" -> \"" - << node1->tp_name << "\"\n"; - } - } - file << "}\n"; - } -#endif + bool dumpTypeGraph(const char *fileName) const; + NodeSet nodeSet() const; PyTypeObject *identifyType(void **cptr, PyTypeObject *type, PyTypeObject *baseType) const { @@ -85,24 +73,53 @@ public: } }; +static void formatDotNode(const char *nameC, std::ostream &file) +{ + std::string_view name(nameC); + auto lastDot = name.rfind('.'); + file << " \"" << name << "\" [ label="; + if (lastDot != std::string::npos) { + file << '"' << name.substr(lastDot + 1) << "\" tooltip=\"" + << name.substr(0, lastDot) << '"'; + } else { + file << '"' << name << '"'; + } + file << " ]\n"; +} -#ifndef NDEBUG -static void showWrapperMap(const WrapperMap &wrapperMap) +Graph::NodeSet Graph::nodeSet() const { - if (Shiboken::pyVerbose() > 0) { - fprintf(stderr, "-------------------------------\n"); - fprintf(stderr, "WrapperMap: %p (size: %d)\n", &wrapperMap, (int) wrapperMap.size()); - for (auto it = wrapperMap.begin(), end = wrapperMap.end(); it != end; ++it) { - const SbkObject *sbkObj = it->second; - fprintf(stderr, "key: %p, value: %p (%s, refcnt: %d)\n", it->first, - static_cast<const void *>(sbkObj), - (Py_TYPE(sbkObj))->tp_name, - int(Py_REFCNT(reinterpret_cast<const PyObject *>(sbkObj)))); - } - fprintf(stderr, "-------------------------------\n"); + NodeSet result; + for (const auto &p : m_edges) { + result.insert(p.first); + for (const PyTypeObject *node2 : p.second) + result.insert(node2); } + return result; +} + +bool Graph::dumpTypeGraph(const char *fileName) const +{ + std::ofstream file(fileName); + if (!file.good()) + return false; + + file << "digraph D {\n"; + + // Define nodes with short names + for (const auto *node : nodeSet()) + formatDotNode(node->tp_name, file); + + // Write edges + for (const auto &p : m_edges) { + auto *node1 = p.first; + const NodeList &nodeList = p.second; + for (const PyTypeObject *node2 : nodeList) + file << " \"" << node2->tp_name << "\" -> \"" << node1->tp_name << "\"\n"; + } + file << "}\n"; + return true; } -#endif struct BindingManager::BindingManagerPrivate { using DestructorEntries = std::vector<DestructorEntry>; @@ -189,7 +206,8 @@ BindingManager::~BindingManager() debugRemoveFreeHook(); #endif #ifndef NDEBUG - showWrapperMap(m_d->wrapperMapper); + if (Shiboken::pyVerbose() > 0) + dumpWrapperMap(); #endif /* Cleanup hanging references. We just invalidate them as when * the BindingManager is being destroyed the interpreter is alredy @@ -395,6 +413,27 @@ void BindingManager::visitAllPyObjects(ObjectVisitor visitor, void *data) } } +bool BindingManager::dumpTypeGraph(const char *fileName) const +{ + return m_d->classHierarchy.dumpTypeGraph(fileName); +} + +void BindingManager::dumpWrapperMap() +{ + const auto &wrapperMap = m_d->wrapperMapper; + std::cerr << "-------------------------------\n" + << "WrapperMap size: " << wrapperMap.size() << " Types: " + << m_d->classHierarchy.nodeSet().size() << '\n'; + for (auto it = wrapperMap.begin(), end = wrapperMap.end(); it != end; ++it) { + const SbkObject *sbkObj = it->second; + std::cerr << "key: " << it->first << ", value: " + << static_cast<const void *>(sbkObj) << " (" + << (Py_TYPE(sbkObj))->tp_name << ", refcnt: " + << Py_REFCNT(reinterpret_cast<const PyObject *>(sbkObj)) << ")\n"; + } + std::cerr << "-------------------------------\n"; +} + static bool isPythonType(PyTypeObject *type) { // This is a type which should be called by multiple inheritance. diff --git a/sources/shiboken6/libshiboken/bindingmanager.h b/sources/shiboken6/libshiboken/bindingmanager.h index 4b21ae835..47db14975 100644 --- a/sources/shiboken6/libshiboken/bindingmanager.h +++ b/sources/shiboken6/libshiboken/bindingmanager.h @@ -59,6 +59,9 @@ public: */ void visitAllPyObjects(ObjectVisitor visitor, void *data); + bool dumpTypeGraph(const char *fileName) const; + void dumpWrapperMap(); + private: ~BindingManager(); BindingManager(); diff --git a/sources/shiboken6/shibokenmodule/shibokenmodule.cpp b/sources/shiboken6/shibokenmodule/shibokenmodule.cpp index 6feca9ea8..b3adfe78b 100644 --- a/sources/shiboken6/shibokenmodule/shibokenmodule.cpp +++ b/sources/shiboken6/shibokenmodule/shibokenmodule.cpp @@ -91,6 +91,15 @@ for (auto *o : setAll) { return listAll; // @snippet getallvalidwrappers +// @snippet dumptypegraph +const bool ok = Shiboken::BindingManager::instance().dumpTypeGraph(%1); +%PYARG_0 = %CONVERTTOPYTHON[bool](ok); +// @snippet dumptypegraph + +// @snippet dumpwrappermap +Shiboken::BindingManager::instance().dumpWrapperMap(); +// @snippet dumpwrappermap + // @snippet init // Add __version__ and __version_info__ attributes to the module PyObject* version = PyTuple_New(5); diff --git a/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml b/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml index 2288ca7a4..aa08a8bbf 100644 --- a/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml +++ b/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml @@ -49,6 +49,14 @@ <inject-code file="shibokenmodule.cpp" snippet="getallvalidwrappers"/> </add-function> + <add-function signature="dumpTypeGraph(const char *@fileName@)" return-type="bool"> + <inject-code file="shibokenmodule.cpp" snippet="dumptypegraph"/> + </add-function> + + <add-function signature="dumpWrapperMap()"> + <inject-code file="shibokenmodule.cpp" snippet="dumpwrappermap"/> + </add-function> + <extra-includes> <include file-name="sbkversion.h" location="local"/> <include file-name="voidptr.h" location="local"/> |