pygame-ce icon indicating copy to clipboard operation
pygame-ce copied to clipboard

Added pg_IntFromObjEx(), pg_TwoIntsFromObjEx() and pg_IntFromSeqIndexEx()

Open itzpr3d4t0r opened this issue 2 years ago • 3 comments
trafficstars

Added three new C API functions:

  • pg_IntFromObjEx
  • pg_IntFromSeqIndexEx
  • pg_TwoIntsFromObjEx

These three C API functions are supposed to be slightly faster than the current ones and have a different behaviour as they raise errors on their own, something that their current couterparts do not do. Errors should be more precise and provide more information, epecifically about what the error is, what it expected and what it got in terms of value/type/numebr of values.

You can either use a custom error message to override the default ones or pass NULL to use the predefined error messages and formatting. I recommend passing NULL most of the time as it will give you more precise and informative error messages. Only use a custom message when you need to add more description.

Modified:

  • Rect.collidepoint() to use the new functionality as an example.

I'd like to higlight that in the case of collidepoint, passing a tupleof 2 items is about 83% faster and a list of 2 items about 38% faster. This could entail similar benefits for every function that prefers tuples/lists of 2 items.

Rect.collidepoint() main:

pygame-ce 2.1.4.dev1 (SDL 2.0.22, Python 3.11.0)

====||SEQUENCES||====
-) tup inside tup: 0.6059378 s
-) coll tup: 0.56530388 s
-) not coll tup: 0.5557564 s
-) coll list: 0.8165761 s
-) not coll list: 0.80312168 s
-) coll 2 args: 0.3694743 s
-) not coll 2 args: 0.36558976 s
-) coll unpack tuple 1->2: 0.63821076 s
-) not coll unpack tuple 1->2: 0.62786246 s
-) coll unpack list 1->2: 1.00910418 s
-) not coll unpack list 1->2: 0.98168378 s
______________
-) Mean time: 0.66714737

====||VECTORS||====
-) coll vector: 0.60935196 s
-) not coll vector: 0.61871136 s
______________
-) Mean time: 0.61403166

This PR:

pygame-ce 2.1.4.dev1 (SDL 2.0.22, Python 3.11.0)

====||SEQUENCES||====
-) tup inside tup: 0.31907396 s
-) coll tup: 0.30785382 s
-) not coll tup: 0.31080586 s
-) coll list: 0.59054886 s
-) not coll list: 0.59381622 s
-) coll 2 args: 0.31044572 s
-) not coll 2 args: 0.3121588 s
-) coll unpack tuple 1->2: 0.56166662 s
-) not coll unpack tuple 1->2: 0.5666255 s
-) coll unpack list 1->2: 0.9124658 s
-) not coll unpack list 1->2: 0.89807034 s
______________
-) Mean time: 0.51668468

====||VECTORS||====
-) coll vector: 0.51883372 s
-) not coll vector: 0.51085838 s
______________
-) Mean time: 0.51484605

I used this program to test the new collidepoint with the new C functions:

import pygame

from statistics import fmean
import timeit


def test(test_name: str, func: str, globs: dict, num: int,
         mode: str = "mean") -> float:
    value = 0
    if mode == "mean":
        value = fmean(timeit.repeat(func, globals=globs, number=num))
    elif mode == "cumulative":
        value = timeit.timeit(func, globals=globs, number=num)
    else:
        raise NotImplementedError("Incorrect test mode")
    print("-) " + test_name + f": {round(value, 8)} s")
    return value


def test_group(group_name: str, sequence: list[str],
               globs: dict,
               tests_names: tuple[str, ...] = None, num: int = 10_000_000,
               include_tot: bool = False, include_mean: bool = True,
               test_mode: str = "mean") -> float:
    print("\n====||" + group_name.upper() + "||====")

    test_data = [
        test(tests_names[i] if tests_names else str(i + 1), test_obj, globs,
             num, test_mode)
        for
        i, test_obj in
        enumerate(sequence)]

    print("______________")
    if include_tot:
        print(f"-) Total time: {round(sum(test_data), 8)}")

    if include_mean:
        print(f"-) Mean time: {round(fmean(test_data), 8)}")

    return fmean(test_data)


