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

Very slow on babel+rollup ES6/ES7 compilation #39

Closed
thednp opened this issue Jan 14, 2020 · 8 comments
Closed

Very slow on babel+rollup ES6/ES7 compilation #39

thednp opened this issue Jan 14, 2020 · 8 comments

Comments

@thednp
Copy link

thednp commented Jan 14, 2020

I've made a lebab conversion of your code, imported into my test setup and my compilation time jumped from 700-1100ms to 15-17s.

I've searched the web all day for a solution, people talk about leaky scripts, I've re-installed node.js couple of times, searched for self executing anonymous functions, and other shenanigands, I didn't realize it's your script until I made a build without your it.

Any plans to help solve this issue?

@gre
Copy link
Owner

gre commented Jan 15, 2020

I'm not sure to understand why a small lib like this one is slow but I can provide a es module entry

@thednp
Copy link
Author

thednp commented Jan 15, 2020

I made an ES6 class in about 5 min, still same thing:

export default class CubicBezierClass {
  constructor(mX1, mY1, mX2, mY2){
    this.newtonIterations = 4;
    this.newtonMinSlope = 0.001;
    this.subdivisionPrecision = 0.0000001;
    this.subdivisionMaxIterations = 10;

    this.mX1 = mX1
    this.mY1 = mY1
    this.mX2 = mX2
    this.mY2 = mY2
    
    this.kSplineTableSize = 11;
    this.kSampleStepSize = 1.0 / (this.kSplineTableSize - 1.0);
    
    this.float32ArraySupported = typeof Float32Array === 'function';

    // Precompute samples table
    this.sampleValues = this.float32ArraySupported ? new Float32Array(this.kSplineTableSize) : new Array(this.kSplineTableSize);
    for (let i = 0; i < this.kSplineTableSize; ++i) {
      this.sampleValues[i] = this.calcBezier(i * this.kSampleStepSize, mX1, mX2);
    }    
    return this.CubicBezier (mX1, mY1, mX2, mY2)
  }
  A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
  B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
  C (aA1)      { return 3.0 * aA1; }
  
  // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
  calcBezier (aT, aA1, aA2) { return ((this.A(aA1, aA2) * aT + this.B(aA1, aA2)) * aT + this.C(aA1)) * aT; }
  
  // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
  getSlope (aT, aA1, aA2) { return 3.0 * this.A(aA1, aA2) * aT * aT + 2.0 * this.B(aA1, aA2) * aT + this.C(aA1); }
  
  binarySubdivide (aX, aA, aB) {
    let currentX, currentT, i = 0;
    do {
      currentT = aA + (aB - aA) / 2.0;
      currentX = this.calcBezier(currentT, this.mX1, this.mX2) - aX;
      if (currentX > 0.0) {
        aB = currentT;
      } else {
        aA = currentT;
      }
    } while (Math.abs(currentX) > this.subdivisionPrecision && ++i < this.subdivisionMaxIterations);
    return currentT;
  }
  
  newtonRaphsonIterate (aX, aGuessT) {
   for (let i = 0; i < this.newtonIterations; ++i) {
     let currentSlope = this.getSlope(aGuessT, this.mX1, this.mX2);
     if (currentSlope === 0.0) {
       return aGuessT;
     }
     let currentX = this.calcBezier(aGuessT, this.mX1, this.mX2) - aX;
     aGuessT -= currentX / currentSlope;
   }
   return aGuessT;
  }
  getTForX (aX) {
    let intervalStart = 0.0;
    let currentSample = 1;
    let lastSample = this.kSplineTableSize - 1;

    for (; currentSample !== lastSample && this.sampleValues[currentSample] <= aX; ++currentSample) {
      intervalStart += this.kSampleStepSize;
    }
    --currentSample;

    // Interpolate to provide an initial guess for t
    let dist = (aX - this.sampleValues[currentSample]) / (this.sampleValues[currentSample + 1] - this.sampleValues[currentSample]);
    let guessForT = intervalStart + dist * this.kSampleStepSize;

    let initialSlope = this.getSlope(guessForT, this.mX1, this.mX2);
    if (initialSlope >= this.newtonMinSlope) {
      return this.newtonRaphsonIterate(aX, guessForT);
    } else if (initialSlope === 0.0) {
      return guessForT;
    } else {
      return this.binarySubdivide(aX, intervalStart, intervalStart + this.kSampleStepSize);
    }
  }
  CubicBezier (mX1, mY1, mX2, mY2) {
    if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
      throw new Error('bezier x values must be in [0, 1] range');
    }
  
    if (mX1 === mY1 && mX2 === mY2) {
      return function (x) {
        return x;
      };
    }

    let BezierEasing;

    return BezierEasing = x => {
      // Because JavaScript number are imprecise, we should guarantee the extremes are right.
      return x === 0 || x === 1 ? x : this.calcBezier(this.getTForX(x), mY1, mY2);
    }
  }
}

Updated, this one really does bezier, but still slow compile.

@gre
Copy link
Owner

gre commented Jan 15, 2020

do you have a reproductible minimal example that build it slow?

@thednp
Copy link
Author

thednp commented Jan 15, 2020

Yea, there you go
CubicBezier.zip

npm install

npm run build

15s on my machine

@thednp
Copy link
Author

thednp commented Jan 15, 2020

Another big problem is the returned function having no name, making it difficult to track.

@thednp
Copy link
Author

thednp commented Jan 15, 2020

In the above code I've updated and fixed the functionName issue. The major leak needs to be solved. Perhaps the code needs to be simplified. IDK, I will do some research and provide some feedback.

@gre
Copy link
Owner

gre commented Jan 15, 2020

what i don't understand is there is not this constructor.name = code in the code. i'll later test if providing a es module target would help

@thednp
Copy link
Author

thednp commented Jan 15, 2020

@gre please delete that line, use the above code, it's updated to fix the function name issue.

@thednp thednp closed this as completed Jan 16, 2020
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

No branches or pull requests

2 participants