From e90b2fb3d99a8162f7ec1a04ad0219a7f378d3b6 Mon Sep 17 00:00:00 2001 From: Massimo Fabbro Date: Wed, 5 Nov 2025 21:17:17 +0100 Subject: [PATCH 1/2] Ifc5d quantify function time Useful for quantify function optimization --- src/ifc5d/ifc5d/qto.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ifc5d/ifc5d/qto.py b/src/ifc5d/ifc5d/qto.py index deb14f0a22b..891d8bd575f 100644 --- a/src/ifc5d/ifc5d/qto.py +++ b/src/ifc5d/ifc5d/qto.py @@ -36,6 +36,7 @@ from collections import defaultdict from typing import Any, Literal, get_args, Union, NamedTuple from collections.abc import Iterable +import time class Function(NamedTuple): @@ -85,6 +86,7 @@ def quantify(ifc_file: ifcopenshell.file, elements: set[ifcopenshell.entity_inst :param rules: Set of rules from `ifc5d.qto.rules`. """ + start = time.perf_counter() results: ResultsDict = {} elements_by_classes: defaultdict[str, set[ifcopenshell.entity_instance]] = defaultdict(set) for element in elements: @@ -124,6 +126,8 @@ def quantify(ifc_file: ifcopenshell.file, elements: set[ifcopenshell.entity_inst if filtered_elements: calculator.calculate(ifc_file, filtered_elements, qtos, results) + end = time.perf_counter() + print(f"Quantify function TIME: {end-start:.6f} seconds") return results From ffec0eebf2efc8246e7596858f7caec6b403bb50 Mon Sep 17 00:00:00 2001 From: Massimo Fabbro Date: Fri, 7 Nov 2025 15:30:09 +0100 Subject: [PATCH 2/2] Add profiler in ifcopenshell util --- src/bonsai/bonsai/bim/module/qto/operator.py | 7 ++-- src/ifc5d/ifc5d/qto.py | 4 --- .../ifcopenshell/util/profiler.py | 34 +++++++++++++++++++ 3 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 src/ifcopenshell-python/ifcopenshell/util/profiler.py diff --git a/src/bonsai/bonsai/bim/module/qto/operator.py b/src/bonsai/bonsai/bim/module/qto/operator.py index eb2ccda2820..c8d32b58297 100644 --- a/src/bonsai/bonsai/bim/module/qto/operator.py +++ b/src/bonsai/bonsai/bim/module/qto/operator.py @@ -22,6 +22,7 @@ import bonsai.tool as tool import bonsai.core.qto as core from bonsai.bim.module.qto import helper +from ifcopenshell.util.profiler import Profiler class CalculateCircleRadius(bpy.types.Operator): @@ -148,7 +149,8 @@ def _execute(self, context): } ifc_file = tool.Ifc.get() - results = ifc5d.qto.quantify(ifc_file, elements, rules) + with(Profiler("Quantify function time:")): + results = ifc5d.qto.quantify(ifc_file, elements, rules) ifc5d.qto.edit_qtos(ifc_file, results) not_quantified_elements = elements - set(results.keys()) @@ -190,7 +192,8 @@ def run_quantification( ) -> set[ifcopenshell.entity_instance]: rules = ifc5d.qto.rules[rule] ifc_file = tool.Ifc.get() - results = ifc5d.qto.quantify(ifc_file, elements, rules) + with(Profiler("Quantify function time:")): + results = ifc5d.qto.quantify(ifc_file, elements, rules) ifc5d.qto.edit_qtos(ifc_file, results) not_quantified_elements = elements - set(results.keys()) return not_quantified_elements diff --git a/src/ifc5d/ifc5d/qto.py b/src/ifc5d/ifc5d/qto.py index 891d8bd575f..deb14f0a22b 100644 --- a/src/ifc5d/ifc5d/qto.py +++ b/src/ifc5d/ifc5d/qto.py @@ -36,7 +36,6 @@ from collections import defaultdict from typing import Any, Literal, get_args, Union, NamedTuple from collections.abc import Iterable -import time class Function(NamedTuple): @@ -86,7 +85,6 @@ def quantify(ifc_file: ifcopenshell.file, elements: set[ifcopenshell.entity_inst :param rules: Set of rules from `ifc5d.qto.rules`. """ - start = time.perf_counter() results: ResultsDict = {} elements_by_classes: defaultdict[str, set[ifcopenshell.entity_instance]] = defaultdict(set) for element in elements: @@ -126,8 +124,6 @@ def quantify(ifc_file: ifcopenshell.file, elements: set[ifcopenshell.entity_inst if filtered_elements: calculator.calculate(ifc_file, filtered_elements, qtos, results) - end = time.perf_counter() - print(f"Quantify function TIME: {end-start:.6f} seconds") return results diff --git a/src/ifcopenshell-python/ifcopenshell/util/profiler.py b/src/ifcopenshell-python/ifcopenshell/util/profiler.py new file mode 100644 index 00000000000..aabfe37977a --- /dev/null +++ b/src/ifcopenshell-python/ifcopenshell/util/profiler.py @@ -0,0 +1,34 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2021 Dion Moult +# +# This file is part of IfcOpenShell. +# +# IfcOpenShell is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# IfcOpenShell 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with IfcOpenShell. If not, see . + + +from timeit import default_timer as timer + +class Profiler: + """ + A python context manager timing utility, useful for measure functions performances + """ + + def __init__(self, task): + self.task = task + + def __enter__(self): + self.start = timer() + + def __exit__(self, *args): + print(f"{self.task} {timer() - self.start:.6f} s")