Jump to content

Updating a middle element of a variant tree


Recommended Posts

Does anyone know a faster way to accomplish this?  The profiler marks this as one of my top hits for VI time.  I wish I could speed it up but I cannot think of a better way.

 

post-2411-0-07912300-1382404107.png

 

Thanks for any ideas.  (Even if that idea is to not use variant trees for storing data.  But if so, please offer a faster data store method.)

 

-John

Link to comment

Make sure you’ve kudoed "In Place Element Structure Support for Variant Attributes”.    It’s the copy at the first “Get Attribute” that is killing you.  

 

One way around this is to not use the actual value of your storage variants at all; instead keep the "content" of that tree node as a “NodeContent” attribute.  Then your above code becomes just a “Set Attribute”.

  • Like 1
Link to comment

Thanks for the tips!  I will see if I can re-factor my code to avoid the copy.  I do have a few questions:

 

1. Using the IPE, it appears that I still need to do the copy to extract the first attribute.  But it does eliminate the need to reattach the children of the attribute.  

2. If I move the node data to an attribute, there would be no need to use the IPE as far as I can see.

3. I often extract all child attributes from one of the top attributes and then perform an action on each of those.  If the node is now an attribute, I would need to remove that item from the array of attributes before I process them.  There are two ways I can think of doing this.  The first is to test the attribute name inside the process loop and skip the one named 'NodeContent'.  The second is to search the array of attribute names for the element named 'NodeContent' and then delete it from the array before I process the array in a for loop.  Any opinion on which solution would be faster?  I expect most attribute arrays to have less than 100 elements.

 

thanks again.

 

-John

Link to comment
3. I often extract all child attributes from one of the top attributes and then perform an action on each of those.  If the node is now an attribute, I would need to remove that item from the array of attributes before I process them.  There are two ways I can think of doing this.  The first is to test the attribute name inside the process loop and skip the one named 'NodeContent'.  The second is to search the array of attribute names for the element named 'NodeContent' and then delete it from the array before I process the array in a for loop.  Any opinion on which solution would be faster?

I believe attributes come out ordered, so name your content attribute a single zero byte (Hex 00) and it will always be the first element (which can be skipped at minimal cost with an array subset).

Link to comment

Thanks for the trick.  I will try that next.

I just tried the re-factor using the IPE instead of the for loop to preserve the child attributes.  The result is a 31% DECREASE in performance.  I must admit I am very surprised by this.

post-2411-0-79278700-1382474743_thumb.pn

 

Assuming I did this right, I think your other solution sounds better.  I'll post my results once I complete the edits...

Link to comment
Thanks for the trick.  I will try that next.

I just tried the re-factor using the IPE instead of the for loop to preserve the child attributes.  The result is a 31% DECREASE in performance.  I must admit I am very surprised by this.

attachicon.gifupdate middle variant data using IPE.png

 

Assuming I did this right, I think your other solution sounds better.  I'll post my results once I complete the edits...

I’m confused because I couldn’t get the IPE to work with a variant for the type input (LabVIEW 2011); I have to supply the actual type (which limits its applicability).  Using a variant only works on variants inside variants (did you unknowingly do that? would reduce performance).

 

BTW, the first “Get Attribute” that is copying an entire branch of your tree, so that’s also needs to be inplace (if you can get that solution to work).  

Link to comment

Kinda.  I had to cast the generic variant to a variant using the 'to variant' prim when I added the child to the top variant.  After that, it allowed me to use the IPE to update it.  Not sure if that is what you mean.

 

It is not possible to make the first 'get attribute' inplace since I am getting an attribute value by name and replacing it.  The IPE only provides access to the node data, not its attributes, as pointed out in the Idea Exchange link you provided in your first comment to the thread.

Link to comment
It is not possible to make the first 'get attribute' inplace since I am getting an attribute value by name and replacing it.  The IPE only provides access to the node data, not its attributes, as pointed out in the Idea Exchange link you provided in your first comment to the thread.

Oh yeah, duh.  I’m working too hard.  Liking my original suggestion better.

Link to comment

Ok, new version isolating the node data to a separate attribute produces and 8% overall speed increase.  The original copy of the branch from the main tree seems to be the overwhelming issue.  Here is the new code:

 

post-2411-0-72307700-1382479867_thumb.pn

 

I did not include a snippet of the other changes I needed to make:

  • Populate the top child with an empty NodeData Attribute when adding that branch.
  • Deleting the NodeData attribute from the array when getting the list of branch children.

 

