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

Optimize simplifying paths for faster project generation #857

Merged
merged 2 commits into from
May 12, 2020

Conversation

akkyie
Copy link
Contributor

@akkyie akkyie commented May 8, 2020

We are using XcodeGen with a ~3000 files project, and the project generation for it takes about 3s.
I wanted to know what's taking time, and Instruments told me that the time of Path.simplifyingParentDirectoryReferences calls reaches almost 30% of the whole.
I also found that repeated invocation of Path.+ is time-consuming as it causes String copying and conversion between NSString.

This looks kind of overkill to me, because most of the paths in our project don't include parent path reference nor have trailing slashes. So, this change avoids Path.+ when the path does not include .. in its middle, while manually removing trailing slashes with a simpler way instead.
It cuts off our project generation time down to about 2/3 (2s). I think it's not common case where many paths in a project needs the actual simplification, but the overhead of this change for these cases would be ignorable.

I didn't completely rewrite the whole function to minimize the possibility of regression for special cases. I want to know if even this fast-path has any patterns to cause regression.

Before After
before after
PathKit

@@ -11,7 +11,14 @@ extension Path {
/// - `../a/b` simplifies to `../a/b`
/// - `a/../../c` simplifies to `../c`
public func simplifyingParentDirectoryReferences() -> Path {
normalize().components.reduce(Path(), +)
if !string.contains("..") { // Skip simplifying if its already simple
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need to look for ../ instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry for late response. Wouldn't it be like if !(string.contains("/..") || string.contains("../")) if we want it to match real parent references only?
I preferred to keep it simple than perfect because false positives like ./file..name/ or ... are edge cases and won't be big problems IMO, while false negatives can break things.
I guess we could possibly rewrite the complete normalization by ourselves to get both better performance and correctness, as a future task maybe.

@brentleyjones
Copy link
Collaborator

This makes our project generation 1-2 seconds faster (~9%).

Copy link
Collaborator

@brentleyjones brentleyjones left a comment

Choose a reason for hiding this comment

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

I think this is good as is (but would welcome a rewrite of the normalization as a future PR).

Thanks @akkyie!

@brentleyjones brentleyjones merged commit 2ed9a81 into yonaskolb:master May 12, 2020
@akkyie
Copy link
Contributor Author

akkyie commented May 12, 2020

Thanks! I'll find time to give it a try 👍

@akkyie akkyie deleted the optimize-path-simplification branch May 12, 2020 15:31
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