question

Tom S4 avatar image
0 Likes"
Tom S4 asked Tom S4 commented

Bind statistics for SDT

I want to add a statistic to ResourceInstance. I'm having some trouble binding it to the my class.

/* 
   Lines (A) and (B) are causing errors
   If I keep (A) and don't bind it, there is an error.
   If I bind (A) as a variable (i.e., bind() { bindNodePtr(customStat); } ), no problems. 
   If I bind (A) as a statistic (see (B)), there is an error.
*/

class CustomResourceInstance : public ::ProcessFlow::ResourceInstance
{
public:
    treenode customStat = nullptr; // (A)
    virtual void bindStatistics() override;
}

...

void CustomResourceInstance::bindStatistics()
{
    ResourceInstance::bindStatistics();
    bindStatistic(customStat, STAT_TIME_WEIGHTED); // (B)
}

I think the instance is created within Resource::instanceFactory(), so I am copying that into CustomResourceInstance and returning that instead. I have verified that the created instance found in the tree is, in fact, the custom instance I've created:

ProcessBlockInstance* CustomResource::instanceFactory()
{
    // memory leak?
    CustomResourceInstance* processBlockInstance = new CustomResourceInstance(*(CustomResourceInstance*) Resource::instanceFactory());
    return processBlockInstance;
}  

Any thoughts as to why I am unable to bind the statistic?

Thanks.

FlexSim 23.0.1
module sdkbound statistics
· 2
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

Jordan Johnson avatar image Jordan Johnson ♦♦ commented ·
You shouldn't bind it as a variable; stats are own meant to be present if something "asserts" the stat. I think that happens automatically for block instances, although I'm not 100% sure.


What is the error when you don't bind as a variable, but keep both lines A and B?

0 Likes 0 ·
Tom S4 avatar image Tom S4 Jordan Johnson ♦♦ commented ·

I am getting:

exception: Exception caught in TreeNode::callMemberFunction() main function. Throwing... 

exception: FlexScript exception: Exception caught in TreeNode::callMemberFunction() c++/dll execution. Throwing...  at VIEW:/active/MainPanel/BackPanel/SplitterXPane/SplitterYPane/SplitterXPane/TabPane~2/TabControl/ProcessFlow>eventfunctions/OnDrop c: VIEW:/active/MainPanel/BackPanel/SplitterXPane/SplitterYPane/SplitterXPane/TabPane~2/TabControl/ProcessFlow i: VIEW:/active/MainPanel/BackPanel/SplitterXPane/ToolTabPane/TabControl/LibraryIconGrid/GroupIconGrid

exception: Exception caught in TreeNode::callMemberFunction() main function. Throwing... 

exception: FlexScript exception: Exception caught in TreeNode::callMemberFunction() c++/dll execution. Throwing...  at VIEW:/active/MainPanel/BackPanel/SplitterXPane/SplitterYPane/SplitterXPane/TabPane~2/TabControl/ProcessFlow>eventfunctions/OnDraw c: VIEW:/active/MainPanel/BackPanel/SplitterXPane/SplitterYPane/SplitterXPane/TabPane~2/TabControl/ProcessFlow

I threw this code into its own project. A and B in my original question are found in CustomResourceInstance.h, line 9 and CustomResourceInstance.cpp, line 15. It was compiled with those two lines commented out, and the module should work without an error. Running with those lines uncommented causes an error.

To test it, I've been dropping my custom resource object into a general processflow.

(hopefully this was set up correctly that it can be extracted into the modules folder with no problem - apologies if not)

MyModule.zip

Any ideas?

0 Likes 0 ·
mymodule.zip (3.7 MiB)

1 Answer

Jordan Johnson avatar image
0 Likes"
Jordan Johnson answered Tom S4 commented

I think the issue is using the "QuickLibrary" (the view that opens when you double click) rather than the regular Library (the view usually docked on the side). Your module should add a section to the quick library, the way the Process Flow and People modules do. Look at this node:

VIEW:/standardviews/modelingutilities/QuickLibrary/IconGrid>variables/list

I think if you fix that, the issue will resolve. I say this because I can drag your Custom Resource form the Library view without an issue.

While looking at your code, I realized there's a step that isn't obvious for binding statistics. That step is to have the CustomResource override bindStatistics() and call bindRelayedClassStatistics(), like so:

// in CustomResource.h
void bindStatistics() override;

// in CustomResource.cpp
void CustomResource::bindStatistics()
{
    bindRelayedClassStatistics<CustomResourceInstance>("", STAT_1_REQUIREMENT, &ProcessBlock::instanceResolver, &ProcessBlock::instanceEnumerator);
}

Once I did that, I am able to view the custom statistic in the Statistics window:

1678121260093.png

That tells me that the statistic is binding properly, since this view can find it.


1678121260093.png (67.4 KiB)
· 4
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

Tom S4 avatar image Tom S4 commented ·

Hi @Jordan Johnson,

I followed these steps but it is producing some weird results.

I added this QuickLibrary node to my module:

65191-1678123296013.png

When I add via the Quick Library, it seems to bind correctly. I can see the stat in the tree and in the Statistics window. This looks fine, except for some reason the asset name opens up as blank and resets when I try to change it (?)

65192-1678123486231.png

However, when it try add via the Library, sometimes it lets me drop it in once and throws errors on subsequent drops. Other times it throws errors the first time I try to drop it in. My function calls and prints within bindStatistics() are still working correctly in either case.

In this video, I first double click the PF view and select my resource (my recorder did not capture this window). The resource is created and works fine. Then, I drag another resource from the Library, and it breaks.

Here is my current module:

MyModule.zip

0 Likes 0 ·
Jordan Johnson avatar image Jordan Johnson ♦♦ Tom S4 commented ·

Hi Tom,

I dug into the code and noticed a couple things. I added this line to CustomResourceInstance.h:

const char* getClassFactory() override { return "MyModule::CustomResourceInstance"; }

The getClassFactory() method must be overridden. It gets used in all kinds of ways.

I also updated the instanceFactory method:

ProcessBlockInstance* CustomResource::instanceFactory()
{
    // memory leak?
    CustomResourceInstance* processBlockInstance = new CustomResourceInstance();
    return processBlockInstance;
}

I'm not entirely sure what the effect of the old could would have been, but it seems better to not call the super class' instanceFactory().

After making these two changes, I couldn't get exceptions from either the quick library or the regular library. I was able to reliably create many CustomResource blocks.

I don't know why the name isn't showing in the stats window. I'd look at how that window is defined and see what there is to see about that. If you get stuck, feel free to ask a new question.

And to answer your memory leak question: no, this isn't a leak. The SDT is bound to a node just after this function call. Then the node's destructor

0 Likes 0 ·
Tom S4 avatar image Tom S4 Jordan Johnson ♦♦ commented ·
This seems to work! Thank you Jordan - really appreciate the help.
0 Likes 0 ·
Tom S4 avatar image Tom S4 commented ·

Looks like the first image I uploaded was broken. Here it as again:

65191-1678123296013-1.png

0 Likes 0 ·