Re: [v8-users] v8 3.28, getting data from typed arrays, I'm unsure if this approach is correct (and doesn't leak)

2016-02-21 Thread Ben Noordhuis
On Sun, Feb 21, 2016 at 11:27 PM, George Corney  wrote:
> Hello,
>
> I'm working with typed arrays in v8 3.28, I've got a native function that
> takes a Float32Array from javascript and passes the float* data off to a gl
> call (glBufferData).
>
> I discovered that using just
> const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData();
> works, but not reliably, the data gets passes to glBufferData correctly most
> of the time, but not always!
>
> I've found creating a persistent handle before getting the data pointer, and
> then reseting handle after the glBufferData solves the problem, but is it
> the right approach? Am I leaking memory / risking sending incorrect data to
> glBufferData? Here's the snippet
>
> v8::Local bufferView =
> dataArg.As();
> size_t byteLength = bufferView->ByteLength();
> size_t byteOffset = bufferView->ByteOffset();
>
> v8::Persistent persistent;
> persistent.Reset(__contextORisolate, bufferView->Buffer());
>
> const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData();
> const unsigned char* bytePtr = static_cast(rawData);
>
> glBufferData(target, byteLength, bytePtr + byteOffset, usage);
> REPORT_GL_ERRORS();
>
> persistent.Reset();
>
>
> ---
>
> If this the wrong approach, I think the next thing is to use
> bufferView->Buffer()->Externalize();
> before getting the data pointer. In this case I'm then responsible for
> freeing the data - If this is necessary, could you explain how to do this?
> Can it be done without altering the ArrayBufferAllocator?
>
>
> Many thanks!
> George Corney

GetIndexedPropertiesExternalArrayData() is the wrong approach if you
plan on upgrading someday - it was removed in V8 3.29.  In your case,
I'd use GetContents() coupled with a Persistent for
keeping the arraybuffer object alive until you're done with it.

If GetContents() doesn't exist in the version of V8 you're using,
upgrade.  That's a good idea anyway because the 3.28 branch is
retired, the last update was in 2014.

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] v8 3.28, getting data from typed arrays, I'm unsure if this approach is correct (and doesn't leak)

2016-02-21 Thread Jochen Eisinger
Please note that 3.28 is a really old version of V8 which is full of known
issues and no longer maintained.

In general, you'll wait to externalize the buffer and keep a weak
persistent handle to the buffer - once the weak callback was triggered, you
know that you can free the backing store (if you no longer need it
otherwise).

More current versions of V8 also have a method
ArrayBufferView::CopyContents that allows you to access the backing store
without externalizing the underlying buffer.

On Sun, Feb 21, 2016 at 11:27 PM George Corney  wrote:

> Hello,
>
> I'm working with typed arrays in v8 3.28, I've got a native function that
> takes a Float32Array from javascript and passes the float* data off to a gl
> call (glBufferData).
>
> I discovered that using just
> const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData();
> works, but not reliably, the data gets passes to glBufferData correctly
> most of the time, but not always!
>
> I've found creating a persistent handle before getting the data pointer,
> and then reseting handle after the glBufferData solves the problem, but is
> it the right approach? Am I leaking memory / risking sending incorrect data
> to glBufferData? Here's the snippet
>
> v8::Local bufferView =
> dataArg.As();
> size_t byteLength = bufferView->ByteLength();
> size_t byteOffset = bufferView->ByteOffset();
>
> v8::Persistent persistent;
> persistent.Reset(__contextORisolate, bufferView->Buffer());
>
> const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData();
> const unsigned char* bytePtr = static_cast(rawData);
>
> glBufferData(target, byteLength, bytePtr + byteOffset, usage);
> REPORT_GL_ERRORS();
>
> persistent.Reset();
>
>
> ---
>
> If this the wrong approach, I think the next thing is to use
> bufferView->Buffer()->Externalize();
> before getting the data pointer. In this case I'm then responsible for
> freeing the data - If this is necessary, could you explain how to do this?
> Can it be done without altering the ArrayBufferAllocator?
>
>
> Many thanks!
> George Corney
>
> --
> --
> v8-users mailing list
> v8-users@googlegroups.com
> http://groups.google.com/group/v8-users
> ---
> You received this message because you are subscribed to the Google Groups
> "v8-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to v8-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] Pre-allocated array with many undefined entries - dense or sparse?

