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

Make object faster maybe similar to https://v8.dev/blog/fast-properties #122

Open
Bnaya opened this issue Jun 29, 2020 · 6 comments
Open
Labels
Mission Impossible Worth to mention, but impossible to do

Comments

@Bnaya
Copy link
Owner

Bnaya commented Jun 29, 2020

No description provided.

@Bnaya Bnaya added the Mission Impossible Worth to mention, but impossible to do label Jun 29, 2020
@emibcn
Copy link

emibcn commented Feb 5, 2021

Hi! Have you done some profiling/benchmarking? If yes, what are the results you've got?

I've just published a library similar to this one (@3m1/binary-object), but with fixed schema defined using in-class @decorators. I archived a 2-3 times slower instantiation/read/write operations compared to normal JS objects, with an extra 2-3 times heap memory usage on instantiation. If this is good for you, I can take a look into this issue and, if I'm able, apply here some of the work done in my lib.

@Bnaya
Copy link
Owner Author

Bnaya commented Feb 6, 2021

Hey @emibcn :)
There's automatic self-benchmarks on each PR:
#146 (comment)
For various factors, IMO we can't effectively compare this library to native js objects.

Anyhow, I would love to collaborate about this topic!

I think that the "free shape" + automatic memory reclaim brings many difficulties
I will throw in some of the challenges to make fast props, or cheap objects:
We will need to have an objects shape registry, a way to compute object registry, and a cheap way to search the registry to see if this share is already exists.
(every shape will need to have reference count so we know when we can re claim it)
And a very painful code path that we will must have is, when object shape changes, we will need to turn it into slow object, or assign it a new shape.
All that is a lot of code, with unclear performance benefits (yet)

@emibcn
Copy link

emibcn commented Feb 7, 2021

I think that the "free shape" + automatic memory reclaim brings many difficulties

Me too. This is why I did mine without automatic memory and fixed shape 😜 Well, not only because of complexity, but also versatility. And maybe this would be a solution: let the user decide how to manage the object via some parameters:

We will need to have an objects shape registry, a way to compute object registry, and a cheap way to search the registry to see if this share is already exists.
(every shape will need to have reference count so we know when we can re claim it)

This is going to be a JS re-programming, but using JS itself, which performance is not always as expected. Have you considered adding some WASM to this project?

And a very painful code path that we will must have is, when object shape changes, we will need to turn it into slow object, or assign it a new shape.

Here is when we can let the user decide, using some of the options as default: it's not the same to handle a bunch of objects changing very fast than millions of objects rarely changing.

All that is a lot of code, with unclear performance benefits (yet)

I have taken several dead-end paths because of performance. But I had lot of fun walking those paths ;)

@moomoolive
Copy link

moomoolive commented Apr 11, 2022

Hey @Bnaya ,

I know I'm late to the party, but I think I've figured out a way create very fast objects that are backed by buffers.

Essentially what you do is create classes on the fly via the unsafe Function constructor that maps key names to a particular offsets in a typed array via getters and setters.

Here's an example:

// your object definition
const def = {x: "num", y: "num"}

// create a class based on definition
const MyObject = Function(`return class MyBufferObject {
  constructor() {
    this._memory = new Float64Array(${Object.keys(def).length})
  }

  ${Object.keys(def).map((key, offset) => {
    const getter = `get ${key}() { return this._memory[${offset}] }`
    const setter = `set ${key}(newValue) { this._memory[${offset}] = newValue }`
    return getter + ";" + setter
  }).join("\n")}
}
`)()

// now you can use it like a normal object
const obj = new MyObject()
obj.x = 2
obj.y = 5
const {x, y} = obj
console.log(x, y) // output: 2 5

From my benchmarking, objects created this way are just as fast as native objects.

Anyhow, I though I'd give you my two cents on the issue.

@Bnaya
Copy link
Owner Author

Bnaya commented Apr 16, 2022

@moomoolive thank you for the research!
The library supports dynamic object shape which means we can't ahead of time create fixed getters and settres, among other things.

@moomoolive
Copy link

Fair enough! This approach wouldn't really work with dynamic objects.

PS this library is such a good idea - I really hope js supports something like this out of the box in the future

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Mission Impossible Worth to mention, but impossible to do
Projects
None yet
Development

No branches or pull requests

3 participants