Skip to content

Conversation

@lihaoyi
Copy link
Contributor

@lihaoyi lihaoyi commented Jan 14, 2026

Fixes #1628

This PR micro-optimizes the top three hotspots i found in the JProfiler profiles compiling the Netty codebase using Javac in Zinc in Mill

sortBy

.sortBy(x => x.toUri().toString()) creates a new URI object and String for every comparison during the sort - that's O(n log n) object allocations, and it's blowing up the profile on the linked issue. .sorted instead uses Path's native Comparable<Path> implementation which compares paths directly without allocating objects.

Both produce deterministic ordering (which is what's needed for reproducible content hashes). The only semantic difference is the comparison method (lexicographic path comparison vs URI string comparison), but for the purpose of consistent hashing, both work.

isDirectory

toVirtualFile called Files.isDirectory() on every file from filtered list. Added toVirtualFileForRegularFile() that skips the syscall sys we know it is already a regular file

Caching contentHash

Changed all our def contentHashes to lazy vals. Looking at the code it seems to be safe - we re-create the file instances every time, and when file metadata changes ClasspathCache creates a new VirtualFile. Furthermore, contentHashStr is already a lazy val, so it seems the code already assumes the files are re-created when changed and so it should be safe to cache the hashes

Manually tested this via publishLocal and manually reproducing the original workload in the linked issue, the performance seems to have gone back to previous levels and the profiler no longer shows toURI taking up 34% of CPU time, and the isDirectory and contentHash hotspots each taking ~5% of CPU time dropped off the profiles as well. ./mill clean && time ./mill __.compile in the Netty codebase dropped from ~15s to ~8.5s

@lihaoyi
Copy link
Contributor Author

lihaoyi commented Jan 14, 2026

CC @eed3si9n for review, looks like CI is green

@lihaoyi lihaoyi changed the title Avoid calling expensive.toUri.toString and just sort paths directly Avoid calling expensive.toUri.toString and other micro-optimizations Jan 14, 2026
Copy link
Member

@eed3si9n eed3si9n left a comment

Choose a reason for hiding this comment

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

Thanks!

@eed3si9n eed3si9n merged commit 5a6c5f7 into sbt:develop Jan 14, 2026
9 checks passed
@lihaoyi
Copy link
Contributor Author

lihaoyi commented Jan 14, 2026

Thanks for the merge @eed3si9n. Could I request a milestone release one of these days? I'd like to include this fix in Mill 1.1.0 which should go out Wed 21 Jan

@eed3si9n
Copy link
Member

Sounds good.

@lihaoyi
Copy link
Contributor Author

lihaoyi commented Jan 22, 2026

Ping on this @eed3si9n, since Scala 3.8.1 is out and a Zinc release with this PR is the only thing blocking Mill 1.1.0 final.

@eed3si9n
Copy link
Member

Sorry about that. I'll try to get this out today.

@eed3si9n
Copy link
Member

@lihaoyi
Copy link
Contributor Author

lihaoyi commented Jan 23, 2026

Thanks eugene!

lihaoyi added a commit to com-lihaoyi/mill that referenced this pull request Jan 23, 2026
Pulls in latest version of Zinc with
sbt/zinc#1629 to improve performance
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.

Significant slowdown in Zinc 2.0.0-M11

2 participants