2016-02-21 Thread Michael Zhou
Thanks a lot Jokob for the clarifications.

How fast is Object.keys() on a dense array?

On Sunday, February 21, 2016 at 5:12:47 PM UTC-5, Jakob Kummerow wrote:
>
> A few clarifications:
>
> On Sat, Feb 20, 2016 at 8:18 PM, Louis Santillan  > wrote:
>
>> In JS, the size of the Array is not directly related to the index keys
>> of the Array.  In this respect, JS is memory conservative.  So, you
>> can always pre-allocate an array of 50 entries and until you add a
>> 51st entry, the runtime shouldn't have to grow the Array which will
>> then (often) make it sparse.  
>
>
> To be precise, the JS spec doesn't say anything about preallocation 
> behavior. Implementations can do whatever they think is clever. Also, I 
> don't see how adding a 51st element to a dense 50-element array would make 
> it sparse (in either the mathematical or the memory-layout sense of the 
> word).
>  
>
>> In v8, however, you can trigger sparse
>> behavior (or hashed behavior) by using poor (sub-optimal) indexing as
>> well.
>>
>> ```
>> // Memory dense, sub-optimal access array
>> var i, a = new Array( 50 );
>> for( i = 0; i < 50; i++ )
>> {
>>a[ i * 50 ] = ( i + 1 ) * 50;
>> }
>> ```
>>
>> v8 initially expects that `a` will have indexes [0...49].   It's smart
>> enough to realize that it doesn't need to allocate more memory but
>> array accesses are forever slower once your second index becomes 50 in
>> the above code.
>>
>
> For recent V8 versions, this is not correct. With the code above, the 
> array still has "fast elements" (i.e. a contiguous, non-dictionary backing 
> store) in the end.
> The general concept is true, however: at some point there's a sparseness 
> threshold where V8 will use a dictionary for the elements.
>  
>
>> Also, as you saw, you can hint to runtime your intentions for the
>> Array but touching `.length`.  This helps when you need to grow the
>> array but hurts if you truncate it.  v8 reverts to sparse behavior in
>> the truncation case.
>>
>
> Incorrect. Truncating an array does not trigger to-dictionary conversion 
> of its elements backing store.
>  
>
>> On Sat, Feb 20, 2016 at 7:11 AM, Michael Zhou
>> > wrote:
>> > From this perf https://jsperf.com/preallocating-array/27, using
>> > pre-allocated Array(size) seems the fastest.
>>
>
> Yes, those results make sense. 
>
> > On Saturday, February 20, 2016 at 8:57:20 AM UTC-5, Dean McNamee wrote:
>> >>
>> >> https://youtu.be/UJPdhx5zTaw?t=17m43s
>> >>
>> >> Not sure if that advice still stands as it's a few years old, but my
>> >> experience has been, in the general case, it is unfortunately faster
>> >> to allocate an empty array and use push() than to preallocate an array
>> >> of the desired size and populate it.  I have notes above a utility
>> >> function I wrote that said I measured a 2x improvement in using push
>> >> over Array(size), but I can't tell you now for what sort of size
>> >> values that was.
>>
>
> Preallocation behavior of Array(N) has changed over time. I believe the 
> dictionary threshold used to be N=100,000, whereas more recent V8 versions 
> assume that programmers know what they're doing and preallocate even for 
> much larger values of N.
>  
>
>> >>
>> >> As always, just try it and measure.  
>>
>
> Strong +1!
> And don't obsess about it -- even if you see a 2x difference in a 
> microbenchmark, real uses cases might have very different performance 
> characteristics.
> Keep in mind that there are no "good" and "bad" representations -- what 
> works better depends on the use case.
>  
>
>> I've also found using some of the
>> >> native methods helps in the process to understand why the performance
>> >> difference is there.
>> >>
>> >> You can probably use something like the native %HasFastProperties() to
>> >> check (this means running with --allow_natives_syntax).
>>
>
> In V8, properties != elements. You're looking for 
> %HasDictionaryElements(). 
>  
>
>> >>
>> >> There is also %_HasFastPackedElements() in Hydrogen, but I didn't look
>> >> to see what the difference is.
>>
>
> Don't use that one, it's subtle and doesn't do what you think it does. 
>  
>
>> >>
>> >> On Sat, Feb 20, 2016 at 1:05 PM, Michael Zhou
>> >>  wrote:
>> >> > If I have
>> >> >
>> >> > var arr = new Array(50); // Should be dense, I guess?
>> >> > arr[20] = 0;
>> >> > arr[40] = 1;
>> >> > arr[20] = undefined;
>> >> > var keys = Object.keys(arr);
>> >> >
>> >> > Will this access pattern make v8 think arr is a sparse array and 
>> change
>> >> > to
>> >> > using a hash table?
>>
>
> No, Object.keys() does not convert array elements to dictionary mode.
>  
>
>> >> >
>> >> > Also, is copying from old back store to new back store unavoidable 
>> when
>> >> > I
>> >> > grow the array by doing
>> >> > for (var i = 50; i < 100; i++) {
>> >> >   arr[i] = 0;
>> >> > }
>>
>
> Yes, when a backing store is grown, the old backing store's contents must 
> be copied into the new one. (V8 used to have an optimization that tried to 
> avoid this in a very specif

[v8-users] v8 3.28, getting data from typed arrays, I'm unsure if this approach is correct (and doesn't leak)