At this point, I am wondering if I could get a speed improvement from redesigning this using LVOOP objects instead of variants. 

Link to comment

I don't have time to review this whole thread, but I thought I'd lob this one over to see if it makes sense to your situation.

 

When I posted that idea I was contending with variant tables that were creeping into the multiple GB realm, the size of an individual attribute could reach up to 100 MB and itself not be "flat" data. The ultimate solution was to migrate to a database, but that's beside the point. What I ended up doing before I landed there was to flatten the structure to a single variant and use a syntax for key naming to resolve the "hierarchy". For example rather than storing a variant with a collection of keys ["A", "B", "C", "D"] in a top level variant under the key "X", instead store four keys in the top level variant ["X.A", "X.B", "X.C", "X.D"]. This removes the need for the copy when you need to access any of the child elements and may help you.

 

Unfortunately it adds a whole mess of other requirements that aren't so attractive depending on the nature of your data. Do you need to be able to reference the hierarchy at any level, as in "Get me all of the subkeys that fall under "X"? You'll either need secondary data structures to manage queries like that or do some painful searches over all key names. Also you'll need to manage your syntax to avoid parent keys from stomping on lower level keys. Never mind the headache of having all of your data management at a single non-extensible level. All of those drawbacks quickly moved me away from variants as a means to store large amounts of hierarchical data.

 

In my opinion variants are unmatched at storing large amounts of flat associative data, but until we can get in-place access to attributes they are awful for hierarchical structures if your data is significant.

Link to comment

Another idea is to keep all data in a single flat structure such as an array, with the index to that structure stored in the variant tree.  Lookup the index then index the array in place.  Then at least all the copying will be of small integers.  Or one could try a tree containing DVR references.  But if we are taking very large data sizes then mje’s ultimate solution of a database might be best.  I’ve even considered using in-memory SQLite databases in place of variants for small data structures, just to have the increased flexibility of SQL, but the performance is significantly worse than variants when the data size is small. 

Link to comment

Funny you mention that.  As I attempted to re-factor this problem away, I ended up trying two things.

1. Store the node values in a separate variant.

2. Store a DVR of the node data in the attributes of that separate variant instead of storing the node data directly in the attribute.

 

In my case, I am implementing a subscription message system.  The system needs to allow for multiple subscriptions and each subscription needs to keep track of all of its subscribers and the last message sent.  That allows me to broadcast to all active listeners and for new listeners to request the current value of they subscribe between broadcasts.

 

The benefits:

I can add subscribers and remove them from a variant tree that contains no data other than the attribute names.  I expect to have under ~500 subscriptions in the system at max load and each subscription would have under 10 subscribers.  So the tree is not too big.

Having the data stored as DVRs allows me to avoid that massive copy when I extract the node data tree from the system (I store system data in a DVR itself so all processes have access to it).  The other benefit is I no longer need to write back any changes to the node data in the tree.  I just update the DVR's content.  The variant tree never changes.

 

One caveat: My node data is a message.  All messages inherit from a common ancestor.  I tried to create a DVR of this ancestor and use that as my node data type, but LV will not let you modify the data in a DVR if the type is a class, even if the new data is a child of that class.  Not sure I fully understand the reason for this, but the workaround is to store the data in the node ad a DVR of a variant.  That just means an extra cast when I want to access the data.  Seems kinda silly to have this limitation but I am sure they have their reasons.

 

Anyways, problem solved and speed is no longer an issue.  Now to add some cleanup code to free all those DVRs on shutdown...

 

Thanks for all the help and tips.  This is why I love LAVA!

 

-John

Link to comment
In my case, I am implementing a subscription message system.  The system needs to allow for multiple subscriptions and each subscription needs to keep track of all of its subscribers and the last message sent.  That allows me to broadcast to all active listeners and for new listeners to request the current value of they subscribe between broadcasts.

Funny, I use variant attributes for much the same thing, and asked about copies in this conversation.  I also allow new subscribers to get a copy of the most recent message on subscription (though not always; I distinguish between “State” notifications (save the most recent message) and “Event” notifications (don’t save).

 

I’ve long been meaning to improve the performance, but haven’t got round to it.

Link to comment

Yup.  That thread is exactly what I am doing.  Wish I would have seen that first.  It would have saved me a lot of time.

Still agree that we need IPE support for attribute access.  That would still improve my solution.

 

Well, I am now off to find other places to use DVRs in my message system.  I bet there are a few more places I can improve things...

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.