Repository navigation
Optimize vector creation/update using pg_VectorCoordsFromObj - #3458
Conversation
Rather than using pgVectorCompatible_Check and then PySequence_AsVectorCoords, which have duplicative operations, we can use pg_VectorCoordsFromObj to try to unpack directly for a speedup when processing sequence input.
ankith26
left a comment
There was a problem hiding this comment.
I did some benchmarking on Ubuntu 25.04 and found the results to be highly variable across different attempts. This one time I got all numbers in the 30% - 50% improvement range but in another attempt I got both branches to be roughly the same with this PR only marginally better.
I suppose this makes sense given the current time is low enough as it is, in such cases performance measurements no longer become super reliable. All we can say for sure is that it improves performance by some bit, and it makes the code simpler so it's good reason to approve this PR, thanks! π
|
I also noticed the |
|
We can say for sure that this should improve performance, it's not like I just moved stuff around, pg_VectorCoordsFromObj uses a subset of the calls that the other functions do combined. Anyway there are some other instances but I would not like to do them in this PR, keep this PR simple and just do a few functions. |
|
Hmmmm, I'm not so sure about this... I used (calculated as (pull_time - main_time) / main_time * 100) |
|
If |
Here's my test scriptimport pygame
from timeit import repeat
from functools import partial
def test_create(cls, *args, iterations=1000000):
return sum(repeat(partial(cls, *args), number = iterations))
print("Vector2()\t\t", test_create(pygame.Vector2))
print("Vector2(int-int)\t", test_create(pygame.Vector2, 24,12))
print("Vector2(float-float)\t", test_create(pygame.Vector2, 24.2,12.9))
print("Vector2(int-tuple)\t", test_create(pygame.Vector2, (24,12)))
print("Vector2(float-tuple)\t", test_create(pygame.Vector2, (24.2,12.9)))
print("Vector2(int)\t\t", test_create(pygame.Vector2, 24))
print("Vector2(float)\t\t", test_create(pygame.Vector2, 24.2))
print("Vector2(Vector2)\t", test_create(pygame.Vector2, pygame.Vector2(24.2,12.9)))
print("Vector2(str)\t\t", test_create(pygame.Vector2, repr(pygame.Vector2(24.2,12.9))))
print("Vector3()\t\t", test_create(pygame.Vector3))
print("Vector3(int-int)\t", test_create(pygame.Vector3, 24,12,4))
print("Vector3(float-float)\t", test_create(pygame.Vector3, 24.2,12.9,4.2))
print("Vector3(int-tuple)\t", test_create(pygame.Vector3, (24,12,4)))
print("Vector3(float-tuple)\t", test_create(pygame.Vector3, (24.2,12.9,4.2)))
print("Vector3(int)\t\t", test_create(pygame.Vector3, 24))
print("Vector3(float)\t\t", test_create(pygame.Vector3, 24.2))
print("Vector3(Vector3)\t", test_create(pygame.Vector3, pygame.Vector3(24.2,12.9,4.2)))
print("Vector3(str)\t\t", test_create(pygame.Vector3, repr(pygame.Vector3(24.2,12.9,4.2))))
def test_update(instance, *args, iterations=1000000):
return sum(repeat(partial(instance.update, *args), number = iterations))
print("Vector2.update(int-int)\t", test_update(pygame.Vector2(24.2,12.9), 27.2, 23.1))
print("Vector2.update(int-tuple)\t", test_update(pygame.Vector2(24.2,12.9), (27.2, 23.1)))
print("Vector2.update(int)\t\t", test_update(pygame.Vector2(24.2,12.9), 27.2))
print("Vector2.update(Vector2)\t\t", test_update(pygame.Vector2(24.2,12.9), pygame.Vector2(14.2,10.9)))
print("Vector3.update(int-int)\t", test_update(pygame.Vector3(24.2,12.9,4.2), 27.2, 23.1, 62.9))
print("Vector3.update(int-tuple)\t", test_update(pygame.Vector3(24.2,12.9,4.2), (27.2, 23.1, 62.9)))
print("Vector3.update(int)\t\t", test_update(pygame.Vector3(24.2,12.9,4.2), 27.2))
print("Vector3.update(Vector3)\t\t", test_update(pygame.Vector3(24.2,12.9,4.2), pygame.Vector3(14.2,10.9,42.2)))Here's a sample csv of my results, the first data column is your pull, the second data column is mainVector2(),0.18141399999149144,0.1956771002151072
Vector2(int-int),0.3431495000841096,0.35592650016769767
Vector2(float-float),0.27297670010011643,0.278007100103423
Vector2(int-tuple),0.3280133999651298,0.3831212999066338
Vector2(float-tuple),0.25656020012684166,0.32770409993827343
Vector2(int),0.27341980033088475,0.2757786998990923
Vector2(float),0.2362144001526758,0.24694119987543672
Vector2(Vector2),0.2150278000626713,0.22204600006807595
Vector2(str),1.2432881002314389,1.2415092998417094
Vector3(),0.1823664001422003,0.18075780000071973
Vector3(int-int),0.43637820007279515,0.4344247999833897
Vector3(float-float),0.34569360001478344,0.33218510006554425
Vector3(int-tuple),0.35870049986988306,0.4514008000260219
Vector3(float-tuple),0.26794569997582585,0.39183720014989376
Vector3(int),0.27129990002140403,0.28120390011463314
Vector3(float),0.23677530023269355,0.25552330003120005
Vector3(Vector3),0.21837150014471263,0.22957930015400052
Vector3(str),1.6838350999169052,1.7100850999122486
Vector2.update(int-int),0.2269032000331208,0.22657820023596287
Vector2.update(int-tuple),0.19853689998853952,0.2836833999026567
Vector2.update(int),0.19830159994307905,0.18359799997415394
Vector2.update(Vector2),0.16061399993486702,0.17089750000741333
Vector3.update(int-int),0.2782052999828011,0.2611844999482855
Vector3.update(int-tuple),0.22197650000452995,0.33471639989875257
Vector3.update(int),0.18535450019408017,0.1842459999024868
Vector3.update(Vector3),0.1674094998743385,0.17589529987890273Here's my csv analysis scriptimport csv
diffs: dict[str, float] = {}
with open("results.csv", "r") as data:
csv_reader = csv.reader(data.readlines())
for line in csv_reader:
func = line[0]
pull_value = float(line[1])
main_value = float(line[2])
percent_diff = ((pull_value - main_value) / main_value) * 100
diffs[func] = percent_diff
from pprint import pprint
pprint(diffs) |
You're right, I'm tired lol |
Rather than using
pgVectorCompatible_Checkand thenPySequence_AsVectorCoords, which have duplicative operations, we can usepg_VectorCoordsFromObjto try to unpack directly, for a speedup when processing sequence input.This also shrinks the code (nice for an optimization to do that).
I ran benchmarks and averaged results, here are the benchmarks that changed by 3% or more.
I don't understand the slowdowns seen in Vector3 construction, because they don't happen in Vector2/3 update or Vector2 creation. If you read through the code of the 3 helper methods in the scope of this PR it should be unequivocally faster. But I didn't think it was worth just changing vector2, and I think the improvement is worth it overall. I'm interested if somebody not on MSVC gets the same results there.
Basic testing script