2016-02-21 Thread George Corney
Hello,

I'm working with typed arrays in v8 3.28, I've got a native function that 
takes a Float32Array from javascript and passes the float* data off to a gl 
call (glBufferData).

I discovered that using just
const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData();
works, but not reliably, the data gets passes to glBufferData correctly 
most of the time, but not always! 

I've found creating a persistent handle before getting the data pointer, 
and then reseting handle after the glBufferData solves the problem, but is 
it the right approach? Am I leaking memory / risking sending incorrect data 
to glBufferData? Here's the snippet

v8::Local bufferView = 
dataArg.As();
size_t byteLength = bufferView->ByteLength();
size_t byteOffset = bufferView->ByteOffset();

v8::Persistent persistent;
persistent.Reset(__contextORisolate, bufferView->Buffer());

const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData();
const unsigned char* bytePtr = static_cast(rawData);

glBufferData(target, byteLength, bytePtr + byteOffset, usage);
REPORT_GL_ERRORS();

persistent.Reset();


---

If this the wrong approach, I think the next thing is to use 
bufferView->Buffer()->Externalize();
before getting the data pointer. In this case I'm then responsible for 
freeing the data - If this is necessary, could you explain how to do this? 
Can it be done without altering the ArrayBufferAllocator? 


Many thanks!
George Corney

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] Pre-allocated array with many undefined entries - dense or sparse?

2016-02-21 Thread Jakob Kummerow
A few clarifications:

On Sat, Feb 20, 2016 at 8:18 PM, Louis Santillan  wrote:

> In JS, the size of the Array is not directly related to the index keys
> of the Array.  In this respect, JS is memory conservative.  So, you
> can always pre-allocate an array of 50 entries and until you add a
> 51st entry, the runtime shouldn't have to grow the Array which will
> then (often) make it sparse.


To be precise, the JS spec doesn't say anything about preallocation
behavior. Implementations can do whatever they think is clever. Also, I
don't see how adding a 51st element to a dense 50-element array would make
it sparse (in either the mathematical or the memory-layout sense of the
word).


