diff --git a/src/View/Debug/Table.py b/src/View/Debug/Table.py
new file mode 100644
index 00000000..ce4c8f2b
--- /dev/null
+++ b/src/View/Debug/Table.py
@@ -0,0 +1,74 @@
+# Table.py -- Pamhyr
+# Copyright (C) 2026 INRAE
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+# -*- coding: utf-8 -*-
+
+import logging
+
+from functools import reduce
+from tools import trace, timer, _timers, _calls
+
+from PyQt5.QtCore import (
+ Qt, QVariant, QAbstractTableModel,
+ QCoreApplication, QModelIndex, pyqtSlot,
+ QRect,
+)
+
+from PyQt5.QtWidgets import (
+ QDialogButtonBox, QPushButton, QLineEdit,
+ QFileDialog, QTableView, QAbstractItemView,
+ QUndoStack, QShortcut, QAction, QItemDelegate,
+ QComboBox,
+)
+
+from Modules import Modules
+from View.Tools.PamhyrTable import PamhyrTableModel
+
+logger = logging.getLogger()
+
+
+class TableModel(PamhyrTableModel):
+ def _setup_lst(self):
+ self._lst = sorted(
+ map(
+ lambda f: (
+ f"{f.__module__}.{f.__qualname__}",
+ _timers[f],
+ _calls[f]
+ ),
+ _timers
+ ),
+ key=lambda f: f[1],
+ reverse=True
+ )
+
+ def update_lst(self):
+ self._setup_lst()
+ self.layoutChanged.emit()
+
+ def data(self, index, role):
+ row = index.row()
+ column = index.column()
+
+ if role == Qt.DisplayRole:
+ if self._headers[column] == "name":
+ return self._lst[row][0]
+ elif self._headers[column] == "time":
+ return self._lst[row][1]
+ elif self._headers[column] == "calls":
+ return self._lst[row][2]
+
+ return QVariant()
diff --git a/src/View/Debug/Window.py b/src/View/Debug/Window.py
index c5f4c720..e93ec9bf 100644
--- a/src/View/Debug/Window.py
+++ b/src/View/Debug/Window.py
@@ -1,5 +1,5 @@
# Window.py -- Pamhyr
-# Copyright (C) 2023-2025 INRAE
+# Copyright (C) 2023-2026 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@ from tools import trace, timer
from View.Tools.PamhyrWindow import PamhyrWindow
from View.Tools.PamhyrPythonEditor import PamhyrPythonEditor
+from View.Debug.Table import TableModel
from PyQt5.QtGui import (
QKeySequence,
@@ -31,7 +32,7 @@ from PyQt5.QtGui import (
from PyQt5.QtCore import (
Qt, QVariant, QAbstractTableModel,
QCoreApplication, QModelIndex, QRect, QThread,
- pyqtSlot, pyqtSignal,
+ QTimer, pyqtSlot, pyqtSignal,
)
from PyQt5.QtWidgets import (
@@ -101,3 +102,54 @@ class ReplWindow(PamhyrWindow):
self.find(QTextEdit, "textEdit").append(msg)
# Display results
self.find(QTextEdit, "textEdit").append(str(value))
+
+class TimerWindow(PamhyrWindow):
+ _pamhyr_ui = "DebugTimer"
+ _pamhyr_name = "Debug Timer"
+
+ def __init__(self, study=None, config=None,
+ solver=None, parent=None):
+ title = _translate("Debug", "Debug Timer")
+
+ super(TimerWindow, self).__init__(
+ title=title,
+ study=study,
+ config=config,
+ options=[],
+ parent=parent
+ )
+
+ self.setup_table()
+ self.setup_alarm()
+ self.setup_connections()
+
+ def setup_table(self):
+ table = self.find(QTableView, f"tableView")
+ self._table = TableModel(
+ table_view=table,
+ table_headers={
+ "name": "Function name",
+ "time": "Time (sec)",
+ "calls": "Number of calls"
+ },
+ data=None,
+ )
+
+ def setup_alarm(self):
+ self._alarm = QTimer()
+ self._alarm.start(2000)
+
+ def setup_connections(self):
+ self.find(QAction, "action_reset").triggered.connect(self.reset)
+ self.find(QAction, "action_export").triggered.connect(self.export)
+
+ self._alarm.timeout.connect(self.update)
+
+ def update(self):
+ self._table.update_lst()
+
+ def reset(self):
+ return
+
+ def export(self):
+ return
diff --git a/src/View/MainWindow.py b/src/View/MainWindow.py
index 70a70f5c..f112ccdf 100644
--- a/src/View/MainWindow.py
+++ b/src/View/MainWindow.py
@@ -100,7 +100,7 @@ from View.CheckList.WindowAdisTS import CheckListWindowAdisTS
from View.Results.WindowAdisTS import ResultsWindowAdisTS
from View.Results.ReadingResultsDialog import ReadingResultsDialog
-from View.Debug.Window import ReplWindow
+from View.Debug.Window import ReplWindow, TimerWindow
from View.OutputRKAdisTS.Window import OutputRKAdisTSWindow
from View.Pollutants.Window import PollutantsWindow
from View.D90AdisTS.Window import D90AdisTSWindow
@@ -409,21 +409,28 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
self.debug_action.setToolTip(self._trad["open_debug"])
self.debug_action.triggered.connect(self.open_debug)
+ self.debug_timer_action = QAction("Debug timer", self)
+ self.debug_timer_action.setToolTip(self._trad["open_debug_timer"])
+ self.debug_timer_action.triggered.connect(self.open_debug_timer)
+
self.debug_sqlite_action = QAction("Debug SQLite", self)
self.debug_sqlite_action.setToolTip(self._trad["open_debug_sql"])
self.debug_sqlite_action.triggered.connect(self.open_sqlite)
if self.conf.debug:
menu.addAction(self.debug_action)
+ menu.addAction(self.debug_timer_action)
menu.addAction(self.debug_sqlite_action)
self.set_debug_lvl(debug=True)
else:
if self.conf.debug:
menu.addAction(self.debug_action)
+ menu.addAction(self.debug_timer_action)
menu.addAction(self.debug_sqlite_action)
self.set_debug_lvl(debug=True)
else:
menu.removeAction(self.debug_action)
+ menu.removeAction(self.debug_timer_action)
menu.removeAction(self.debug_sqlite_action)
self.set_debug_lvl(debug=False)
@@ -2143,6 +2150,14 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
)
repl.show()
+ def open_debug_timer(self):
+ repl = TimerWindow(
+ study=self._study,
+ config=self.conf,
+ parent=self
+ )
+ repl.show()
+
def open_sqlite(self):
if self._study is None:
logger.debug("No study open for sql debuging...")
diff --git a/src/View/ui/DebugTimer.ui b/src/View/ui/DebugTimer.ui
new file mode 100644
index 00000000..0a4a99f4
--- /dev/null
+++ b/src/View/ui/DebugTimer.ui
@@ -0,0 +1,68 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 800
+ 600
+
+
+
+ MainWindow
+
+
+
+ -
+
+
+
+
+
+
+
+
+ toolBar
+
+
+ TopToolBarArea
+
+
+ false
+
+
+
+
+
+
+
+ ressources/export.pngressources/export.png
+
+
+ Export
+
+
+
+
+
+ ressources/reload.pngressources/reload.png
+
+
+ Reset
+
+
+
+
+
+