microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.19k stars 12.38k forks source link

small code change causes 70% build time regression (20s->34s) [strictGenericChecks] #18646

Open emmanueltouzery opened 6 years ago

emmanueltouzery commented 6 years ago

TypeScript Version: 2.6.0-dev.20170921

Code Sorry it's a bit bigger codebase, but it would be very hard I guess to reproduce a performance issue with little code. If you pull https://github.com/emmanueltouzery/prelude.ts and run npm install and then tsc.

The difference between both tags is very small! https://github.com/emmanueltouzery/prelude.ts/compare/v0.2.1...v0.2.2 6 files changed, 8 insertions(+), 5 deletions(-) (mostly I export an interface which was not marked as exported)

And also if I build with strictGenericChecks: false, the build time collapses from 34 seconds to 5 seconds even for v0.2.2.

Expected behavior: A bit slower build with strictGenericChecks enabled, same build time for 0.2.1 and 0.2.2.

Actual behavior: Almost 7 times slower build time with strictGenericChecks, 70% build time increase between 0.2.1 and 0.2.2.

emmanueltouzery commented 6 years ago

I think the performance is even worse in the equals_experiments branch of the same repo (currently commit c09a286e90d06db0beb7ce4922ed30d479a55ae2). it's slightly worse in runtime than master on my laptop, but on my older desktop I killed it after 3 minutes.

emmanueltouzery commented 6 years ago

sorry, correcting my previous comment, I tested the wrong code on my laptop: the equals_experiment branch is building for minutes at a time on both my laptop and home computer. Killed it after 3 minutes 20 on my fast laptop.

It's probably code like this that makes it explode:

equals(other: Foldable<T&WithEquality>|Collection<T&WithEquality>): boolean;
sandersn commented 6 years ago

After diffing 0.2.1 and 0.2.2 I find that the culprit is a change from Seq to Vector, not the difference in exports. It's almost certain that the change causes us to compare some Seq<T> and Vector<U> structurally somewhere now, where before Seq<T> and Seq<U> could be compared just by comparing T and U. I'll investigate further to track down the exact cause.

sandersn commented 6 years ago

The problem is indeed Vector<T> ==> Seq<U> assignments; when I remove the <Seq<number>> cast on line 63 of tests/Option.ts, compile time goes back down to the same as 0.2.1. And if I add more casts by cloning that test with different types, each one adds about 13 seconds to the compile time.

I'll look to see if we can improve the time it takes to relate Vector to Seq.

sandersn commented 6 years ago

I can also improve compile time down to 4.2 seconds (on my machine) by removing assignments to Seq. See https://github.com/sandersn/prelude.ts/commit/cf627ceb5585bf4ca4e872353a532a09db034e9c in the ts-perf-boost branch for what I did.

emmanueltouzery commented 6 years ago

Thanks for the tip, I understand how you sped it up, but in the end Seq is useful to me, to make sure I have about the same methods in all the 'sequence-like' classes (although it's not really useful to users of the library as type signatures are less precise on Seq, so I don't export it from the library in the index.ts).

So I would keep for instance Vector implementing Seq, otherwise I might as well remove Seq completely. The build time is not a blocker for me (it's OK since 2.5.3 now), but I thought you might want to know about the regression and have a good test to reproduce this slowness which could crop up in other applications elsewhere (which might be closed source) I guess.

sandersn commented 6 years ago

I'm checking right now to see why our caching fails on Seq relatability, so I hope I will find a real solution instead of an unsafe workaround.

emmanueltouzery commented 6 years ago

FYI this is still an issue with typescript 2.9.1. My prelude.ts library has less than 7000 LOC of typescript, tess than 6000 without comments, and needs 45 seconds to build :( [on a slow computer admittedly but still].

I think it's because I use lots of intersection types (eg T & WithEquality).