From 7ecd563beb2eed5db8cc4efcdc9e2bedf6cf33b9 Mon Sep 17 00:00:00 2001 From: Erik Schamper <1254028+Schamper@users.noreply.github.com> Date: Tue, 3 Mar 2026 14:35:58 +0000 Subject: [PATCH] Add expression and parser benchmarks --- tests/test_benchmark.py | 89 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 15e0415..443f9d1 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -1,9 +1,12 @@ from __future__ import annotations +from functools import partial from typing import TYPE_CHECKING import pytest +from dissect.cstruct.expression import Expression + if TYPE_CHECKING: from pytest_benchmark.fixture import BenchmarkFixture @@ -85,3 +88,89 @@ def test_benchmark_getattr_typedefs(cs: cstruct, benchmark: BenchmarkFixture) -> cs.load(cdef) benchmark(lambda: cs.my_uint8) + + +@pytest.mark.benchmark +def test_benchmark_expression_parse(cs: cstruct, benchmark: BenchmarkFixture) -> None: + """Benchmark the parsing of expressions.""" + cs.load("#define a 5\n#define b 10") + + benchmark(lambda: Expression("a * 2 + b * (3 + 4) >> 1")) + + +@pytest.mark.benchmark +def test_benchmark_expression_evaluate(cs: cstruct, benchmark: BenchmarkFixture) -> None: + """Benchmark the evaluation of expressions.""" + cs.load("#define a 5\n#define b 10") + + expression = Expression("a * 2 + b * (3 + 4) >> 1") + benchmark(lambda: expression.evaluate(cs)) + + +@pytest.mark.benchmark +def test_benchmark_expression_parse_and_evaluate(cs: cstruct, benchmark: BenchmarkFixture) -> None: + """Benchmark the parsing and evaluation of expressions.""" + cs.load("#define a 5\n#define b 10") + + benchmark(lambda: Expression("a * 2 + b * (3 + 4) >> 1").evaluate(cs)) + + +_BENCHMARK_CDEF = """ +struct SECURITY_DESCRIPTOR { + uint8 Revision; + uint8 Sbz1; + uint16 Control; + uint32 OffsetOwner; + uint32 OffsetGroup; + uint32 OffsetSacl; + uint32 OffsetDacl; +}; + +struct LDAP_SID_IDENTIFIER_AUTHORITY { + char Value[6]; +}; + +struct LDAP_SID { + uint8 Revision; + uint8 SubAuthorityCount; + LDAP_SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + uint32 SubAuthority[SubAuthorityCount]; +}; + +struct ACL { + uint8 AclRevision; + uint8 Sbz1; + uint16 AclSize; + uint16 AceCount; + uint16 Sbz2; + char Data[AclSize - 8]; +}; + +struct ACE { + uint8 AceType; + uint8 AceFlags; + uint16 AceSize; + char Data[AceSize - 4]; +}; + +struct ACCESS_ALLOWED_ACE { + uint16 Mask; + LDAP_SID Sid; +}; + +struct ACCESS_ALLOWED_OBJECT_ACE { + uint32 Mask; + uint32 Flags; + char ObjectType[(Flags & 1) * 16]; + char InheritedObjectType[(Flags & 2) * 8]; + LDAP_SID Sid; +}; +""" + + +@pytest.mark.benchmark +def test_benchmark_lexer_and_parser(cs: cstruct, benchmark: BenchmarkFixture) -> None: + """Benchmark tokenizing and parsing a realistic set of struct definitions.""" + cs.add_type = partial(cs.add_type, replace=True) + + benchmark(lambda: cs.load(_BENCHMARK_CDEF))