summaryrefslogtreecommitdiffstats
path: root/src/debug
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:24:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:24:48 +0000
commitcca66b9ec4e494c1d919bff0f71a820d8afab1fa (patch)
tree146f39ded1c938019e1ed42d30923c2ac9e86789 /src/debug
parentInitial commit. (diff)
downloadinkscape-cca66b9ec4e494c1d919bff0f71a820d8afab1fa.tar.xz
inkscape-cca66b9ec4e494c1d919bff0f71a820d8afab1fa.zip
Adding upstream version 1.2.2.upstream/1.2.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/debug')
-rw-r--r--src/debug/CMakeLists.txt29
-rw-r--r--src/debug/demangle.cpp60
-rw-r--r--src/debug/demangle.h39
-rw-r--r--src/debug/event-tracker.h236
-rw-r--r--src/debug/event.h81
-rw-r--r--src/debug/gc-heap.h53
-rw-r--r--src/debug/gdk-event-latency-tracker.cpp81
-rw-r--r--src/debug/gdk-event-latency-tracker.h57
-rw-r--r--src/debug/heap.cpp62
-rw-r--r--src/debug/heap.h63
-rw-r--r--src/debug/log-display-config.cpp79
-rw-r--r--src/debug/log-display-config.h36
-rw-r--r--src/debug/logger.cpp231
-rw-r--r--src/debug/logger.h247
-rw-r--r--src/debug/simple-event.h87
-rw-r--r--src/debug/sysv-heap.cpp84
-rw-r--r--src/debug/sysv-heap.h48
-rw-r--r--src/debug/timestamp.cpp46
-rw-r--r--src/debug/timestamp.h39
19 files changed, 1658 insertions, 0 deletions
diff --git a/src/debug/CMakeLists.txt b/src/debug/CMakeLists.txt
new file mode 100644
index 0000000..954df1f
--- /dev/null
+++ b/src/debug/CMakeLists.txt
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+set(debug_SRC
+ demangle.cpp
+ heap.cpp
+ log-display-config.cpp
+ logger.cpp
+ sysv-heap.cpp
+ timestamp.cpp
+ gdk-event-latency-tracker.cpp
+
+
+ # ------
+ # Header
+ demangle.h
+ event-tracker.h
+ event.h
+ gc-heap.h
+ gdk-event-latency-tracker.h
+ heap.h
+ log-display-config.h
+ logger.h
+ simple-event.h
+ sysv-heap.h
+ timestamp.h
+)
+
+# add_inkscape_lib(debug_LIB "${debug_SRC}")
+add_inkscape_source("${debug_SRC}")
diff --git a/src/debug/demangle.cpp b/src/debug/demangle.cpp
new file mode 100644
index 0000000..abf046b
--- /dev/null
+++ b/src/debug/demangle.cpp
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::demangle - demangle C++ symbol names
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2006 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <boost/core/demangle.hpp>
+#include <cstring>
+#include <map>
+#include <memory>
+#include <string>
+#include "debug/demangle.h"
+
+namespace Inkscape {
+
+namespace Debug {
+
+namespace {
+
+struct string_less_than {
+ bool operator()(char const *a, char const *b) const {
+ return ( strcmp(a, b) < 0 );
+ }
+};
+
+typedef std::map<char const *, std::shared_ptr<std::string>, string_less_than> MangleCache;
+MangleCache mangle_cache;
+
+}
+
+std::shared_ptr<std::string> demangle(char const *name) {
+ MangleCache::iterator found=mangle_cache.find(name);
+ if ( found != mangle_cache.end() ) {
+ return (*found).second;
+ }
+
+ std::string result = boost::core::demangle(name);
+ return mangle_cache[name] = std::make_shared<std::string>(result);
+}
+
+}
+
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/demangle.h b/src/debug/demangle.h
new file mode 100644
index 0000000..ba747cd
--- /dev/null
+++ b/src/debug/demangle.h
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::demangle - demangle C++ symbol names
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2006 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SEEN_INKSCAPE_DEBUG_DEMANGLE_H
+#define SEEN_INKSCAPE_DEBUG_DEMANGLE_H
+
+#include <memory>
+#include <string>
+
+namespace Inkscape {
+
+namespace Debug {
+
+std::shared_ptr<std::string> demangle(char const *name);
+
+}
+
+}
+
+#endif
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/event-tracker.h b/src/debug/event-tracker.h
new file mode 100644
index 0000000..a728bac
--- /dev/null
+++ b/src/debug/event-tracker.h
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::EventTracker - semi-automatically track event lifetimes
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2005 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SEEN_INKSCAPE_DEBUG_EVENT_TRACKER_H
+#define SEEN_INKSCAPE_DEBUG_EVENT_TRACKER_H
+
+#include "debug/logger.h"
+
+namespace Inkscape {
+
+namespace Debug {
+
+#ifdef NDEBUG
+// Make event tracking a no-op for non-debug builds
+template <typename = void> struct EventTracker {
+ template <typename... Args> EventTracker(Args &&...) {}
+ template <typename, typename... Args> void set(Args &&...) {}
+ void clear() {}
+};
+#else
+
+struct NoInitialEvent {};
+
+template <typename Event=NoInitialEvent> class EventTracker;
+
+class EventTrackerBase {
+public:
+ virtual ~EventTrackerBase() {
+ if (_active) {
+ Logger::finish();
+ }
+ }
+
+ template <typename EventType>
+ inline void set() {
+ if (_active) {
+ Logger::finish();
+ }
+ Logger::start<EventType>();
+ _active = true;
+ }
+
+ template <typename EventType, typename A>
+ inline void set(A const &a) {
+ if (_active) {
+ Logger::finish();
+ }
+ Logger::start<EventType>(a);
+ _active = true;
+ }
+
+ template <typename EventType, typename A, typename B>
+ inline void set(A const &a, B const &b) {
+ if (_active) {
+ Logger::finish();
+ }
+ Logger::start<EventType>(a, b);
+ _active = true;
+ }
+
+ template <typename EventType, typename A, typename B, typename C>
+ inline void set(A const &a, B const &b, C const &c) {
+ if (_active) {
+ Logger::finish();
+ }
+ Logger::start<EventType>(a, b, c);
+ _active = true;
+ }
+
+ template <typename EventType, typename A, typename B,
+ typename C, typename D>
+ inline void set(A const &a, B const &b, C const &c, D const &d) {
+ if (_active) {
+ Logger::finish();
+ }
+ Logger::start<EventType>(a, b, c, d);
+ _active = true;
+ }
+
+ template <typename EventType, typename A, typename B, typename C,
+ typename D, typename E>
+ inline void set(A const &a, B const &b, C const &c, D const &d, E const &e)
+ {
+ if (_active) {
+ Logger::finish();
+ }
+ Logger::start<EventType>(a, b, c, d, e);
+ _active = true;
+ }
+
+ template <typename EventType, typename A, typename B, typename C,
+ typename D, typename E, typename F>
+ inline void set(A const &a, B const &b, C const &c,
+ D const &d, E const &e, F const &f)
+ {
+ if (_active) {
+ Logger::finish();
+ }
+ Logger::start<EventType>(a, b, c, d, e, f);
+ _active = true;
+ }
+
+ template <typename EventType, typename A, typename B, typename C,
+ typename D, typename E, typename F,
+ typename G>
+ inline void set(A const &a, B const &b, C const &c, D const &d,
+ E const &e, F const &f, G const &g)
+ {
+ if (_active) {
+ Logger::finish();
+ }
+ Logger::start<EventType>(a, b, c, d, e, f, g);
+ _active = true;
+ }
+
+ template <typename EventType, typename A, typename B, typename C,
+ typename D, typename E, typename F,
+ typename G, typename H>
+ inline void set(A const &a, B const &b, C const &c, D const &d,
+ E const &e, F const &f, G const &g, H const &h)
+ {
+ if (_active) {
+ Logger::finish();
+ }
+ Logger::start<EventType>(a, b, c, d, e, f, g, h);
+ _active = true;
+ }
+
+ void clear() {
+ if (_active) {
+ Logger::finish();
+ _active = false;
+ }
+ }
+
+protected:
+ EventTrackerBase(bool active) : _active(active) {}
+
+private:
+ EventTrackerBase(EventTrackerBase const &) = delete; // no copy
+ void operator=(EventTrackerBase const &) = delete; // no assign
+ bool _active;
+};
+
+template <typename EventType> class EventTracker : public EventTrackerBase {
+public:
+ EventTracker() : EventTrackerBase(true) { Logger::start<EventType>(); }
+
+ template <typename A>
+ EventTracker(A const &a) : EventTrackerBase(true) {
+ Logger::start<EventType>(a);
+ }
+
+ template <typename A, typename B>
+ EventTracker(A const &a, B const &b) : EventTrackerBase(true) {
+ Logger::start<EventType>(a, b);
+ }
+
+ template <typename A, typename B, typename C>
+ EventTracker(A const &a, B const &b, C const &c) : EventTrackerBase(true) {
+ Logger::start<EventType>(a, b, c);
+ }
+
+ template <typename A, typename B, typename C, typename D>
+ EventTracker(A const &a, B const &b, C const &c, D const &d)
+ : EventTrackerBase(true)
+ {
+ Logger::start<EventType>(a, b, c, d);
+ }
+
+ template <typename A, typename B, typename C, typename D, typename E>
+ EventTracker(A const &a, B const &b, C const &c, D const &d, E const &e)
+ : EventTrackerBase(true)
+ {
+ Logger::start<EventType>(a, b, c, d, e);
+ }
+
+ template <typename A, typename B, typename C, typename D,
+ typename E, typename F>
+ EventTracker(A const &a, B const &b, C const &c, D const &d,
+ E const &e, F const &f)
+ : EventTrackerBase(true)
+ {
+ Logger::start<EventType>(a, b, c, d, e, f);
+ }
+
+ template <typename A, typename B, typename C, typename D,
+ typename E, typename F, typename G>
+ EventTracker(A const &a, B const &b, C const &c, D const &d,
+ E const &e, F const &f, G const &g)
+ : EventTrackerBase(true)
+ {
+ Logger::start<EventType>(a, b, c, d, e, f, g);
+ }
+
+ template <typename A, typename B, typename C, typename D,
+ typename E, typename F, typename G, typename H>
+ EventTracker(A const &a, B const &b, C const &c, D const &d,
+ E const &e, F const &f, G const &g, H const &h)
+ : EventTrackerBase(true)
+ {
+ Logger::start<EventType>(a, b, c, d, e, f, g, h);
+ }
+};
+
+template <> class EventTracker<NoInitialEvent> : public EventTrackerBase {
+public:
+ EventTracker() : EventTrackerBase(false) {}
+};
+
+#endif
+
+}
+
+}
+
+#endif
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/event.h b/src/debug/event.h
new file mode 100644
index 0000000..3bc6089
--- /dev/null
+++ b/src/debug/event.h
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::Event - event for debug tracing
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2005 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SEEN_INKSCAPE_DEBUG_EVENT_H
+#define SEEN_INKSCAPE_DEBUG_EVENT_H
+
+#include <memory>
+#include <string>
+#include <utility>
+
+namespace Inkscape {
+
+namespace Debug {
+
+class Event {
+public:
+ virtual ~Event() = default;
+
+ enum Category {
+ CORE=0,
+ XML,
+ SPOBJECT,
+ DOCUMENT,
+ REFCOUNT,
+ EXTENSION,
+ FINALIZERS,
+ INTERACTION,
+ CONFIGURATION,
+ OTHER
+ };
+ enum { N_CATEGORIES=OTHER+1 };
+
+ struct PropertyPair {
+ public:
+ PropertyPair() = default;
+ PropertyPair(char const *n, std::shared_ptr<std::string>&& v)
+ : name(n), value(std::move(v)) {}
+ PropertyPair(char const *n, char const *v)
+ : name(n),
+ value(std::make_shared<std::string>(v)) {}
+
+ char const *name;
+ std::shared_ptr<std::string> value;
+ };
+
+ static Category category() { return OTHER; }
+
+ // To reduce allocations, we assume the name here is always allocated statically and will never
+ // need to be deallocated. It would be nice to be able to assert that during the creation of
+ // the Event though.
+ virtual char const *name() const=0;
+ virtual unsigned propertyCount() const=0;
+ virtual PropertyPair property(unsigned property) const=0;
+
+ virtual void generateChildEvents() const=0;
+};
+
+}
+
+}
+
+#endif
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/gc-heap.h b/src/debug/gc-heap.h
new file mode 100644
index 0000000..e0fd8f1
--- /dev/null
+++ b/src/debug/gc-heap.h
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::GCHeap - heap statistics for libgc heap
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2004 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SEEN_INKSCAPE_DEBUG_GC_HEAP_H
+#define SEEN_INKSCAPE_DEBUG_GC_HEAP_H
+
+#include "inkgc/gc-core.h"
+#include "debug/heap.h"
+
+namespace Inkscape {
+namespace Debug {
+
+class GCHeap : public Debug::Heap {
+public:
+ int features() const override {
+ return SIZE_AVAILABLE | USED_AVAILABLE | GARBAGE_COLLECTED;
+ }
+ char const *name() const override {
+ return "libgc";
+ }
+ Heap::Stats stats() const override {
+ Stats stats;
+ stats.size = GC::Core::get_heap_size();
+ stats.bytes_used = stats.size - GC::Core::get_free_bytes();
+ return stats;
+ }
+ void force_collect() override { GC::Core::gcollect(); }
+};
+
+}
+}
+
+#endif
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/gdk-event-latency-tracker.cpp b/src/debug/gdk-event-latency-tracker.cpp
new file mode 100644
index 0000000..db93912
--- /dev/null
+++ b/src/debug/gdk-event-latency-tracker.cpp
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::GdkEventLatencyTracker - tracks backlog of GDK events
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2008 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <gdk/gdk.h>
+
+#include "debug/gdk-event-latency-tracker.h"
+#include "preferences.h"
+
+namespace Inkscape {
+namespace Debug {
+
+GdkEventLatencyTracker::GdkEventLatencyTracker()
+ : start_seconds(0.0), max_latency(0.0), skew(1.0), last_elapsed(0.0), last_seconds(0.0)
+{
+ elapsed.stop();
+ elapsed.reset();
+}
+
+std::optional<double> GdkEventLatencyTracker::process(GdkEvent const *event) {
+ guint32 const timestamp=gdk_event_get_time(const_cast<GdkEvent *>(event));
+ if (timestamp == GDK_CURRENT_TIME) {
+ return std::optional<double>();
+ }
+ double const timestamp_seconds = timestamp / 1000.0;
+
+ if (start_seconds == 0.0) {
+ elapsed.start();
+ start_seconds = timestamp_seconds;
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ skew = prefs->getDoubleLimited("/debug/latency/skew", 1.0, 0.5, 2.0);
+ return std::optional<double>(0.0);
+ } else {
+ last_elapsed = elapsed.elapsed();
+ last_seconds = timestamp_seconds;
+ double const current_seconds = (last_elapsed * skew) + start_seconds;
+ double delta = current_seconds - timestamp_seconds;
+ if (delta < 0.0) {
+ start_seconds += -delta;
+ delta = 0.0;
+ } else if (delta > max_latency) {
+ max_latency = delta;
+ }
+ return std::optional<double>(delta);
+ }
+}
+
+double GdkEventLatencyTracker::getSkew() {
+ double val = 0.0;
+ if ((last_elapsed > 0.0) && (last_seconds > 0.0)) {
+ val = (last_seconds - start_seconds) / last_elapsed;
+ }
+ return val;
+}
+
+GdkEventLatencyTracker &GdkEventLatencyTracker::default_tracker() {
+ static GdkEventLatencyTracker tracker;
+ return tracker;
+}
+
+}
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/gdk-event-latency-tracker.h b/src/debug/gdk-event-latency-tracker.h
new file mode 100644
index 0000000..569e53a
--- /dev/null
+++ b/src/debug/gdk-event-latency-tracker.h
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::GdkEventLatencyTracker - tracks backlog of GDK events
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2008 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SEEN_INKSCAPE_DEBUG_GDK_EVENT_LATENCY_TRACKER_H
+#define SEEN_INKSCAPE_DEBUG_GDK_EVENT_LATENCY_TRACKER_H
+
+typedef union _GdkEvent GdkEvent;
+#include <glibmm/timer.h>
+#include <optional>
+
+namespace Inkscape {
+namespace Debug {
+
+class GdkEventLatencyTracker {
+public:
+ GdkEventLatencyTracker();
+ std::optional<double> process(GdkEvent const *e);
+ double maxLatency() const { return max_latency; }
+ double getSkew();
+
+ static GdkEventLatencyTracker &default_tracker();
+
+private:
+ GdkEventLatencyTracker(GdkEventLatencyTracker const &) = delete; // no copy
+ void operator=(GdkEventLatencyTracker const &) = delete; // no assign
+
+ double start_seconds;
+ double max_latency;
+ double skew;
+ double last_elapsed;
+ double last_seconds;
+ Glib::Timer elapsed;
+};
+
+}
+}
+
+#endif
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/heap.cpp b/src/debug/heap.cpp
new file mode 100644
index 0000000..ce9cacf
--- /dev/null
+++ b/src/debug/heap.cpp
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::Heap - interface for gathering heap statistics
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2005 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "inkgc/gc-alloc.h"
+#include "debug/gc-heap.h"
+#include "debug/sysv-heap.h"
+#include <vector>
+
+namespace Inkscape {
+namespace Debug {
+
+namespace {
+
+typedef std::vector<Heap *, GC::Alloc<Heap *, GC::MANUAL> > HeapCollection;
+
+HeapCollection &heaps() {
+ static bool is_initialized=false;
+ static HeapCollection heaps;
+ if (!is_initialized) {
+ heaps.push_back(new SysVHeap());
+ heaps.push_back(new GCHeap());
+ is_initialized = true;
+ }
+ return heaps;
+}
+
+}
+
+unsigned heap_count() {
+ return heaps().size();
+}
+
+Heap *get_heap(unsigned i) {
+ return heaps()[i];
+}
+
+void register_extra_heap(Heap &heap) {
+ heaps().push_back(&heap);
+}
+
+}
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/heap.h b/src/debug/heap.h
new file mode 100644
index 0000000..81e7b73
--- /dev/null
+++ b/src/debug/heap.h
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::Heap - interface for gathering heap statistics
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2005 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SEEN_INKSCAPE_DEBUG_HEAP_H
+#define SEEN_INKSCAPE_DEBUG_HEAP_H
+
+#include <cstddef>
+
+namespace Inkscape {
+
+namespace Debug {
+
+class Heap {
+public:
+ virtual ~Heap() = default;
+
+ struct Stats {
+ std::size_t size;
+ std::size_t bytes_used;
+ };
+
+ enum {
+ SIZE_AVAILABLE = ( 1 << 0 ),
+ USED_AVAILABLE = ( 1 << 1 ),
+ GARBAGE_COLLECTED = ( 1 << 2 )
+ };
+
+ virtual int features() const=0;
+
+ virtual char const *name() const=0;
+ virtual Stats stats() const=0;
+ virtual void force_collect()=0;
+};
+
+unsigned heap_count();
+Heap *get_heap(unsigned i);
+
+void register_extra_heap(Heap &heap);
+
+}
+
+}
+
+#endif
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/log-display-config.cpp b/src/debug/log-display-config.cpp
new file mode 100644
index 0000000..7de69be
--- /dev/null
+++ b/src/debug/log-display-config.cpp
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::log_display_config - log display configuration
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2007 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <iostream>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include "debug/event-tracker.h"
+#include "debug/logger.h"
+#include "debug/simple-event.h"
+#include "debug/log-display-config.h"
+
+namespace Inkscape {
+
+namespace Debug {
+
+namespace {
+
+typedef SimpleEvent<Event::CONFIGURATION> ConfigurationEvent;
+
+class Monitor : public ConfigurationEvent {
+public:
+ Monitor(GdkMonitor *monitor)
+ : ConfigurationEvent("monitor")
+ {
+ GdkRectangle area;
+ gdk_monitor_get_geometry(monitor, &area);
+
+ _addProperty("x", area.x);
+ _addProperty("y", area.y);
+ _addProperty("width", area.width);
+ _addProperty("height", area.height);
+ }
+};
+
+class Display : public ConfigurationEvent {
+public:
+ Display() : ConfigurationEvent("display") {}
+ void generateChildEvents() const override {
+ GdkDisplay *display=gdk_display_get_default();
+
+ gint const n_monitors = gdk_display_get_n_monitors(display);
+
+ // Loop through all monitors and log their details
+ for (gint i_monitor = 0; i_monitor < n_monitors; ++i_monitor) {
+ GdkMonitor *monitor = gdk_display_get_monitor(display, i_monitor);
+ Logger::write<Monitor>(monitor);
+ }
+ }
+};
+
+}
+
+void log_display_config() {
+ Logger::write<Display>();
+}
+
+}
+
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/log-display-config.h b/src/debug/log-display-config.h
new file mode 100644
index 0000000..df9be18
--- /dev/null
+++ b/src/debug/log-display-config.h
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::log_display_config - log display configuration
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2007 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SEEN_INKSCAPE_DEBUG_LOG_DISPLAY_CONFIG_H
+#define SEEN_INKSCAPE_DEBUG_LOG_DISPLAY_CONFIG_H
+
+namespace Inkscape {
+
+namespace Debug {
+
+void log_display_config();
+
+}
+
+}
+
+#endif
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/logger.cpp b/src/debug/logger.cpp
new file mode 100644
index 0000000..37b8221
--- /dev/null
+++ b/src/debug/logger.cpp
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::Logger - debug logging facility
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2005 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <cstring>
+#include <fstream>
+#include <memory>
+#include <string>
+#include <vector>
+#include <glib.h>
+#include "inkscape-version.h"
+#include "debug/logger.h"
+#include "debug/simple-event.h"
+
+namespace Inkscape {
+
+namespace Debug {
+
+bool Logger::_enabled=false;
+bool Logger::_category_mask[Event::N_CATEGORIES];
+
+namespace {
+
+static void write_escaped_value(std::ostream &os, char const *value) {
+ for ( char const *current=value ; *current ; ++current ) {
+ switch (*current) {
+ case '&':
+ os << "&amp;";
+ break;
+ case '"':
+ os << "&quot;";
+ break;
+ case '\'':
+ os << "&apos;";
+ break;
+ case '<':
+ os << "&lt;";
+ break;
+ case '>':
+ os << "&gt;";
+ break;
+ default:
+ os.put(*current);
+ }
+ }
+}
+
+static void write_indent(std::ostream &os, unsigned depth) {
+ for ( unsigned i = 0 ; i < depth ; i++ ) {
+ os.write(" ", 2);
+ }
+}
+
+static std::ofstream log_stream;
+static bool empty_tag=false;
+typedef std::vector<std::shared_ptr<std::string>> TagStack;
+static TagStack &tag_stack() {
+ static TagStack stack;
+ return stack;
+}
+
+static void do_shutdown() {
+ Debug::Logger::shutdown();
+}
+
+static bool equal_range(char const *c_string,
+ char const *start, char const *end)
+{
+ return !std::strncmp(start, c_string, end - start) &&
+ !c_string[end - start];
+}
+
+static void set_category_mask(bool * const mask, char const *filter) {
+ if (!filter) {
+ for ( unsigned i = 0 ; i < Event::N_CATEGORIES ; i++ ) {
+ mask[i] = true;
+ }
+ return;
+ } else {
+ for ( unsigned i = 0 ; i < Event::N_CATEGORIES ; i++ ) {
+ mask[i] = false;
+ }
+ mask[Event::CORE] = true;
+ }
+
+ char const *start;
+ char const *end;
+ start = end = filter;
+ while (*end) {
+ while ( *end && *end != ',' ) { end++; }
+ if ( start != end ) {
+ struct CategoryName {
+ char const *name;
+ Event::Category category;
+ };
+ static const CategoryName category_names[] = {
+ { "CORE", Event::CORE },
+ { "XML", Event::XML },
+ { "SPOBJECT", Event::SPOBJECT },
+ { "DOCUMENT", Event::DOCUMENT },
+ { "REFCOUNT", Event::REFCOUNT },
+ { "EXTENSION", Event::EXTENSION },
+ { "FINALIZERS", Event::FINALIZERS },
+ { "INTERACTION", Event::INTERACTION },
+ { "CONFIGURATION", Event::CONFIGURATION },
+ { "OTHER", Event::OTHER },
+ { nullptr, Event::OTHER }
+ };
+ CategoryName const *iter;
+ for ( iter = category_names ; iter->name ; iter++ ) {
+ if (equal_range(iter->name, start, end)) {
+ mask[iter->category] = true;
+ break;
+ }
+ }
+ if (!iter->name) {
+ g_warning("Unknown debugging category %*s", (int)(end - start), start);
+ }
+ }
+ if (*end) {
+ start = end = end + 1;
+ }
+ }
+}
+
+typedef SimpleEvent<Event::CORE> CoreEvent;
+
+class SessionEvent : public CoreEvent {
+public:
+ SessionEvent() : CoreEvent("session") {
+ _addProperty("inkscape-version", Inkscape::version_string);
+ }
+};
+
+}
+
+void Logger::init() {
+ if (!_enabled) {
+ char const *log_filename=std::getenv("INKSCAPE_DEBUG_LOG");
+ if (log_filename) {
+ log_stream.open(log_filename);
+ if (log_stream.is_open()) {
+ char const *log_filter=std::getenv("INKSCAPE_DEBUG_FILTER");
+ set_category_mask(_category_mask, log_filter);
+ log_stream << "<?xml version=\"1.0\"?>\n";
+ log_stream.flush();
+ _enabled = true;
+ start<SessionEvent>();
+ std::atexit(&do_shutdown);
+ }
+ }
+ }
+}
+
+void Logger::_start(Event const &event) {
+ char const *name=event.name();
+
+ if (empty_tag) {
+ log_stream << ">\n";
+ }
+
+ write_indent(log_stream, tag_stack().size());
+
+ log_stream << "<" << name;
+
+ unsigned property_count=event.propertyCount();
+ for ( unsigned i = 0 ; i < property_count ; i++ ) {
+ Event::PropertyPair property=event.property(i);
+ log_stream << " " << property.name << "=\"";
+ write_escaped_value(log_stream, property.value->c_str());
+ log_stream << "\"";
+ }
+
+ log_stream.flush();
+
+ tag_stack().push_back(std::make_shared<std::string>(name));
+ empty_tag = true;
+
+ event.generateChildEvents();
+}
+
+void Logger::_skip() {
+ tag_stack().push_back(nullptr);
+}
+
+void Logger::_finish() {
+ if (tag_stack().back()) {
+ if (empty_tag) {
+ log_stream << "/>\n";
+ } else {
+ write_indent(log_stream, tag_stack().size() - 1);
+ log_stream << "</" << tag_stack().back()->c_str() << ">\n";
+ }
+ log_stream.flush();
+
+ empty_tag = false;
+ }
+
+ tag_stack().pop_back();
+}
+
+void Logger::shutdown() {
+ if (_enabled) {
+ while (!tag_stack().empty()) {
+ finish();
+ }
+ }
+}
+
+}
+
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/logger.h b/src/debug/logger.h
new file mode 100644
index 0000000..ab6c826
--- /dev/null
+++ b/src/debug/logger.h
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::Logger - debug logging facility
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2005 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SEEN_INKSCAPE_DEBUG_LOGGER_H
+#define SEEN_INKSCAPE_DEBUG_LOGGER_H
+
+#include "debug/event.h"
+
+namespace Inkscape {
+
+namespace Debug {
+
+class Logger {
+public:
+ static void init();
+
+ template <typename EventType>
+ inline static void start() {
+ if (_enabled) {
+ if (_category_mask[EventType::category()]) {
+ _start(EventType());
+ } else {
+ _skip();
+ }
+ }
+ }
+
+ template <typename EventType, typename A>
+ inline static void start(A const &a) {
+ if (_enabled) {
+ if (_category_mask[EventType::category()]) {
+ _start(EventType(a));
+ } else {
+ _skip();
+ }
+ }
+ }
+
+ template <typename EventType, typename A, typename B>
+ inline static void start(A const &a, B const &b) {
+ if (_enabled) {
+ if (_category_mask[EventType::category()]) {
+ _start(EventType(a, b));
+ } else {
+ _skip();
+ }
+ }
+ }
+
+ template <typename EventType, typename A, typename B, typename C>
+ inline static void start(A const &a, B const &b, C const &c) {
+ if (_enabled) {
+ if (_category_mask[EventType::category()]) {
+ _start(EventType(a, b, c));
+ } else {
+ _skip();
+ }
+ }
+ }
+
+ template <typename EventType, typename A, typename B,
+ typename C, typename D>
+ inline static void start(A const &a, B const &b, C const &c, D const &d) {
+ if (_enabled) {
+ if (_category_mask[EventType::category()]) {
+ _start(EventType(a, b, c, d));
+ } else {
+ _skip();
+ }
+ }
+ }
+
+ template <typename EventType, typename A, typename B, typename C,
+ typename D, typename E>
+ inline static void start(A const &a, B const &b, C const &c,
+ D const &d, E const &e)
+ {
+ if (_enabled) {
+ if (_category_mask[EventType::category()]) {
+ _start(EventType(a, b, c, d, e));
+ } else {
+ _skip();
+ }
+ }
+ }
+
+ template <typename EventType, typename A, typename B, typename C,
+ typename D, typename E, typename F>
+ inline static void start(A const &a, B const &b, C const &c,
+ D const &d, E const &e, F const &f)
+ {
+ if (_enabled) {
+ if (_category_mask[EventType::category()]) {
+ _start(EventType(a, b, c, d, e, f));
+ } else {
+ _skip();
+ }
+ }
+ }
+
+ template <typename EventType, typename A, typename B, typename C,
+ typename D, typename E, typename F,
+ typename G>
+ inline static void start(A const &a, B const &b, C const &c, D const &d,
+ E const &e, F const &f, G const &g)
+ {
+ if (_enabled) {
+ if (_category_mask[EventType::category()]) {
+ _start(EventType(a, b, c, d, e, f, g));
+ } else {
+ _skip();
+ }
+ }
+ }
+
+ template <typename EventType, typename A, typename B, typename C,
+ typename D, typename E, typename F,
+ typename G, typename H>
+ inline static void start(A const &a, B const &b, C const &c, D const &d,
+ E const &e, F const &f, G const &g, H const &h)
+ {
+ if (_enabled) {
+ if (_category_mask[EventType::category()]) {
+ _start(EventType(a, b, c, d, e, f, g, h));
+ } else {
+ _skip();
+ }
+ }
+ }
+
+ inline static void finish() {
+ if (_enabled) {
+ _finish();
+ }
+ }
+
+ template <typename EventType>
+ inline static void write() {
+ start<EventType>();
+ finish();
+ }
+
+ template <typename EventType, typename A>
+ inline static void write(A const &a) {
+ start<EventType, A>(a);
+ finish();
+ }
+
+ template <typename EventType, typename A, typename B>
+ inline static void write(A const &a, B const &b) {
+ start<EventType, A, B>(a, b);
+ finish();
+ }
+
+ template <typename EventType, typename A, typename B, typename C>
+ inline static void write(A const &a, B const &b, C const &c) {
+ start<EventType, A, B, C>(a, b, c);
+ finish();
+ }
+
+ template <typename EventType, typename A, typename B,
+ typename C, typename D>
+ inline static void write(A const &a, B const &b, C const &c, D const &d) {
+ start<EventType, A, B, C, D>(a, b, c, d);
+ finish();
+ }
+
+ template <typename EventType, typename A, typename B,
+ typename C, typename D,
+ typename E>
+ inline static void write(A const &a, B const &b, C const &c,
+ D const &d, E const &e)
+ {
+ start<EventType, A, B, C, D, E>(a, b, c, d, e);
+ finish();
+ }
+
+ template <typename EventType, typename A, typename B,
+ typename C, typename D,
+ typename E, typename F>
+ inline static void write(A const &a, B const &b, C const &c,
+ D const &d, E const &e, F const &f)
+ {
+ start<EventType, A, B, C, D, E, F>(a, b, c, d, e, f);
+ finish();
+ }
+
+ template <typename EventType, typename A, typename B,
+ typename C, typename D,
+ typename E, typename F,
+ typename G>
+ inline static void write(A const &a, B const &b, C const &c,
+ D const &d, E const &e, F const &f,
+ G const &g)
+ {
+ start<EventType, A, B, C, D, E, F, G>(a, b, c, d, e, f, g);
+ finish();
+ }
+
+ template <typename EventType, typename A, typename B,
+ typename C, typename D,
+ typename E, typename F,
+ typename G, typename H>
+ inline static void write(A const &a, B const &b, C const &c,
+ D const &d, E const &e, F const &f,
+ G const &g, H const &h)
+ {
+ start<EventType, A, B, C, D, E, F, G, H>(a, b, c, d, e, f, g, h);
+ finish();
+ }
+
+ static void shutdown();
+
+private:
+ static bool _enabled;
+
+ static void _start(Event const &event);
+ static void _skip();
+ static void _finish();
+
+ static bool _category_mask[Event::N_CATEGORIES];
+};
+
+}
+
+}
+
+#endif
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/simple-event.h b/src/debug/simple-event.h
new file mode 100644
index 0000000..58719b7
--- /dev/null
+++ b/src/debug/simple-event.h
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::SimpleEvent - trivial implementation of Debug::Event
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2005 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SEEN_INKSCAPE_DEBUG_SIMPLE_EVENT_H
+#define SEEN_INKSCAPE_DEBUG_SIMPLE_EVENT_H
+
+#include <cstdarg>
+#include <memory>
+#include <string>
+#include <vector>
+#include <glib.h> // g_assert()
+
+#include "debug/event.h"
+
+namespace Inkscape {
+
+namespace Debug {
+
+template <Event::Category C=Event::OTHER>
+class SimpleEvent : public Event {
+public:
+ explicit SimpleEvent(char const *name) : _name(name) {}
+
+ // default copy
+ // default assign
+
+ static Category category() { return C; }
+
+ char const *name() const override { return _name; }
+ unsigned propertyCount() const override { return _properties.size(); }
+ PropertyPair property(unsigned property) const override {
+ return _properties[property];
+ }
+
+ void generateChildEvents() const override {}
+
+protected:
+ void _addProperty(char const *name, std::shared_ptr<std::string>&& value) {
+ _properties.emplace_back(name, std::move(value));
+ }
+ void _addProperty(char const *name, char const *value) {
+ _addProperty(name, std::make_shared<std::string>(value));
+ }
+ void _addProperty(char const *name, long value) {
+ _addFormattedProperty(name, "%ld", value);
+ }
+
+private:
+ char const *_name;
+ std::vector<PropertyPair> _properties;
+
+ void _addFormattedProperty(char const *name, char const *format, ...)
+ {
+ va_list args;
+ va_start(args, format);
+ gchar *value=g_strdup_vprintf(format, args);
+ g_assert(value != nullptr);
+ va_end(args);
+ _addProperty(name, value);
+ g_free(value);
+ }
+};
+
+}
+
+}
+
+#endif
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/sysv-heap.cpp b/src/debug/sysv-heap.cpp
new file mode 100644
index 0000000..7d21c02
--- /dev/null
+++ b/src/debug/sysv-heap.cpp
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::SysVHeap - malloc() statistics via System V interface
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2005 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h" // only include where actually required!
+#endif
+
+#ifdef HAVE_MALLOC_H
+# include <malloc.h>
+#endif
+
+#include "debug/sysv-heap.h"
+
+namespace Inkscape {
+namespace Debug {
+
+int SysVHeap::features() const {
+#ifdef HAVE_MALLINFO
+ return SIZE_AVAILABLE | USED_AVAILABLE;
+#else
+ return 0;
+#endif
+}
+
+Heap::Stats SysVHeap::stats() const {
+ Stats stats = { 0, 0 };
+
+#ifdef HAVE_MALLINFO
+#ifdef HAVE_MALLINFO2
+ struct mallinfo2 info=mallinfo2();
+#else
+ struct mallinfo info=mallinfo();
+#endif
+
+#ifdef HAVE_STRUCT_MALLINFO_USMBLKS
+ stats.size += info.usmblks;
+ stats.bytes_used += info.usmblks;
+#endif
+
+#ifdef HAVE_STRUCT_MALLINFO_FSMBLKS
+ stats.size += info.fsmblks;
+#endif
+
+#ifdef HAVE_STRUCT_MALLINFO_UORDBLKS
+ stats.size += info.uordblks;
+ stats.bytes_used += info.uordblks;
+#endif
+
+#ifdef HAVE_STRUCT_MALLINFO_FORDBLKS
+ stats.size += info.fordblks;
+#endif
+
+#ifdef HAVE_STRUCT_MALLINFO_HBLKHD
+ stats.size += info.hblkhd;
+ stats.bytes_used += info.hblkhd;
+#endif
+
+#endif
+
+ return stats;
+}
+
+}
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/sysv-heap.h b/src/debug/sysv-heap.h
new file mode 100644
index 0000000..f7ed271
--- /dev/null
+++ b/src/debug/sysv-heap.h
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::SysVHeap - malloc() statistics via System V interface
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2005 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SEEN_INKSCAPE_DEBUG_SYSV_HEAP_H
+#define SEEN_INKSCAPE_DEBUG_SYSV_HEAP_H
+
+#include "debug/heap.h"
+
+namespace Inkscape {
+namespace Debug {
+
+class SysVHeap : public Heap {
+public:
+ SysVHeap() = default;
+
+ int features() const override;
+
+ char const *name() const override {
+ return "standard malloc()";
+ }
+ Stats stats() const override;
+ void force_collect() override {}
+};
+
+}
+}
+
+#endif
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/timestamp.cpp b/src/debug/timestamp.cpp
new file mode 100644
index 0000000..dab4e73
--- /dev/null
+++ b/src/debug/timestamp.cpp
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::SimpleEvent - trivial implementation of Debug::Event
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2007 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+
+#include <glib.h>
+#include <glibmm/ustring.h>
+#include <memory>
+#include <string>
+#include "debug/simple-event.h"
+#include "timestamp.h"
+
+namespace Inkscape {
+
+namespace Debug {
+
+std::shared_ptr<std::string> timestamp() {
+ gint64 micr = g_get_monotonic_time();
+ gchar *value = g_strdup_printf("%.6f", (gdouble)micr / 1000000.0);
+ std::shared_ptr<std::string> result = std::make_shared<std::string>(value);
+ g_free(value);
+ return result;
+}
+
+}
+
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/debug/timestamp.h b/src/debug/timestamp.h
new file mode 100644
index 0000000..a4db90d
--- /dev/null
+++ b/src/debug/timestamp.h
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::timestamp - timestamp strings
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2007 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef SEEN_INKSCAPE_DEBUG_TIMESTAMP_H
+#define SEEN_INKSCAPE_DEBUG_TIMESTAMP_H
+
+#include <memory>
+#include <string>
+
+namespace Inkscape {
+
+namespace Debug {
+
+std::shared_ptr<std::string> timestamp();
+
+}
+
+}
+
+#endif
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :