VAR_IN_OUT_AS_POINTER and memory usage

tvm
2019-11-29
2023-06-02
  • tvm - 2019-11-29

    I'm trying to understand how parameters are passed to visualizations through the interface, and how that affects memory usage.

    According to the manual:

    Zitat:
    VAR_IN_OUT: If a data structure is transferred, it has to be defined as VAR_IN_OUT. Without pragma, the parameter values are copied when the visualization is opened. Entries are written to the copied data structure. When the visualization is closed, the values are written back to the parameters.
    VAR_IN_OUT with attribute VAR_IN_OUT_AS_POINTER: Objects are allowed to be transferred as references to visualizations. This can be useful in situations where information is to be transferred to a visualization without actually copying the information, or for updating information from outside, while the dialog is open.

    I have a function block defined in the interface of a visualization:

    VAR_IN_OUT
       Meter:      ELECTRIC_METER;
    END_VAR
    

    My visualizations work fine with this setup. But I'm running out of memory. For example, let's say I have 15 meters, they're all defined in a program somewhere, then each one has an interface in a tab control. It seems to me that I'm running out of memory because each meter is now taking up twice the space (one for the program, and one in the visualization).

    So, I thought I'd use the attribute VAR_IN_OUT_AS_POINTER, which makes more sense to me, passing a reference to the function block instead of copying it.

    VAR_IN_OUT
       {attribute 'VAR_IN_OUT_AS_POINTER'}
       Meter:      ELECTRIC_METER;
    END_VAR
    

    Unfortunately that doesn't seem to work with frames or tab controls, only dialogs. If I use it in a tab control or frame I get the error: >Zitat:
    The interface of the referenced visualization does not match the current configuration. Please do an update of the frame references in the current visualization.

    Am I understanding this correctly?

    thanks

    Tim

     
  • m.prestel - 2019-11-29

    Hello Tim,

    you are mixing a few things together here so let I try to separate everything:

    Small explanations for this example
    We have a function block defined in our GVL. The content of the fb does not matter.

    VAR_GLOBAL
       data : FBData;
    END_VAR
    

    Dialogs
    Normal dialog (VAR_IN_OUT)
    Interface

    VAR_IN_OUT
       data : FBData;
    END_VAR
    

    Generated code
    The generated code for this interface kinda looks like this:

    VAR_INPUT
       data : FBData;
    END_VAR
    

    The values of the functionblock will be copied once (when the dialog is opened)

    Dialog.DATA := GVL.data;
    

    Dialogs with Attribute VAR_IN_OUT_AS_POINTER
    Interface

    VAR_IN_OUT
       {attribute 'VAR_IN_OUT_AS_POINTER'}
       data : FBData;
    END_VAR
    

    This attribute is only available for dialogs. It has no effect for frames and therefore correctly reports an error.

    Generated code
    The generated code for this interface kinda looks like this:

    VAR_INPUT
       data : REFERENCE TO FBData;
    END_VAR
    

    The reference to the data will be set once (when the dialog is opened)

    DialogVarInOutPointer.DATA REF= GVL.data;
    

    Frames
    Interface

    VAR_IN_OUT
       data: FBData;
    END_VAR
    

    Generated code
    The generated code for this interface kinda looks like this:

    VAR_INPUT
       data : REFERENCE TO FBData;
    END_VAR
    

    In each cycle the reference to the data will be updated (since the data can be different for each referenced visualization).

    Frame.data REF= GVL.data;
    

    TL;DR
    Frames will use a reference, no need to use any attribute.

    Best regards,
    Marcel

     
  • tvm - 2019-11-29

    Now I understand, thank you for that very comprehensive reply.

    I'm still running out of memory, though, and that leads to another question. Let's say I have a tab control with 15 frames, all pointing to the same visualization, with different references. By process of elimination (removing one frame at a time), it looks like I'm using the same amount of memory for each frame (about 182K each, for a total of 2.8MB). I would have thought that the tab element would "know" that each frame is the same, and to only update the references when the tab is switched. Otherwise what's really the advantage of using a frame--might as well use separate visualizations. Or is there a different element that would accomplish this?

    Tim

     
  • m.prestel - 2019-12-03

    Hello Tim,

    there are a few reasons for that, but it is mostly that the referenced visualization was not stateless before SP15.
    Starting with SP15 the referenced data will be updated in each cycle. Before SP15 the referenced data was only assigned once in the start of the application.

    I added an improvement to cover this use case and reduce the data size.

    Adding 15 visualization with different data is just a fancy way to write an array with different indexes in my honest opinion

    Best regards,
    Marcel

     
  • tvm - 2019-12-03

    Ok, I am using SP 12 (Schneider Machine Expert), so I guess I can't change the reference at runtime. However, what if I do it with interfaces and arrays?

    Interface

    VAR_IN_OUT
       Meter:    METER_ITF;   //function block interface.  This is hard to research because Codesys uses the term "interface" for both visualizations and function blocks
    END_VAR
    

    ..but, in each cycle, the data won't be updated, since I'm using <SP15. Therefore, in a program:

       VAR
          MeterIndex:   UINT;
          AllMeters:      ARRAY[1..15] OF DATA_ITF;   //array of interfaces, assigned at runtime
          CurrentMeter:   DATA_ITF;            //linked to interface of visualization
       END_VAR
    

    Then at runtime:

    AllMeters[1]:= Meter1;
    AllMeters[2]:= Meter2;
    //..etc
    CurrentMeter:= AllMeters[MeterIndex];
    

    Seems like it should save a lot of memory. I won't be able to use the tab control, but should be able to do the same with with a single frame and a bunch of buttons that change the MeterIndex variable

    I haven't tried this yet. I'll update if it works.

     
  • tvm - 2019-12-04

    Update: that works quite well.

    FUNCTION BLOCK METER IMPLEMENTS ELECMETER_ITF
    ...
    PROGRAM ElectricMeters_PRG
    VAR
       Meter1:         METER;
       Meter2:         METER;
       //etc
       AllMeters:         ARRAY[1..13] OF ELECMETER_ITF:= [Meter1, Meter2, Meter3, Meter4, Meter5, Meter6, Meter7, Meter8, Meter9, Meter10, Meter11, Meter12, Meter13];
       MeterInterface:   ELECMETER_ITF:= AllMeters[1];   //it's very important to initialize this variable with a valid reference, or your visualization won't start
       SelectedMeter:      UINT(1..13):= 1;
    END_VAR
    MeterInterface:= AllMeters[SelectedMeter];
    

    point the visualization to ElectricMeters_PRG.MeterInterface. Change the SelectedMeter variable with a button or whatever to change the visualization reference

    Saves >2MB of memory

    Note: requires 'Activate property handling in all element properties' to be checked in Project Settings/Visualization to allow the use of properties in the visualization

     

    Related

    Talk.ru: 1

  • sbt-277 - 2023-06-02

    I tried tvm's solution in SP16 which comes with stateless visualizations (whatever that means in detail). So, the referenced data will be updated in each cycle.

    Only problem now is that the

    MeterInterface:= AllMeters[SelectedMeter];
    

    has to be called at each cycle whether the SelectedMeter value changed or not, because somewhere the old value of MeterInterface gets written back to it. I guess somewhere in the codesys visaulization code the value of the initial value of MeterInterface is stored and written back at each cycle. But where? Sadly there is no documentation about the internals of codesys visualization...

     

    Last edit: sbt-277 2023-06-02

Log in to post a comment.