diff options
| -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"/> |
