Opened 10 years ago
Last modified 9 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 , 10 years ago
comment:2 by , 10 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 , 10 years ago
| Cc: | added |
|---|
comment:4 by , 10 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 , 10 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 , 10 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 , 10 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 , 9 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
.nmeans "lookup n in the global scope".