'Standard' vapor website drops 1.5% of requests, even at concurrency of 100!

Node.js's BigInteger.+ beats attaswift.BigInt.+ by about 3x for the specific case that's being exercised here (n = 10,000), which is precisely within expectations for a naive implementation.

Swift code
import BigInt

func fibonacci(_ n: Int) -> BigInt {
  precondition(n > 0)
  if n == 1 {
    return 0
  }
  var previous: BigInt = 0
  var current: BigInt = 1
  for _ in 2 ... n {
    let next = previous + current
    previous = current
    current = next
  }
  return current
}

let counts = [10000, 30000, 100000, 300000, 1000000]
for c in counts {
  print(c)
  var f: BigInt = 0
  let clock = ContinuousClock()
  var duration = clock.measure {
    f = fibonacci(c)
  }
  print("fibonacci: \(duration)")

  duration = clock.measure {
    print(f)
  }
  print("print: \(duration)")
}
Node.js code
function fib_loop(n) {
  if (n <= 1) {
    return BigInt(n);
  } else {
    let a = BigInt(0);
    let b = BigInt(1);
    let temp;
    for (let i = 2; i <= n; i++) {
      temp = a + b;
      a = b;
      b = temp;
    }
    return b.toString();
  }
}

let counts = [10000, 30000, 100000, 300000, 1000000];
for (let i = 0; i < counts.length; i++) {
    let c = counts[i];
    console.log(c);
    console.time("fib_loop");
    let f = fib_loop(c);
    console.timeEnd("fib_loop");

    console.time("print");
    console.log(f);
    console.timeEnd("print");
}
Interesting, but ultimately irrelevant benchmark data

Interestingly, the gap widens to ~6x on larger values:

Count node.js Swift ratio
10,000 1.558ms 4.345ms 2.78x
30,000 8.794ms 33.127ms 3.76x
100,000 69.763ms 350.025ms 5.02x
300,000 552.623ms 3056.003ms 5.52x
1,000,000 5.944s 34.368s 5.78x

(Switching to using BigUInt and += is expected to eliminate the allocation overhead. Doing that shaves off a few percentages, but it doesn't meaningfully close the gap.)

Radix conversions are particularly slow in my old library. For n = 10,000, attaswift does its decimal conversion about 7x slower than Node.js. Other values demonstrate that the latter may have an algorithmic advantage:

Count node.js Swift ratio
10,000 0.024ms 0.164ms 6.8x
30,000 0.047ms 1.199ms 25.5x
100,000 0.076ms 12.006ms 158x
300,000 0.18ms 109.942ms 611x
1,000,000 0.536ms 1273.589ms 2376x

It would be useful to follow up on these to rule out Standard Library issues. However, these are most likely due to a multitude of package-level issues. (I wrote this stuff almost a decade ago, in the Swift 2 era. Swift 4 was in beta the last time I was able to update this code.)

6 Likes