Skip to content

Commit c0dc30e

Browse files
authored
Clean getRecords in Timer module (#561)
* Clean getRecords in Timer module * remove extra /**
1 parent d2ba475 commit c0dc30e

1 file changed

Lines changed: 67 additions & 82 deletions

File tree

bindings/SofaRuntime/src/SofaPython3/SofaRuntime/Timer/Submodule_Timer.cpp

Lines changed: 67 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,38 @@ using sofa::helper::AdvancedTimer;
3232
namespace sofapython3
3333
{
3434

35+
/**
36+
* @brief Converts AdvancedTimer records to a Python dictionary structure
37+
*
38+
* This function processes the timer records and builds a hierarchical Python dictionary
39+
* that represents the timer data in a format that's easy to use in Python.
40+
*
41+
* @param id The timer ID to get records for
42+
* @return A Python dictionary representing the timer records
43+
*/
3544
py::dict getRecords(const std::string & id) {
3645
using sofa::helper::Record;
3746
using sofa::helper::system::thread::ctime_t;
38-
using sofa::helper::system::thread::CTime;
3947

40-
static auto timer_freq = CTime::getTicksPerSec();
41-
auto getTime = [](ctime_t t)
48+
auto getTime = [](ctime_t t, ctime_t referenceTime)
4249
{
43-
return 1000. * t / timer_freq;
50+
constexpr double nbMillisecPerSec = 1000.;
51+
return nbMillisecPerSec * sofa::helper::system::thread::CTime::toSecond(t - referenceTime);
4452
};
4553

4654
const auto records = AdvancedTimer::getRecords(id);
4755

48-
std::stack<py::dict> tokens;
49-
py::dict token, token_temp;
50-
tokens.push(token);
51-
ctime_t t0;
56+
// Stack of dictionaries that represents the hierarchical structure of timer records
57+
// Each element in the stack corresponds to a different level in the timer hierarchy.
58+
std::stack<py::dict> hierarchyStack;
59+
60+
// Current dictionary being processed at the top of the stack
61+
// Represents the most recently created level in the timer hierarchy.
62+
py::dict currentLevel;
63+
64+
py::dict token_temp;
65+
hierarchyStack.push(currentLevel);
66+
std::optional<ctime_t> referenceTime;
5267

5368
for (const auto& r : records)
5469
{
@@ -57,126 +72,96 @@ py::dict getRecords(const std::string & id) {
5772
case Record::RNONE:
5873
break;
5974
case Record::RBEGIN: // Timer begins
60-
token = tokens.top();
61-
if (token.contains(r.label.c_str()))
75+
case Record::RSTEP_BEGIN: // Step begins
76+
currentLevel = hierarchyStack.top();
77+
if (currentLevel.contains(r.label.c_str()))
6278
{
63-
if (py::list::check_(token[r.label.c_str()]))
79+
if (py::list::check_(currentLevel[r.label.c_str()]))
6480
{
6581
token_temp = py::dict();
66-
py::list(token[r.label.c_str()]).append(token_temp);
67-
token = token_temp;
82+
py::list(currentLevel[r.label.c_str()]).append(token_temp);
83+
currentLevel = token_temp;
6884
}
69-
else if (py::dict::check_(token[r.label.c_str()]))
85+
else if (py::dict::check_(currentLevel[r.label.c_str()]))
7086
{
71-
token_temp = token[r.label.c_str()];
72-
token[r.label.c_str()] = py::list();
73-
py::list(token[r.label.c_str()]).append(token_temp);
87+
token_temp = currentLevel[r.label.c_str()];
88+
currentLevel[r.label.c_str()] = py::list();
89+
py::list(currentLevel[r.label.c_str()]).append(token_temp);
7490
token_temp = py::dict();
75-
py::list(token[r.label.c_str()]).append(token_temp);
76-
token = token_temp;
91+
py::list(currentLevel[r.label.c_str()]).append(token_temp);
92+
currentLevel = token_temp;
7793
}
7894
else
7995
{
80-
msg_error("Timer::getRecords") << "Got an unexpected token of type '" << std::string(py::str(token.get_type())) << "'.";
96+
msg_error("Timer::getRecords") << "Got an unexpected token of type '" << std::string(py::str(currentLevel.get_type())) << "'.";
8197
break;
8298
}
8399
}
84100
else
85101
{
86-
token[r.label.c_str()] = py::dict();
87-
token = token[r.label.c_str()];
102+
// Creating a new level in the hierarchy for the current timer label
103+
currentLevel[r.label.c_str()] = py::dict();
104+
// Update the current level to the one just added
105+
currentLevel = currentLevel[r.label.c_str()];
88106
}
89-
t0 = r.time;
90-
token["start_time"] = getTime(r.time - t0);
91-
tokens.push(token);
92-
break;
93-
case Record::REND: // Timer ends
94-
token = tokens.top();
95-
token["end_time"] = getTime(r.time - t0);
96-
token["total_time"] = getTime(r.time - t0) - py::cast<float>(token["start_time"]);
97-
tokens.pop();
98-
break;
99-
case Record::RSTEP_BEGIN: // Step begins
100-
token = tokens.top();
101-
if (token.contains(r.label.c_str()))
107+
if (r.type == Record::RBEGIN)
102108
{
103-
if (py::list::check_(token[r.label.c_str()]))
104-
{
105-
token_temp = py::dict();
106-
py::list(token[r.label.c_str()]).append(token_temp);
107-
token = token_temp;
108-
}
109-
else if (py::dict::check_(token[r.label.c_str()]))
110-
{
111-
token_temp = token[r.label.c_str()];
112-
token[r.label.c_str()] = py::list();
113-
py::list(token[r.label.c_str()]).append(token_temp);
114-
token_temp = py::dict();
115-
py::list(token[r.label.c_str()]).append(token_temp);
116-
token = token_temp;
117-
}
118-
else
119-
{
120-
msg_error("Timer::getRecords") << "Got an unexpected token of type '" << std::string(py::str(token.get_type())) << "'.";
121-
break;
122-
}
109+
referenceTime = r.time;
123110
}
124-
else
111+
if (!referenceTime.has_value())
125112
{
126-
token[r.label.c_str()] = py::dict();
127-
token = token[r.label.c_str()];
113+
msg_error("Timer::getRecords") << "Reference time not set.";
114+
break;
128115
}
129-
token["start_time"] = getTime(r.time - t0);
130-
tokens.push(token);
116+
currentLevel["start_time"] = getTime(r.time, *referenceTime);
117+
hierarchyStack.push(currentLevel);
131118
break;
119+
case Record::REND: // Timer ends
132120
case Record::RSTEP_END: // Step ends
133-
token = tokens.top();
134-
token["end_time"] = getTime(r.time - t0);
135-
token["total_time"] = getTime(r.time - t0) - py::cast<float>(token["start_time"]);
136-
tokens.pop();
121+
currentLevel = hierarchyStack.top();
122+
currentLevel["end_time"] = getTime(r.time, *referenceTime);
123+
currentLevel["total_time"] = getTime(r.time, *referenceTime) - py::cast<float>(currentLevel["start_time"]);
124+
hierarchyStack.pop();
137125
break;
138126
case Record::RVAL_SET: // Sets a value
139-
token = tokens.top();
140-
token[r.label.c_str()] = r.val;
141-
break;
142127
case Record::RVAL_ADD: // Sets a value
143-
token = tokens.top();
144-
token[r.label.c_str()] = r.val;
128+
currentLevel = hierarchyStack.top();
129+
currentLevel[r.label.c_str()] = r.val;
145130
break;
146131
default:
147-
token = tokens.top();
148-
token[r.label.c_str()] = py::list();
149-
token = token[r.label.c_str()];
150-
token["start_time"] = r.time;
132+
currentLevel = hierarchyStack.top();
133+
currentLevel[r.label.c_str()] = py::list();
134+
currentLevel = currentLevel[r.label.c_str()];
135+
currentLevel["start_time"] = r.time;
151136
break;
152137
}
153138
}
154139

155140
// There should be two remaining records: Top level "record" + "timer starts". The "timer starts" record remains in
156141
// the stack since we normally get the records before the timer ends (ending the timer in Sofa destroys the
157142
// records...)
158-
if (tokens.size() == 2)
143+
if (hierarchyStack.size() == 2)
159144
{
160-
token = tokens.top();
161-
tokens.pop();
145+
currentLevel = hierarchyStack.top();
146+
hierarchyStack.pop();
162147
}
163-
else if (tokens.size() == 1)
148+
else if (hierarchyStack.size() == 1)
164149
{
165150
// This should not happen unless we successfully got the timer records AFTER the timer has ends, which would mean
166151
// that Sofa's advanced timer has improved, let not warn the user for that.
167-
token = tokens.top();
152+
currentLevel = hierarchyStack.top();
168153
}
169154

170155
// Pop the last token ("records")
171-
tokens.pop();
156+
hierarchyStack.pop();
172157

173158
// The stack should be empty by now
174-
if (!tokens.empty())
159+
if (!hierarchyStack.empty())
175160
{
176-
msg_error("Timer::getRecords") << "Records stack leaked.";
161+
msg_error("Timer::getRecords") << "Records stack leaked (" << hierarchyStack.size() << " elements).";
177162
}
178163

179-
return token;
164+
return currentLevel;
180165
}
181166

182167
py::module addSubmoduleTimer(py::module &m)

0 commit comments

Comments
 (0)