Re: [v8-users] v8 3.28, getting data from typed arrays, I'm unsure if this approach is correct (and doesn't leak)
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)
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?
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)
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?
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