[Jamvm-general] jamvm / primitive arrays
Brought to you by:
rlougher
From: Christopher F. <chr...@gm...> - 2013-08-07 03:55:41
|
Hi list, I've done some experimenting with Jamvm-1.5.4 and classpath-0.98 w.r.t. ByteBuffer, MappedByteBuffer, etc. Rob, I emailed you off-list about this a while back. The short version of this email results in a question I'd like to ask the list (and Rob of course) so feel free to skip ahead to "@Q@" for the short version. My experimentation has involved a couple of key things: (1) Small patch for jamvm-1.5.4 to support Darwin / x86_64 (just for quick prototyping on my Mac) (2) Small patch for classpath-0.98 that allows it to map special files (i.e. those in /dev such as /dev/fb0) (3) Slightly larger patch for classpath-0.98 and jamvm-1.5.4 that provided a byte[] backing_buffer for both heap and non-heap / non-stack sections of virtual memory, e.g. pages returned by mmap(... some fd ... ). The idea is to realize the *ByteBuffer.array() functionality, allowing interpreted Java bytecode to write directly to memory rather than relying on JNI to get() and put(). The implementation of (3) wasn't very pretty, but the speedup is obvious (Darwin / x86_64). The result is a bounds-checked, reference-counted, and properly finalized byte[] . bb.capacity:4194304 bb.isReadOnly:false bb.hasArray:true bb.isDirect:true bb.array:[B@adff288 Testing ByteBuffer.put() with 4194304 random bytes ... 5568252000 ns Testing ByteBuffer.array() writes with 4194304 random bytes ... 622120000 ns speedup:8.950446859126856 That is all fine and dandy. However, there is an issue about supporting ByteBuffer.asIntBuffer() and friends. The issue here has to do with JamVM's representation of a primitive array in memory. Don't get me wrong, it's actually a really simple and efficient solution. The current solution is to allocate [ data:(size*element_size) + capacity:sizeof(uintptr_t) + class:sizeof(Object) ]. The uintptr_t just encodes the number of elements in the array, while the Object includes a lock (mandatory) and a pointer the primitive array Class. To realize an efficient implementation of the ByteBuffer.asIntBuffer() for a ByteBuffer with backing_buffer (i.e. array() realized), there should really be a way to allocate only the header of the int[] Object but with an additional uintptr_t. E.g. (mind the pseudo code) if ( address ) { // do not allocate data, but point to other potentially non-local page x = allocate [ capacity:sizeof(uintptr_t) + pointer:sizeof(uintptr_t) + class:sizeof(Object) ] x.capacity = capacity x.pointer = address x.class = class } else { // normal array allocation, note pointer is page-localized to object x = allocate [ data:(size * element_size) + capacity:sizeof(uintptr_t) + pointer:sizeof(uintptr_t) + sizeof(Object) ] x.capacity = capacity x.pointer = &x.data x.class = class clear(&x.data) } According to the javadoc for asIntBuffer() and friends, both original byte[] and new int[] should have equal access capabilities to the same underlying region of memory. If one used JNI to change the underlying byte[] Object into an int[] Object (kind of subversively), then the original byte[] would be mangled with jamvm's current primitive array implementation. The price for the 2-dereference method: (i) An extra uintptr_t per array. (iI) the interpreter would get a small hit because it would need to dereference twice (once for the x pointer and once for "pointer") rather than once, as it is currently. My guess is that the cpu and memory caches would probably be pretty forgiving for this overhead, but I could be spouting hot air. AFAIK, making the necessary modifications to the interpreter to do this shouldn't be a problem. I guess that the reference count for the original byte[] would need to be increased, but that's also not too difficult. @Q@ In the design for primitive array representation in JamVM, was the two-dereference idea considered? If not, why and would it be considered for any up-coming releases of JamVM? Thanks, C |