From 706d73347962e78f11ab0ea55e151458de7f388f Mon Sep 17 00:00:00 2001 From: stepan Date: Tue, 13 Oct 2026 14:18:42 +0200 Subject: [PATCH] Add megamorphic attribute access benchmark --- .../micro/attribute-access-megamorphic.py | 164 ++++++++++++++++++ mx.graalpython/copyrights/overrides | 1 + mx.graalpython/mx_graalpython_bench_param.py | 2 + 3 files changed, 167 insertions(+) create mode 100644 graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-megamorphic.py diff --git a/graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-megamorphic.py b/graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-megamorphic.py new file mode 100644 index 0000000000..ecfc0455e3 --- /dev/null +++ b/graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-megamorphic.py @@ -0,0 +1,164 @@ +# Copyright (c) 2017, 2026, Oracle and/or its affiliates. +# Copyright (c) 2013, Regents of the University of California +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# micro benchmark: megamorphic attribute access inspired by richards + +iteration = 20000 + + +class TaskState(object): + pass + + +class Task(TaskState): + def __init__(self, foo): + self.foo = foo + + +class Task0(Task): + def __init__(self, foo): + Task.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task1(Task0): + def __init__(self, foo): + Task.__init__(self, foo) + + +class Task2(Task1): + def __init__(self, foo): + Task.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task3(Task2): + def __init__(self, foo): + Task.__init__(self, foo) + + +class Task4(Task): + def __init__(self, foo): + Task.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task5(Task4): + def __init__(self, foo): + Task.__init__(self, foo) + + +class Task6(Task5): + def __init__(self, foo): + Task.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task7(Task6): + def __init__(self, foo): + Task.__init__(self, foo) + + +class Task8(TaskState): + def __init__(self, foo): + self.foo = foo + + +class Task9(Task8): + def __init__(self, foo): + Task8.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task10(Task9): + def __init__(self, foo): + Task8.__init__(self, foo) + + +class Task11(Task10): + def __init__(self, foo): + Task8.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task12(TaskState): + def __init__(self, foo): + self.foo = foo + + +class Task13(Task12): + def __init__(self, foo): + Task12.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task14(Task13): + def __init__(self, foo): + Task12.__init__(self, foo) + + +class Task15(Task14): + def __init__(self, foo): + Task12.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +TASK_LIST = [Task0(0), Task1(1), Task2(2), Task3(3), + Task4(4), Task5(5), Task6(6), Task7(7), + Task8(8), Task9(9), Task10(10), Task11(11), + Task12(12), Task13(13), Task14(14), Task15(15)] + + +def do_stuff(): + task_list = TASK_LIST + total = 0 + for i in range(iteration): + for t in task_list: + total = (total + t.foo) % 7 + + return total + + +def measure(num): + result = 0 + for i in range(num): # 50000 + result |= do_stuff() + + return result + + +def __benchmark__(num=1000): + return measure(num) + + +def run(): + __benchmark__(num=10) + diff --git a/mx.graalpython/copyrights/overrides b/mx.graalpython/copyrights/overrides index 556e94fda8..36df899701 100644 --- a/mx.graalpython/copyrights/overrides +++ b/mx.graalpython/copyrights/overrides @@ -33,6 +33,7 @@ graalpython/com.oracle.graal.python.benchmarks/python/meso/spectralnorm3.py,benc graalpython/com.oracle.graal.python.benchmarks/python/meso/threadring.py,benchmarks.copyright graalpython/com.oracle.graal.python.benchmarks/python/micro/arith-binop.py,zippy.copyright graalpython/com.oracle.graal.python.benchmarks/python/micro/arith-modulo-sized.py,zippy.copyright +graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-megamorphic.py,zippy.copyright graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-polymorphic.py,zippy.copyright graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access.py,zippy.copyright graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-bool.py,zippy.copyright diff --git a/mx.graalpython/mx_graalpython_bench_param.py b/mx.graalpython/mx_graalpython_bench_param.py index 3100fa3cfe..9ad50704fe 100644 --- a/mx.graalpython/mx_graalpython_bench_param.py +++ b/mx.graalpython/mx_graalpython_bench_param.py @@ -64,6 +64,7 @@ MICRO_BENCHMARKS = { 'arith-binop': ITER_10 + ['5'], 'arith-modulo-sized': ITER_10 + ['500'], + 'attribute-access-megamorphic': ITER_10 + ['200'], 'attribute-access-polymorphic': ITER_10 + ['1000'], 'attribute-access': ITER_15 + ['5000'], 'attribute-access-super': ITER_20 + ['5_000'], @@ -161,6 +162,7 @@ 'if-generic': ITER_10 + WARMUP_2 + ['500000'], 'if-generic-non-builtin': ITER_10 + WARMUP_2 + ['500000'], 'if-polymorph': ITER_10 + WARMUP_2 + ['1000000'], + 'attribute-access-megamorphic': ITER_6 + WARMUP_2 + ['13'], 'attribute-access-polymorphic': ITER_6 + WARMUP_2 + ['20'], 'attribute-access': ITER_6 + WARMUP_2 + ['100'], 'attribute-access-super': ITER_6 + WARMUP_2 + ['40'],