Within GSL, memory is allocated and types initialized such that for a gsl_vector* v object, the pointers v->datav->block->data point to the same array in memory.
When I create reflex-compatible versions of these structs (which might not be possible; several other questions I’ve posted here deal with various other issues), will Reflex recognize that these are two pointers to the same array? Or will it duplicate the array when saving it to persistence?
As an additional note, I recognize now that gsl_vector.block is a non-array pointer. How would this be annotated for Reflex – //[1]?
As an additional note, I recognize now that gsl_vector.block is a non-array pointer. How would this be annotated for Reflex – //[1]?
Pointers to numeric type are assumed to be arrays and thus need to be decorated.
Pointers to objects are assumed to be non-array and a single element is stored.
will Reflex recognize that these are two pointers to the same array?
In ROOT I/O we do have, for objects only, code to recognize that the same objects is being stored twice (within an I/O operation). Consequently, you example would have worked if the data has been struct/classes. For numeric type, this detection has not been implemented (as it is very rare but would still come to a cost to all cases).
Instead in this case, I recommend to set gsl_vector::data as a transient member (never saved) and add an I/O customization rules that sets gsl_vector::data to the value of gsl_vector::block::data at the end of the streaming.
Thank you for the very clear explanation. Indeed, I was wondering if declaring something as transient was the way to go, but I didn’t know about the I/O customization rules so I was worried it would leave code in a broken state. I am searching online for instructions on how to use these I/O customization rules, and I’ve found many presentation slides that you’ve written but they all seem to be high-level summaries, without instructions. Is there a resource explaining how to do this?
Would the reverse be possible, setting epm_gsl_block::data as a transient member and adding a customization rule to set epm_gsl_vector::block::data equal to epm_gsl_vector::data, via
I ask because, combining all your helpful responses from several threads, I think my best is apply your struct inheritance trick to epm_gsl_vector and epm_gsl_matrix. For the former (the latter follows by analogy),
gsl_vector* GSL(epm_gsl_vector* ev) {
auto gv = reinterpret_cast<gsl_vector*>(static_cast<epm_gsl_vector_substruct*>(ev));
return gv;
}
epm_gsl_vector* DeGSL(gsl_vector* gv) {
auto ev = static_cast<epm_gsl_vector*>(reinterpret_cast<epm_gsl_vector_substruct*>(ev));
return ev;
}
The advantage this has is that the pointer epm_gsl_vector::block does not have to be modified in any way to be cast to a pointer to a gsl_block. If epm_gsl_block instead carried the modifications, I cannot find an easy way for casting operations on epm_gsl_vector to appropriately modify the epm_gsl_vector::block element.
I think that a further simplification (and reduction of on-file size) is to mark both epm_gsl_vector_substruct::size and epm_gsl_vector::block as transient.
<ioread sourceClass="epm_gsl_vector"
source="double* data"
targetClass="epm_gsl_vector"
target="data,block,size"
>
<![CDATA[
data = onfile.data; // copy pointer value in place.
newObj->size = newObj->reflex_size;
newObj->block = new epm_gsl_block;
newObj->block->data = data;
newObj->block->size = newObj->reflex_size;
]] >
Thanks for this suggestion; I will try it. I’m currently trying to diagnose a segfault, however, in TStreamerInfo::InitCounter, related to my epm_gsl_matrix struct (renamed to espresso_matrix), which follows your prescription of inheriting from an espresso_matrix_io whose single field is reflex_size:
(gdb) info f
Stack level 0, frame at 0x7ffffffd64c0:
rip = 0x7fffeed01be0 in InitCounter
(/mnt/build/jenkins/workspace/lcg_release_tar/BUILDTYPE/Debug/COMPILER/gcc49/LABEL/slc6/build/projects/ROOT-6.08.02/src/ROOT/6.08.02/core/meta/src/TStreamerElement.cxx:74); saved rip = 0x7fffeed04fad
called by frame at 0x7ffffffd64f0
source language c++.
Arglist at 0x7ffffffd64b0, args: countClass=0x7edb350 "espresso_matrix_io", countName=0x7edb319 "reflex_size", directive=0x7ed25d0
Locals at 0x7ffffffd64b0, Previous frame's sp is 0x7ffffffd64c0
Saved registers:
rbx at 0x7ffffffd64a8, rbp at 0x7ffffffd64b0, rip at 0x7ffffffd64b8
(gdb) info args
countClass = 0x7edb350 "espresso_matrix_io"
countName = 0x7edb319 "reflex_size"
directive = 0x7ed25d0
(gdb) info locals
info = 0x7ed25d0
rdCounter = 0x7ffff07d25e4 <TString::GetPointer() const+40>
dmCounter = 0x7ffffffd6490
cl = 0x7edb328
counter = 0x0
The cause of the segfault is not immediately obvious to me, because none of the local variables that have been set at this line (so, excluding counter) are null pointers.
I’m using 6.08/02 – hopefully the cause of the error isn’t because of some error I’m making somewhere else. I get these errors when directly adding one my classes (of which the GSL structs are members of members) to a TFile and saving it, or when saving it through a RooWorkspace.
I printed all the GDB information that I have, unfortunately – “list” tells me nothing, and gdb just reports line 74 as the issue I’m attaching gdb to a PyRoot script, so perhaps the intermediate python layer limits the available debug information. It is odd that valgrind says there is a null pointer when GDB does not. I’m trying to compile a equivalent C++ program and investigate this in more detail – I’ll post here when I have more information. Thanks again for all of your help!