Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimized Rect/FRect pgRect_FromObject #2041

Merged

Conversation

itzpr3d4t0r
Copy link
Member

@itzpr3d4t0r itzpr3d4t0r commented Mar 21, 2023

I have ported #1843 since the last addition of FRect. I also updated my test program to produce more compact results. This PR should speed up all functions that accept a Rect-like as param. Actual Rect/FRect object as parameters are not affected.
This means that functions that take sequences like (x, y, w, h) or ((x, y), (w, h)) should benefit from this.
Results:

FRect
OLD

FRect (ms) 4a 1a 2a 1a 2s r attr r meth
instantiation 142.775 148.58 151.93 165.547 258.922 321.953
update 108.586 119.54 129.14 150.608 241.638 320.861
union 128.721 139.383 144.534 164.283 264.903 330.44
union_ip 110.288 122.154 131.417 156.187 236.39 319.557
clip 124.958 135.148 144.719 169.749 266.152 331.327
colliderect 68.5006 90.9471 82.5043 120.149 203.799 284.795
collidelist 1503.06 1630.91
collidelistall 1539.78 1669.13

NEW

FRect (ms) 4a 1a 2a 1a 2s r attr r meth
instantiation 112.192 124.763 154.137 161.03 207.193 259.056
update 106.381 114.321 115.644 130.511 170.518 238.515
union 121.665 133.924 142.434 151.088 201.634 256.291
union_ip 108.603 123.94 119.543 137.935 177.864 237.649
clip 120.511 130.499 136.267 151.63 201.553 256.948
colliderect 64.6672 83.9012 89.2537 100.712 157.369 201.935
collidelist 1284.65 1557.18
collidelistall 1299.62 1572.09

Rect
OLD

Rect (ms) 4a 1a 2a 1a 2s r attr r meth
instantiation 145.682 155.88 151.38 164.339 268.44 323.51
update 134.111 135.066 138.892 150.072 249.852 320.009
union 154.835 154.755 157.354 171.846 272.256 331.964
union_ip 128.519 140.884 142.469 157.663 258.865 314.057
clip 148.828 156.624 160.743 179.83 285.872 353.953
colliderect 65.0292 90.2959 97.4342 114.931 210.152 278.185
collidelist 1007.44 1316.01
collidelistall 1035.64 1382.66

NEW

Rect (ms) 4a 1a 2a 1a 2s r attr r meth
instantiation 125.46 127.815 144.663 160.908 206.661 255.443
update 90.2074 93.5331 123.818 133.744 177.901 240.214
union 117.424 123.701 153.282 157.854 201.07 256.451
union_ip 107.671 104.778 127.645 139.339 183.731 246.307
clip 123.323 129.958 150.536 160.204 197.421 259.764
colliderect 62.8959 75.0202 86.1815 104.539 148.968 207.309
collidelist 668.871 1179.3
collidelistall 712.745 1223.26

The code I used:

import timeit
from statistics import fmean

from pygame.rect import Rect, FRect
from tabulate import tabulate


def create_table(title: str, *headers, data: list):
    table_headers = [title, *headers]
    table = []
    for row in data:
        table.append(row)

    print(tabulate(table, headers=table_headers, tablefmt="github", numalign="left",
                   stralign="left", ))


NUMBER = 1_000_000

r1 = Rect(799, 799, 10, 10)
r2 = Rect(0, 0, 5, 5)
rects = [
    (0, 0, 100, 100),
    (50, 50, 100, 100),
    (100, 100, 100, 100),
    (150, 150, 100, 100),
    (200, 200, 100, 100),
    (250, 250, 100, 100),
    (300, 300, 100, 100),
    (350, 350, 100, 100),
    (400, 400, 100, 100),
    (450, 450, 100, 100),
    (500, 500, 100, 100),
    (550, 550, 100, 100),
    (600, 600, 100, 100),
    (650, 650, 100, 100),
    (700, 700, 100, 100),
]
rects2 = [((a, b), (c, d)) for a, b, c, d in rects]


class RectAttr:
    def __init__(self, x, y, w, h):
        self.rect = Rect(x, y, w, h)


r3 = RectAttr(799, 799, 10, 10)


class RectMethod:
    def __init__(self, x, y, w, h):
        self.p = Rect(x, y, w, h)

    def rect(self):
        return self.p


r4 = RectMethod(799, 799, 10, 10)

GLOB = globals()


