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

Improve performance and reduce memory footprint during generation of complex trees #46

Merged
merged 1 commit into from
Jul 24, 2021

Conversation

samipfjo
Copy link
Contributor

@samipfjo samipfjo commented Jun 28, 2021

Since we don't dynamically add instance variables to objects during runtime, we can leverage __slots__ to remove the Leaf, Stem, and Tree classes' __dict__ attribute. This reduces memory requirements and increases performance on complex trees. Really doesn't make a difference for Tree, but I added anyway for consistency.

It doesn't make a difference in simple trees, but in complex trees like the Weeping Willow that have boatloads of branches and leaves it makes a significant difference. My tests show it shaves off about 11 seconds from generating a Weeping Willow while making no statistically significant difference for Black Oak.

I have apparently lost the memory benchmarks from these runs (I did them a while back), but since this removes the __dict__ attribute from each class it's not possible for the footprint to be worse.

W/O __slots__

Tree: Black Oak
Seed: 8684998

Avg of 4 runs:
create_branches: 3.99 seconds
create_leaf_mesh: 7.77 seconds
Tree generated in 11.75 seconds

Tree: Weeping Willow
Seed: 8684998

Avg of 4 runs:
create_branches: 76.21 seconds
create_leaf_mesh: 18.00 seconds
Tree generated in 93.86 seconds

====

__slots__

Tree: Black Oak
Seed: 8684998

Avg of 4 runs:
create_branches: 4.01 seconds
create_leaf_mesh: 8.00 seconds
Tree generated in 11.78 seconds

Tree: Weeping Willow
Seed: 8684998

Avg of 4 runs:
create_branches: 65.62 seconds
create_leaf_mesh: 16.95 seconds
Tree generated in 82.26 seconds

Add __slots__ declarations and move instance variables into __init__

Replace tabs with spaces
@samipfjo samipfjo force-pushed the slots-performance-improvement branch from 82ba117 to 0eb7a20 Compare June 28, 2021 20:42
@samipfjo
Copy link
Contributor Author

Squashed a fix for a dumb mistake

@samipfjo
Copy link
Contributor Author

If you want to run your own tests, I used the decorator function below to run accurate benchmarks. The code is a modified version of the SO answer here.

import time
import os
import functools

def track(func):
    
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.process_time()
        result = func(*args, **kwargs)
        elapsed_time = time.process_time() - start

        print("\n{}: exec time: {}\n".format(
            func.__name__,
            elapsed_time))
        return result

    return wrapper

@friggog
Copy link
Owner

friggog commented Jun 29, 2021

Nice! Do we need to bump the version for a new release?

@samipfjo
Copy link
Contributor Author

I mean, it's a substantial improvement but ultimately a minor change. If we use the major.minor.patch format for versioning I guess it would count as a minor increment.

@samipfjo
Copy link
Contributor Author

@friggog Reminder that this needs merging when you get a chance

@friggog friggog merged commit 4ccb8bf into friggog:master Jul 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants