Differences between revisions 1 and 7 (spanning 6 versions)
Revision 1 as of 2018-03-13 00:18:42
Size: 872
Editor: BevinBrett
Comment:
Revision 7 as of 2018-03-13 01:03:40
Size: 2227
Editor: BevinBrett
Comment:
Deletions are marked like this. Additions are marked like this.
Line 4: Line 4:
Each face had a normal vector and area stored in the nx,ny,nz,orig_area members of the FACE struct. ==== mris_fix_topology has a hot loop, which does unnecessary calculations of the face normals ====
mrisComputeOptimalRetessellation and mrisComputeRandomRetessellation have a similar structure
Line 6: Line 7:
mris_fix_topology has a hot loop _:_: it loops over a set of patches, or iterates on one patch. For each patch it calls
Line 8: Line 9:
 ___: mrisComputeOptimalRetessellation and mrisComputeRandomRetessellation have a similar structure _:_:_: mrisDefectPatchFitness, which calls
Line 10: Line 11:
___: ___: a computeDefectContext is constructed here _:_:_:_: mrisComputeDefectLogLikelihood, which calls
Line 12: Line 13:
___:___: then it loops over a set of patches, or iterates on one patch. For each patch it calls _:_:_:_:_: mrisComputeDefectMRILogUnlikelihood, which
Line 14: Line 15:
___:___:___: mrisDefectPatchFitness, which calls _:_:_:_:_:_: does an expensive computation all the face normals for ALL the faces
Line 16: Line 17:
___:___:___: ___: mrisComputeDefectLogLikelihood, which calls _:_:_:_:_:_: does two other expensive steps, which only use a few of the face normals
Line 18: Line 19:
___:___:___: ___: ___: mrisComputeDefectMRILogUnlikelihood, which ==== To simplify, the original code does this ====
_: loop
Line 20: Line 22:
___:___:___: ___: ___:___: does an expensive computation all the face normals for ALL the faces _:_: for all fno normal[fno] = f (inputs)
Line 22: Line 24:
___:___:___: ___: ___:___: does two other expensive steps, which only use a few of the face normals _:_: for a few fno use normal[fno]

_: end loop

_: change some inputs

_: use some normal[fno]

''Since only a few of the face normals are used, it is a waste of time to calculate all of them every time around the loop! ''

==== This is replaced by code that does ====
_: loop

_:_: for all fno: normal[fno].deferred = true

_:_: for a few fno: use normal[fno], computing it from f (inputs) if is deferred, and changing it to being no-longer deferred

_: end loop

_: compute any remaining deferred normal[fno] before their inputs can change

_: change some inputs

_: use some normal[fno]

==== How can we test it gets the right answers? ====
When checking code is enabled, the normal[fno] is computed from the inputs twice - once when it is deferred, and again when it is undeferred. It is checked that these two values are the same.

==== How do we make sure that the undeferring is done? ====
If we left the __FACE nx,ny,nz,orig_area__ members unchanged, then it would be hard to find all the users. We could just rename them, but it is easier to place them in a struct and have a function called to get a pointer to the struct, and have the function do the undeferral. This is a standard data hiding technique, implemented here in C. Now all the places that need to be changed are compilation errors.

'''Why put the structs into a separate vector?'''

TBD

A variety of techniques have been used.

Deferring calculations until needed

mris_fix_topology has a hot loop, which does unnecessary calculations of the face normals

mrisComputeOptimalRetessellation and mrisComputeRandomRetessellation have a similar structure

_:_: it loops over a set of patches, or iterates on one patch. For each patch it calls

_:_:_: mrisDefectPatchFitness, which calls

_:_:_:_: mrisComputeDefectLogLikelihood, which calls

_:_:_:_:_: mrisComputeDefectMRILogUnlikelihood, which

_:_:_:_:_:_: does an expensive computation all the face normals for ALL the faces

_:_:_:_:_:_: does two other expensive steps, which only use a few of the face normals

To simplify, the original code does this

_: loop

_:_: for all fno normal[fno] = f (inputs)

_:_: for a few fno use normal[fno]

_: end loop

_: change some inputs

_: use some normal[fno]

Since only a few of the face normals are used, it is a waste of time to calculate all of them every time around the loop!

This is replaced by code that does

_: loop

_:_: for all fno: normal[fno].deferred = true

_:_: for a few fno: use normal[fno], computing it from f (inputs) if is deferred, and changing it to being no-longer deferred

_: end loop

_: compute any remaining deferred normal[fno] before their inputs can change

_: change some inputs

_: use some normal[fno]

How can we test it gets the right answers?

When checking code is enabled, the normal[fno] is computed from the inputs twice - once when it is deferred, and again when it is undeferred. It is checked that these two values are the same.

How do we make sure that the undeferring is done?

If we left the FACE nx,ny,nz,orig_area members unchanged, then it would be hard to find all the users. We could just rename them, but it is easier to place them in a struct and have a function called to get a pointer to the struct, and have the function do the undeferral. This is a standard data hiding technique, implemented here in C. Now all the places that need to be changed are compilation errors.

Why put the structs into a separate vector?

TBD

MorphoOptimizationProject_BetterSerialCode_DeferCalculations (last edited 2021-09-22 09:46:34 by DevaniCordero)