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

Q vs. Bluebird performance #381

Closed
davidvgalbraith opened this Issue Nov 11, 2014 · 9 comments

Comments

Projects
None yet
8 participants
@davidvgalbraith
Copy link

davidvgalbraith commented Nov 11, 2014

Hi! In #63, @petkaantonov makes some big statements about Bluebird's performance as compared with Q: it's 100 times faster and uses 5% of the memory. Wow! I've been wondering since I read that, how were such dramatic gains achieved? What were some of the key backend changes that let you more or less preserve Q's semantics while just totally wiping the floor with it in terms of performance? Thanks!

@spion

This comment has been minimized.

Copy link
Collaborator

spion commented Nov 11, 2014

As far as I know, its because one of the primary goals of Q is to provide certain security properties of promises in browsers. Bluebird on the other hand is designed for performance, to be used in environments such as node where the entire code is fully trusted.

Here is one example: you can fulfill a pending promise using promise._fulfill(value). You shouldn't do that - its not part of the official API, and the method is clearly marked private, but its still possible. In the presence of hostile consumers in the browser, this is not acceptable: the consumer should be unable to mutate the value of a promise as that may affect other consumers that don't trust it. For more information, see this Mark S Miller talk: "Secure Distributed Programming on ECMAScript 5 + HTML5 Platforms".

Unfortunately, at the moment there is no efficient way to implement this kind of security, although certain implementations of WeakMaps look promising.

@benjamingr

This comment has been minimized.

Copy link
Collaborator

benjamingr commented Nov 11, 2014

Also because Petka built bluebird knowing how the JIT works in node and
modern browsers at a good level.
On Tue, Nov 11, 2014 at 21:39 Gorgi Kosev notifications@github.com wrote:

As far as I know, its because one of the primary goals of Q is to provide
certain security properties of promises in browsers. Bluebird on the other
hand is designed for performance, to be used in environments such as node
where the entire code is fully trusted.

Here is one example: you can fulfill a pending promise using
promise._fulfill(value). You shouldn't do that - its not part of the
official API, and the method is clearly marked private, but its still
possible. In the presence of hostile consumers in the browser, this is not
acceptable: the consumer should be unable to mutate the value of a promise
as that may affect other consumers that don't trust it. For more
information, see this Mark S Miller talk: "Secure Distributed Programming
on ECMAScript 5 + HTML5 Platforms"
http://www.infoq.com/presentations/Secure-Distributed-Programming.

Unfortunately, at the moment there is no efficient way to implement this
kind of security, although certain implementations of WeakMaps look
promising.


Reply to this email directly or view it on GitHub
#381 (comment)
.

@stefanpenner

This comment has been minimized.

Copy link
Contributor

stefanpenner commented Nov 11, 2014

Some of the largest wins come from making significantly fewer memory allocations, others come from fine tuning for the VM. But in general poor JS performance is tied to excess allocations which then force the GC to steal cycles from you.

As @spion said, hopefully run-times will provide us with the needed machinery to permanently implement private state. Until this happens any implementation that provides these sort of safety will be slower. Although I suspect Q's performance can be dramatically improved while retaining its security, it will unfortunately be held back by the runtimes.

@petkaantonov

This comment has been minimized.

Copy link
Owner

petkaantonov commented Nov 11, 2014

Avoiding object allocations, specifically inline function definitions, at all costs get your pretty far.

@ORESoftware

This comment has been minimized.

Copy link

ORESoftware commented Oct 14, 2015

@petkaantonov i know this is your lib but by inline functions do you mean function declarations/expressions? "inline" is one of those words that can mean different things

@ORESoftware

This comment has been minimized.

Copy link

ORESoftware commented Oct 14, 2015

http://stackoverflow.com/questions/19159703/what-is-the-difference-between-anonymous-and-inline-functions-in-javascript

I guess "inline" functions mean both function expressions and function declarations in JS, so maybe there is some use to the term "inline" as a catch-all term.

however, from the naive perspective, anonymous functions are actually the MOST inline of all of the above, so frankly I am not a fan of using that term for this purpose.

@bergus

This comment has been minimized.

Copy link
Contributor

bergus commented Oct 15, 2015

@ORESoftware I think the following sentence from the answer to the linked question sums it up pretty nicely:

An inline function is a function [assigned to a variable] that is created at runtime instead of at parsetime.

His examples are wrong however, they're not showing the problem, and it doesn't make a difference whether the function is created using a declaration or an expression (anonymous or not). The key part is that the function is created at runtime - multiple times, within ("inline" of) another function that gets called multiple times.

@phpnode

This comment has been minimized.

Copy link

phpnode commented Oct 15, 2015

"inline" in this context refers to V8's ability to inline the body of another function into its callsite. For a simple example, V8 can transform:

function doSomething (a, b) {
  return add(a, b);
}

function add (a, b) {
  return a + b;
}

into

function doSomething (a, b) {
  return a + b;
}

(V8's transformation happens using an intermediate representation, it doesn't manipulate the actual source)

Because V8 was able to remove the overhead of the function call, doSomething() will now be significantly faster.

Petka's sentence refers to purposely writing code which V8 can inline, avoiding any constructs which prevent it.

@spion

This comment has been minimized.

Copy link
Collaborator

spion commented Oct 15, 2015

Hmm. I understood it as "avoiding object allocations (those caused by creating closures in particular) at all costs get you pretty far" - more info in Trevor's article

Also AFAIK if the function is not a closure (doesn't refer to things outside its variable scope and is not included in the return result of the enclosing function), V8 will know how to avoid re-allocating it over and over probably be able to save on allocations a little.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.