diff --git a/bindings/SofaRuntime/src/SofaPython3/SofaRuntime/Timer/Submodule_Timer.cpp b/bindings/SofaRuntime/src/SofaPython3/SofaRuntime/Timer/Submodule_Timer.cpp index e2cd11f1..762f3321 100644 --- a/bindings/SofaRuntime/src/SofaPython3/SofaRuntime/Timer/Submodule_Timer.cpp +++ b/bindings/SofaRuntime/src/SofaPython3/SofaRuntime/Timer/Submodule_Timer.cpp @@ -38,8 +38,9 @@ py::dict getRecords(const std::string & id) { using sofa::helper::system::thread::CTime; static auto timer_freq = CTime::getTicksPerSec(); - auto getTime = [](ctime_t t) { - return 1000.0 * t / timer_freq; + auto getTime = [](ctime_t t) + { + return 1000 * t / timer_freq; }; const auto records = AdvancedTimer::getRecords(id); @@ -49,97 +50,118 @@ py::dict getRecords(const std::string & id) { tokens.push(token); ctime_t t0; - for (const auto & r : records) { - switch (r.type) { - case Record::RNONE: - break; - case Record::RBEGIN: // Timer begins - token = tokens.top(); - if (token.contains(r.label.c_str())) { - if (py::list::check_(token[r.label.c_str()])) { - token_temp = py::dict(); - py::list(token[r.label.c_str()]).append(token_temp); - token = token_temp; - } else if (py::dict::check_(token[r.label.c_str()])) { - token_temp = token[r.label.c_str()]; - token[r.label.c_str()] = py::list(); - py::list(token[r.label.c_str()]).append(token_temp); - token_temp = py::dict(); - py::list(token[r.label.c_str()]).append(token_temp); - token = token_temp; - } else { - msg_error("Timer::getRecords") << "Got an unexpected token of type '" << std::string(py::str(token.get_type())) << "'."; - break; - } - } else { - token[r.label.c_str()] = py::dict(); - token = token[r.label.c_str()]; + for (const auto& r : records) + { + switch (r.type) + { + case Record::RNONE: + break; + case Record::RBEGIN: // Timer begins + token = tokens.top(); + if (token.contains(r.label.c_str())) + { + if (py::list::check_(token[r.label.c_str()])) + { + token_temp = py::dict(); + py::list(token[r.label.c_str()]).append(token_temp); + token = token_temp; } - t0 = r.time; - token["start_time"] = getTime(r.time - t0); - tokens.push(token); - break; - case Record::REND: // Timer ends - token = tokens.top(); - token["end_time"] = getTime(r.time - t0); - token["total_time"] = getTime(r.time - t0) - py::cast(token["start_time"]); - tokens.pop(); - break; - case Record::RSTEP_BEGIN: // Step begins - token = tokens.top(); - if (token.contains(r.label.c_str())) { - if (py::list::check_(token[r.label.c_str()])) { - token_temp = py::dict(); - py::list(token[r.label.c_str()]).append(token_temp); - token = token_temp; - } else if (py::dict::check_(token[r.label.c_str()])) { - token_temp = token[r.label.c_str()]; - token[r.label.c_str()] = py::list(); - py::list(token[r.label.c_str()]).append(token_temp); - token_temp = py::dict(); - py::list(token[r.label.c_str()]).append(token_temp); - token = token_temp; - } else { - msg_error("Timer::getRecords") << "Got an unexpected token of type '" << std::string(py::str(token.get_type())) << "'."; - break; - } - } else { - token[r.label.c_str()] = py::dict(); - token = token[r.label.c_str()]; + else if (py::dict::check_(token[r.label.c_str()])) + { + token_temp = token[r.label.c_str()]; + token[r.label.c_str()] = py::list(); + py::list(token[r.label.c_str()]).append(token_temp); + token_temp = py::dict(); + py::list(token[r.label.c_str()]).append(token_temp); + token = token_temp; } - token["start_time"] = getTime(r.time - t0); - tokens.push(token); - break; - case Record::RSTEP_END: // Step ends - token = tokens.top(); - token["end_time"] = getTime(r.time - t0); - token["total_time"] = getTime(r.time - t0) - py::cast(token["start_time"]); - tokens.pop(); - break; - case Record::RVAL_SET: // Sets a value - token = tokens.top(); - token[r.label.c_str()] = r.val; - break; - case Record::RVAL_ADD: // Sets a value - token = tokens.top(); - token[r.label.c_str()] = r.val; - break; - default: - token = tokens.top(); - token[r.label.c_str()] = py::list(); + else + { + msg_error("Timer::getRecords") << "Got an unexpected token of type '" << std::string(py::str(token.get_type())) << "'."; + break; + } + } + else + { + token[r.label.c_str()] = py::dict(); token = token[r.label.c_str()]; - token["start_time"] = r.time; - break; + } + t0 = r.time; + token["start_time"] = getTime(r.time - t0); + tokens.push(token); + break; + case Record::REND: // Timer ends + token = tokens.top(); + token["end_time"] = getTime(r.time - t0); + token["total_time"] = getTime(r.time - t0) - py::cast(token["start_time"]); + tokens.pop(); + break; + case Record::RSTEP_BEGIN: // Step begins + token = tokens.top(); + if (token.contains(r.label.c_str())) + { + if (py::list::check_(token[r.label.c_str()])) + { + token_temp = py::dict(); + py::list(token[r.label.c_str()]).append(token_temp); + token = token_temp; + } + else if (py::dict::check_(token[r.label.c_str()])) + { + token_temp = token[r.label.c_str()]; + token[r.label.c_str()] = py::list(); + py::list(token[r.label.c_str()]).append(token_temp); + token_temp = py::dict(); + py::list(token[r.label.c_str()]).append(token_temp); + token = token_temp; + } + else + { + msg_error("Timer::getRecords") << "Got an unexpected token of type '" << std::string(py::str(token.get_type())) << "'."; + break; + } + } + else + { + token[r.label.c_str()] = py::dict(); + token = token[r.label.c_str()]; + } + token["start_time"] = getTime(r.time - t0); + tokens.push(token); + break; + case Record::RSTEP_END: // Step ends + token = tokens.top(); + token["end_time"] = getTime(r.time - t0); + token["total_time"] = getTime(r.time - t0) - py::cast(token["start_time"]); + tokens.pop(); + break; + case Record::RVAL_SET: // Sets a value + token = tokens.top(); + token[r.label.c_str()] = r.val; + break; + case Record::RVAL_ADD: // Sets a value + token = tokens.top(); + token[r.label.c_str()] = r.val; + break; + default: + token = tokens.top(); + token[r.label.c_str()] = py::list(); + token = token[r.label.c_str()]; + token["start_time"] = r.time; + break; } } // There should be two remaining records: Top level "record" + "timer starts". The "timer starts" record remains in // the stack since we normally get the records before the timer ends (ending the timer in Sofa destroys the // records...) - if (tokens.size() == 2) { + if (tokens.size() == 2) + { token = tokens.top(); tokens.pop(); - } else if (tokens.size() == 1) { + } + else if (tokens.size() == 1) + { // This should not happen unless we successfully got the timer records AFTER the timer has ends, which would mean // that Sofa's advanced timer has improved, let not warn the user for that. token = tokens.top(); @@ -150,7 +172,9 @@ py::dict getRecords(const std::string & id) { // The stack should be empty by now if (!tokens.empty()) + { msg_error("Timer::getRecords") << "Records stack leaked."; + } return token; } diff --git a/examples/advanced_timer.py b/examples/advanced_timer.py index 0a7a2b27..323069d5 100644 --- a/examples/advanced_timer.py +++ b/examples/advanced_timer.py @@ -25,13 +25,13 @@ def onAnimateEndEvent(self, event): else: records = Timer.getRecords("cg_timer") - step_time = records['AnimateVisitor']['Mechanical (meca)']['total_time'] + step_time = records['solve']['Mechanical (meca)']['total_time'] print(f"Step took {step_time:.2f} ms") - nb_iterations = records['AnimateVisitor']['Mechanical (meca)']['StaticSolver::Solve']['nb_iterations'] + nb_iterations = records['solve']['Mechanical (meca)']['StaticSolver::Solve']['nb_iterations'] for i in range(int(nb_iterations)): - total_time = records['AnimateVisitor']['Mechanical (meca)']['StaticSolver::Solve']['NewtonStep'][i]['total_time'] - CG_iterations = records['AnimateVisitor']['Mechanical (meca)']['StaticSolver::Solve']['NewtonStep'][i]['MBKSolve']['CG iterations'] + total_time = records['solve']['Mechanical (meca)']['StaticSolver::Solve']['NewtonStep'][i]['total_time'] + CG_iterations = records['solve']['Mechanical (meca)']['StaticSolver::Solve']['NewtonStep'][i]['MBKSolve']['CG iterations'] print(f" Newton iteration #{i} took {total_time:.2f} ms using {int(CG_iterations)} CG iterations") if not self.use_sofa_profiler_timer: @@ -66,7 +66,7 @@ def createScene(root): root.addObject( TimerController() ) # Create a grid topology of 10x10x60 centered on (0,0,0) - root.addObject('RegularGridTopology', name='grid', min=[-5, -5, -30], max=[5, 5, 30], n=[11, 11, 61]) + root.addObject('RegularGridTopology', name='grid', min=[-5, -5, -30], max=[5, 5, 30], n=[6, 6, 16]) # Create our mechanical node root.addChild("meca")