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

Rewrite SharedArray to use goja.DynamicArray #1848

Merged
merged 3 commits into from
Feb 16, 2021

Conversation

mstoykov
Copy link
Contributor

@mstoykov mstoykov commented Feb 8, 2021

This should make it considerably faster, but probably more importantly, a
lot easier to reason about and also supporting all operations supported
by a normal Array in JavaScript.

From my quick testing it seems that now the difference even for 10
elements is within 5% CPU difference, which IMO is even within the
margin of error.

fixes #1820

This should make it considerably faster, but probably more importantly, a
lot easier to reason about and also supporting all operations supported
by a normal Array in JavaScript.

From my quick testing it seems that now the difference even for 10
elements is within 5% CPU difference, which IMO is even within the
margin of error.

fixes #1820
@mstoykov mstoykov requested review from imiric and na-- February 8, 2021 16:34
@mstoykov mstoykov added this to the v0.31.0 milestone Feb 8, 2021
@codecov-io
Copy link

codecov-io commented Feb 8, 2021

Codecov Report

Merging #1848 (3ae3a2f) into master (c6dec36) will decrease coverage by 0.01%.
The diff coverage is 56.52%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1848      +/-   ##
==========================================
- Coverage   71.60%   71.58%   -0.02%     
==========================================
  Files         179      179              
  Lines       13928    13955      +27     
==========================================
+ Hits         9973     9990      +17     
- Misses       3323     3329       +6     
- Partials      632      636       +4     
Flag Coverage Δ
ubuntu 71.53% <56.52%> (-0.02%) ⬇️
windows 70.10% <56.52%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
js/modules/k6/data/share.go 53.84% <53.84%> (+3.84%) ⬆️
js/modules/k6/data/data.go 66.66% <71.42%> (+4.16%) ⬆️
lib/executor/vu_handle.go 93.33% <0.00%> (-1.91%) ⬇️
js/bundle.go 91.94% <0.00%> (+0.10%) ⬆️
lib/testutils/minirunner/minirunner.go 80.43% <0.00%> (+4.34%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c6dec36...3ae3a2f. Read the comment docs.

Copy link
Contributor

@imiric imiric left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks much better without the RunString wrappers 👍

Just left a few comments I probably should've made in the previous PR. :)

return o;
};
if goja.IsUndefined(val) {
return nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this check be done first, before the s.freeze() call?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just rewrote the JS snippet that was before in golang + goja. I don't think it matters ... the snippet was provided by @na-- and the original code doesn't even have the check ... so I wonder if I shouldn't just drop it?


// we specifically use JSON.parse to get the json to an object inside as otherwise we won't be
// able to freeze it as goja doesn't let us unless it is a pure goja object and this is the
// easiest way to get one.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still wondering why we stringify the array elements and then parse them back on Get(). Attempting to freeze a non-object would simply return it as is, so the stringify/parse dance doesn't seem necessary and is probably a lot of overhead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was more or less explored in dop251/goja#232 and the answer is that ... while for extremely simple values such as String and numbers it might be feasible ... for even Objects, it is likely that sharing them between goja Runtimes will lead to race conditions even if frozen.

Again the EcmaScript standard is meant for single-threaded operations ... everything in the standard (except the few Atomic and Shared stuff inside of it) is meant for only 1 thing operating on objects from it. So even if theoretically today goja could support it, tomorrow due to change that might break.

Additionally, if we don't serialize and then deserialize, we will need to actually check that things such as lambdas(which can reference outside objects inside of them) are not present. Proxies will also be problematic, as well as probably property methods and so on ... All of those things are not an issue as long as we serialize to JSON and back, because goja follows the EcmaScript standard and it actually specifically says that things like that don't get serialized 🎉 .

Again the "overhead" is minimal and IMO the possible complications far outweigh the amount of additional reasoning and code that will be needed for this to work. Also again ... telling people that their data will be serialized to JSON and back is a thing that they can reason about as well, whatever else we come up with ... likely won't be so easy to reason about and test with available tools.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for explaining, that makes sense. I think I glossed over the initial discussion in that issue. It might be good to link to it in a comment as a future reference for why this is done.

js/modules/k6/data/share.go Show resolved Hide resolved
Copy link
Member

@na-- na-- left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, and yeah, much better than before! ❤️ the new way of calling JS functions from inside of Go!

@mstoykov mstoykov merged commit 0dd04a3 into master Feb 16, 2021
@mstoykov mstoykov deleted the rewriteSharedArrayWithDynamicArray branch February 16, 2021 14:41
na-- pushed a commit that referenced this pull request Mar 1, 2021
This should make it considerably faster, but probably more importantly, a
lot easier to reason about and also supporting all operations supported
by a normal Array in JavaScript.

From my quick testing it seems that now the difference even for 10
elements is within 5% CPU difference, which IMO is even within the
margin of error.

fixes #1820
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

SharedArray doesn't work with forEach
4 participants