pygame.init()

tottime = 0
r1 = pygame.rect.Rect(0, 0, 10, 10)

tup = (5.0, 5.0)
lst = [5.0, 5.0]

ntup = (30.0, 30.0)
nlst = [30.0, 30.0]

vec1 = pygame.math.Vector2(5.0, 5.0)
vec2 = pygame.math.Vector2(30.0, 30.0)

NUMBER = 10000000
GLOB = {"r1": r1, "ntup": ntup, "nlst": nlst, "tup": tup, "lst": lst,
        "vec1": vec1, "vec2": vec2}

test_names = (
    "tup inside tup", "coll tup", "not coll tup", "coll list", "not coll list",
    "coll 2 args", "not coll 2 args", "coll unpack tuple 1->2",
    "not coll unpack tuple 1->2", "coll unpack list 1->2",
    "not coll unpack list 1->2")

test_group(
    "Sequences", [
        "r1.collidepoint(((5.0, 5.0), ))",
        "r1.collidepoint((5.0, 5.0))",
        "r1.collidepoint((30.0, 30.0))",
        "r1.collidepoint([5.0, 5.0])",
        "r1.collidepoint([30.0, 30.0])",
        "r1.collidepoint(5.0, 5.0)",
        "r1.collidepoint(30.0, 30.0)",
        "r1.collidepoint(*tup)",
        "r1.collidepoint(*ntup)",
        "r1.collidepoint(*lst)",
        "r1.collidepoint(*nlst)"
    ],
    GLOB,
    test_names
)

test_group(
    "Vectors", [
        "r1.collidepoint(vec1)",
        "r1.collidepoint(vec2)"
    ],
    GLOB,
    ("coll vector", "not coll vector")
)

itzpr3d4t0r avatar Feb 13 '23 09:02 itzpr3d4t0r

I get it going from (without this PR):

====||SEQUENCES||====
-) tup inside tup: 0.89526932 s
-) coll tup: 0.87893394 s
-) not coll tup: 0.8794718 s
-) coll list: 1.09282864 s
-) not coll list: 1.10122356 s
-) coll 2 args: 1.03318158 s
-) not coll 2 args: 1.06660838 s
-) coll unpack tuple 1->2: 1.11719524 s
-) not coll unpack tuple 1->2: 1.1178481 s
-) coll unpack list 1->2: 1.31008738 s
-) not coll unpack list 1->2: 1.24720098 s
______________
-) Mean time: 1.06725899

====||VECTORS||====
-) coll vector: 0.95589292 s
-) not coll vector: 0.90819832 s
______________
-) Mean time: 0.93204562

to (with this PR):

====||SEQUENCES||====
-) tup inside tup: 0.8181443 s
-) coll tup: 0.75252392 s
-) not coll tup: 0.74443626 s
-) coll list: 1.00662154 s
-) not coll list: 0.95291206 s
-) coll 2 args: 0.85712456 s
-) not coll 2 args: 0.85301936 s
-) coll unpack tuple 1->2: 1.01843844 s
-) not coll unpack tuple 1->2: 1.01575796 s
-) coll unpack list 1->2: 1.18465654 s
-) not coll unpack list 1->2: 1.18172594 s
______________
-) Mean time: 0.94412372

====||VECTORS||====
-) coll vector: 0.8472964 s
-) not coll vector: 0.85649714 s
______________
-) Mean time: 0.85189677

Process finished with exit code 0

Seems about 10% faster all over.

MyreMylar avatar Feb 18 '23 11:02 MyreMylar

I'll be reverting the implementation in rect.collidepoint as an example because of the changes that were made to the rect module.

itzpr3d4t0r avatar Mar 21 '23 14:03 itzpr3d4t0r

This PR is not ready for merge, so I'm marking it as a draft.

Starbuck5 avatar Dec 11 '23 04:12 Starbuck5