> In v8, however, you can trigger sparse
> behavior (or hashed behavior) by using poor (sub-optimal) indexing as
> well.
>
> ```
> // Memory dense, sub-optimal access array
> var i, a = new Array( 50 );
> for( i = 0; i < 50; i++ )
> {
>a[ i * 50 ] = ( i + 1 ) * 50;
> }
> ```
>
> v8 initially expects that `a` will have indexes [0...49].   It's smart
> enough to realize that it doesn't need to allocate more memory but
> array accesses are forever slower once your second index becomes 50 in
> the above code.
>

For recent V8 versions, this is not correct. With the code above, the array
still has "fast elements" (i.e. a contiguous, non-dictionary backing store)
in the end.
The general concept is true, however: at some point there's a sparseness
threshold where V8 will use a dictionary for the elements.


> Also, as you saw, you can hint to runtime your intentions for the
> Array but touching `.length`.  This helps when you need to grow the
> array but hurts if you truncate it.  v8 reverts to sparse behavior in
> the truncation case.
>

Incorrect. Truncating an array does not trigger to-dictionary conversion of
its elements backing store.


> On Sat, Feb 20, 2016 at 7:11 AM, Michael Zhou
>  wrote:
> > From this perf https://jsperf.com/preallocating-array/27, using
> > pre-allocated Array(size) seems the fastest.
>

Yes, those results make sense.

> On Saturday, February 20, 2016 at 8:57:20 AM UTC-5, Dean McNamee wrote:
> >>
> >> https://youtu.be/UJPdhx5zTaw?t=17m43s
> >>
> >> Not sure if that advice still stands as it's a few years old, but my
> >> experience has been, in the general case, it is unfortunately faster
> >> to allocate an empty array and use push() than to preallocate an array
> >> of the desired size and populate it.  I have notes above a utility
> >> function I wrote that said I measured a 2x improvement in using push
> >> over Array(size), but I can't tell you now for what sort of size
> >> values that was.
>

Preallocation behavior of Array(N) has changed over time. I believe the
dictionary threshold used to be N=100,000, whereas more recent V8 versions
assume that programmers know what they're doing and preallocate even for
much larger values of N.


> >>
> >> As always, just try it and measure.
>

Strong +1!
And don't obsess about it -- even if you see a 2x difference in a
microbenchmark, real uses cases might have very different performance
characteristics.
Keep in mind that there are no "good" and "bad" representations -- what
works better depends on the use case.


> I've also found using some of the
> >> native methods helps in the process to understand why the performance
> >> difference is there.
> >>
> >> You can probably use something like the native %HasFastProperties() to
> >> check (this means running with --allow_natives_syntax).
>

In V8, properties != elements. You're looking for %HasDictionaryElements().


> >>
> >> There is also %_HasFastPackedElements() in Hydrogen, but I didn't look
> >> to see what the difference is.
>

Don't use that one, it's subtle and doesn't do what you think it does.


> >>
> >> On Sat, Feb 20, 2016 at 1:05 PM, Michael Zhou
> >>  wrote:
> >> > If I have
> >> >
> >> > var arr = new Array(50); // Should be dense, I guess?
> >> > arr[20] = 0;
> >> > arr[40] = 1;
> >> > arr[20] = undefined;
> >> > var keys = Object.keys(arr);
> >> >
> >> > Will this access pattern make v8 think arr is a sparse array and
> change
> >> > to
> >> > using a hash table?
>

No, Object.keys() does not convert array elements to dictionary mode.


> >> >
> >> > Also, is copying from old back store to new back store unavoidable
> when
> >> > I
> >> > grow the array by doing
> >> > for (var i = 50; i < 100; i++) {
> >> >   arr[i] = 0;
> >> > }
>

Yes, when a backing store is grown, the old backing store's contents must
be copied into the new one. (V8 used to have an optimization that tried to
avoid this in a very specific corner case, but in general, objects in
memory can't be grown in-place.)


> >> >
> >> > ? Thanks.
>

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-u