-
Notifications
You must be signed in to change notification settings - Fork 308
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix slow C3DFileAdpaterReading issue #1698 #1730
Conversation
…e data and labels supplied. Derived classes can use this to avoid appendRow(), which resized the internal matrix.
…rom already populated time vector and data matrix.
…Table constructor and populating a pre-allocated SimTK::Matrix without resizing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice speedup. See my comments; all are minor.
OpenSim/Common/TimeSeriesTable.h
Outdated
@@ -141,6 +141,29 @@ class TimeSeriesTable_ : public DataTable_<double, ETY> { | |||
TimeSeriesTable_& operator=(const TimeSeriesTable_&) = default; | |||
TimeSeriesTable_& operator=(TimeSeriesTable_&&) = default; | |||
~TimeSeriesTable_() = default; | |||
|
|||
/** Convenience Constructor to efficiently populate a time series table |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Constructor -> constructor.
OpenSim/Common/TimeSeriesTable.h
Outdated
// wipe out the data loaded if any | ||
_indData.clear(); | ||
_depData.clear(); | ||
removeDependentsMetaDataForKey("labels"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to rethrow?
OpenSim/Common/TimeSeriesTable.h
Outdated
DataTable_<double, ETY>(indVec, depData, labels) { | ||
try { | ||
// Perform the validation of the data a TimeSeriesTable | ||
this->validateDependentsMetaData(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see you added a comment in the base class about validation. Could you add a little more detail, either in the doxygen description for this constructor or for the one in the base class, explaining the situation with calling virtual functions from constructors?
OpenSim/Common/DataTable.h
Outdated
const SimTK::Matrix_<ETY>& depData, | ||
const std::vector<std::string>& labels) { | ||
OPENSIM_THROW_IF(indVec.size() != depData.nrow(), InvalidArgument, | ||
"Length of independent column does not match number of rows of dependent data."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
80 columns?
OpenSim/Common/C3DFileAdapter.cpp
Outdated
marker_table.appendRow(0 + f * time_step, row); | ||
|
||
marker_matrix.updRow(f) = row; | ||
marker_times[f] = 0 + f * time_step; // pt->GetValues(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you either provide more detail about the comment or remove it?
OpenSim/Common/C3DFileAdapter.cpp
Outdated
|
||
// Create the data | ||
auto& marker_table = *new | ||
TimeSeriesTableVec3 (marker_times, marker_matrix, marker_labels); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space between Vec3 and (
OpenSim/Common/C3DFileAdapter.cpp
Outdated
for(int f = 0; | ||
f < fp_force_pts->GetFrontItem()->GetFrameNumber(); | ||
++f) { | ||
for(int f = 0; f < force_times.size(); ++f) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using nf
instead of force_times.size()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A straight replacement would cause a compiler warning (type mismatch). Would need to do
for (int f = 0; f < static_cast<int>(nf); ++f)
et->GetFrame(), | ||
et->GetDescription() }); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a particular reason for moving this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought it read better to get the events first, which are then added to both the marker and force tables that are created in the two code blocks below. I also thought I might be able to extract the start time for the acquisition at some point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM upon addressing @chrisdembia's comments |-o-|
OpenSim/Common/C3DFileAdapter.cpp
Outdated
for(int f = 0; | ||
f < fp_force_pts->GetFrontItem()->GetFrameNumber(); | ||
++f) { | ||
for(int f = 0; f < force_times.size(); ++f) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A straight replacement would cause a compiler warning (type mismatch). Would need to do
for (int f = 0; f < static_cast<int>(nf); ++f)
…ience constructor must perform their own validation because virtual validateRow() will not invoke the derived class override during construction. Also do not exceed 80chars.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created a new issue about the initial time of the file (#1732).
Thank you @chrisdembia and @tkuchida. Merging. |
@nickbianco and @jimmyDunne can you check that you are getting reasonable performance now on your big C3D files? Thanks! |
I re-ran my test case and I'm getting reasonable performance now. |
Curious how it compares to using BTK directly, can you post the comparison as you did before in MATLAB? |
Pretty much comparable with the update: btk in MATLAB: 0.287 +/- 0.0329 seconds |
Fixes issue #1698
DataTable::appendRow()
is slow because it is resizing the underlyingSimTK::Matrix
on each call, which requires reallocation and copying of the entire matrix.Brief summary of changes
Added a protected
DataTable_
constructor that takes the independent vector, data matrix and labels so thatappendRow()
can be avoided.TimeSeriesTable_
exposes the convenience constructor and performs the validation and cleanup should validation fail.C3DFileAdpater::extendRead()
allocates the full time vector and data matrix first and then updates their elements and the uses the new constructor to create theTimeSeriesTable
avoidingTesting I've completed
Profiled
testC3DFileAdapter
prior to change the bottle neck was insideDataTable_::appendRow()
:87.1 % -> _depData.resizeKeep(_depData.nrow() + 1, _depData.ncol()); (~1600ms)
After the change, the creation and updating of the matrix and construction of the full
TimeSeriesTable
inC3DFileAdpater::extendRead()
now only uses 3.1 % of the total runtime (~34ms).And
testC3DFileAdapter
passes.Looking for feedback on...
CHANGELOG.md (choose one)
The Doxygen for this PR can be viewed at http://myosin.sourceforge.net/?C=N;O=D; click the folder whose name is this PR's number.