def test(name: str, funcs: list[str], data_table) -> None:
    t = [name]
    for func in funcs:
        val = fmean(timeit.repeat(func, globals=GLOB, number=NUMBER))
        t.append(val * 1000)
    data_table.append(t)
    print(f"{name} done")


data = []

test("instantiation",
     [
         "Rect(10.0, 10.0, 2.0, 2.0)",
         "Rect((10.0, 10.0, 2.0, 2.0))",
         "Rect((10.0, 10.0), (2.0, 2.0))",
         "Rect(((10.0, 10.0), (2.0, 2.0)))",
         "Rect(r3)",
         "Rect(r4)",
     ],
     data
     )
test("update",
     [
         "r1.update(10.0, 10.0, 2.0, 2.0)",
         "r1.update((10.0, 10.0, 2.0, 2.0))",
         "r1.update((10.0, 10.0), (2.0, 2.0))",
         "r1.update(((10.0, 10.0), (2.0, 2.0)))",
         "r1.update(r3)",
         "r1.update(r4)",
     ],
     data
     )
test("union",
     [
         "r1.union(10.0, 10.0, 2.0, 2.0)",
         "r1.union((10.0, 10.0, 2.0, 2.0))",
         "r1.union((10.0, 10.0), (2.0, 2.0))",
         "r1.union(((10.0, 10.0), (2.0, 2.0)))",
         "r1.union(r3)",
         "r1.union(r4)",
     ],
     data
     )
test("union_ip",
     [
         "r2.union_ip(10.0, 10.0, 2.0, 2.0)",
         "r2.union_ip((10.0, 10.0, 2.0, 2.0))",
         "r2.union_ip((10.0, 10.0), (2.0, 2.0))",
         "r2.union_ip(((10.0, 10.0), (2.0, 2.0)))",
         "r2.union_ip(r3)",
         "r2.union_ip(r4)",
     ],
     data
     )
test("clip",
     [
         "r1.clip(10.0, 10.0, 2.0, 2.0)",
         "r1.clip((10.0, 10.0, 2.0, 2.0))",
         "r1.clip((10.0, 10.0), (2.0, 2.0))",
         "r1.clip(((10.0, 10.0), (2.0, 2.0)))",
         "r1.clip(r3)",
         "r1.clip(r4)",
     ],
     data
     )
test("colliderect",
     [
         "r1.colliderect(10.0, 10.0, 2.0, 2.0)",
         "r1.colliderect((10.0, 10.0, 2.0, 2.0))",
         "r1.colliderect((10.0, 10.0), (2.0, 2.0))",
         "r1.colliderect(((10.0, 10.0), (2.0, 2.0)))",
         "r1.colliderect(r3)",
         "r1.colliderect(r4)",
     ],
     data
     )
test("collidelist",
     [
         "r1.collidelist(rects)",
         "r1.collidelist(rects2)",
     ],
     data
     )
test("collidelistall",
     [
         "r1.collidelistall(rects)",
         "r1.collidelistall(rects2)",
     ],
     data
     )

create_table(
    "Rect (ms)", "4a", "1a", "2a", "1a 2s", "r attr", "r meth",
    data=data
)

@itzpr3d4t0r itzpr3d4t0r added Performance Related to the speed or resource usage of the project rect pygame.rect labels Mar 21, 2023
@itzpr3d4t0r itzpr3d4t0r requested a review from a team as a code owner March 21, 2023 19:00
@MyreMylar MyreMylar added this to the 2.4.0 milestone Aug 14, 2023
Copy link
Member

@MyreMylar MyreMylar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

I get the same speedup testing locally with this testing. noticed one line that looks to need deleting, but otherwise looks alright to me.

src_c/rect_impl.h Outdated Show resolved Hide resolved
src_c/rect_impl.h Outdated Show resolved Hide resolved
src_c/rect_impl.h Outdated Show resolved Hide resolved
itzpr3d4t0r and others added 3 commits October 4, 2023 19:26
Co-authored-by: Dan Lawrence <danintheshed@gmail.com>
Copy link
Member

@ankith26 ankith26 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the PR 🍰

@itzpr3d4t0r itzpr3d4t0r merged commit 4cadff2 into pygame-community:main Oct 5, 2023
29 of 30 checks passed
@itzpr3d4t0r itzpr3d4t0r deleted the re_pgRect_FromObject_speedup branch October 8, 2023 08:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Performance Related to the speed or resource usage of the project rect pygame.rect
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants