Opened 9 years ago
Last modified 8 years ago
#3814 new enhancement
Optimizsation of record modifications
Reported by: | Henning Kiel | Owned by: | Martin Sjölund |
---|---|---|---|
Priority: | high | Milestone: | Future |
Component: | MetaModelica | Version: | |
Keywords: | Cc: | Francesco Casella |
Description
Consider the following example code:
record exampleLst Integer n; list<Integer> elems; // more elements to follow... end record; function appList input list<Integer> li; input output exampleLst lst; algorithm lst.n := lst.n + listLength(li); lst.elems := listAppend(li, lst.elems); end with; end appList;
Currently the compiler will create a new record for each of the two assignment lines (via mmc_mk_box()
), though the intermediate object is never really referenced or used.
Now, the compiler could try to figure out this and only do one mmc_mk_box()
incorporating both changes. This would immediately reduce overall memory usage.
A second approach would be to extend MetaModelica language with a with <elem> do … end with;
construct like the following:
function appList input list<Integer> li; input output exampleLst lst; algorithm with lst do .n := .n + listLength(li); .elems := listAppend(.elems, li); end with; end appList;
Here, the assignment (mmc_mk_box()
) is only done at the end with;
line, and the component contents stored in temporary variables.
I do not bother if one or both ways are implemented, but I would definitely love to see at least one of them :-)
The second approach could also be extended to e.g. also allow for-loops etc.
function appList input list<list<Integer>> lists; input output exampleLst lst; algorithm for li in lists loop with lst do .n := .n + listLength(li); .elems := listAppend(.elems, li); end with; end for; end appList;
Change History (8)
comment:1 by , 9 years ago
comment:2 by , 9 years ago
can we use some other syntax then? I guess the semantics is not problematic.
Maybe "..n" or "%.n" or something else?
comment:3 by , 9 years ago
Cc: | added |
---|
comment:4 by , 9 years ago
Maybe we should keep the object name:
function appList input list<Integer> li; input output exampleLst lst; algorithm with lst do lst.n := lst.n + listLength(li); lst.elems := listAppend(lst.elems, li); end with; end appList;
and implement the above as syntactic sugar for
function appList input list<Integer> li; input output exampleLst lst; protected Integer lst_n; // used whenever "lst.n" is referenced in code list<Integer> lst_elems; // used whenever "lst.elems" is referenced in code algorithm lst_n := lst.n; // with lst do lst_elems := lst.elems; // use of plain lst inside "with" should produce an error lst_n := lst_n + listLength(li); // lst.n := lst.n + listLength(li); lst_elems := listAppend(lst_elems, li); // lst.elems := listAppend(lst.elems, li); lst := exampleLst(lst_n, lst_elems); // end with; end appList;
comment:5 by , 9 years ago
Optionally, the syntax could be updated to
with <var1>,<var2>,... do <code> end with;
to avoid deeply nested with-clauses, though I doubt that more than two variables will be used simultaneously.
comment:6 by , 9 years ago
SimCodeUtil.derVarFromStateVar
is a prime example of this. It is very annoying to rewrite this function since there are 23 fields in there and we want to update 8 of them. It takes 25 words to store this variable, which means 1600 bytes of allocation for each call to this function. @casella: this function is called once for each variable in the system (#3813); I will change it to only be called for state variables.
comment:7 by , 9 years ago
Any activity on this topic? Looks like this is one of the big memory eaters...
What do you think about
protected function derVarFromStateVar input SimCodeVar.SimVar state; output SimCodeVar.SimVar deriv = state; algorithm with deriv do deriv.arrayCref := Util.applyOption(deriv.arrayCref, ComponentReference.crefPrefixDer); deriv.name := ComponentReference.crefPrefixDer(deriv.name); deriv.varKind := BackendDAE.STATE_DER(); deriv.initialValue := NONE(); deriv.aliasvar := SimCodeVar.NOALIAS(); deriv.causality := SimCodeVar.INTERNAL(); deriv.variable_index := NONE(); deriv.isValueChangeable := false; end do; end derVarFromStateVar;
as syntactic sugar for
protected function derVarFromStateVar input SimCodeVar.SimVar state; output SimCodeVar.SimVar deriv = state; algorithm SIMVAR(name = name, varKind=varKind, .....) := deriv; arrayCref := Util.applyOption(arrayCref, ComponentReference.crefPrefixDer); name := ComponentReference.crefPrefixDer(name); varKind := BackendDAE.STATE_DER(); initialValue := NONE(); aliasvar := SimCodeVar.NOALIAS(); causality := SimCodeVar.INTERNAL(); variable_index := NONE(); isValueChangeable := false; deriv := SIMVAR(name, varKind, .......); end derVarFromStateVar;
?
comment:8 by , 8 years ago
Another idea which does not introduce new keywords. This could also be adapted to accept tuples on the RHS.
protected function derVarFromStateVar input SimCodeVar.SimVar state; output SimCodeVar.SimVar deriv = state; algorithm deriv.(arrayCref, name, varKind, initialValue, aliasvar, causality, variable_index, isValueChangeable) := ( Util.applyOption(deriv.arrayCref, ComponentReference.crefPrefixDer), ComponentReference.crefPrefixDer(deriv.name), BackendDAE.STATE_DER(), NONE(), SimCodeVar.NOALIAS(), SimCodeVar.INTERNAL(), NONE(), false ); end derVarFromStateVar;
Readability is a bit worse than the other aproaches above, but could be easier to implement???
The second approach is not so good since
.n
means "lookup n in the global scope".