Skip to content

Commit 8978138

Browse files
committed
Clean getRecords in Timer module
1 parent 29c4e87 commit 8978138

1 file changed

Lines changed: 68 additions & 82 deletions

File tree

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

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

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

40-
static auto timer_freq = CTime::getTicksPerSec();
41-
auto getTime = [](ctime_t t)
49+
auto getTime = [](ctime_t t, ctime_t referenceTime)
4250
{
43-
return 1000. * t / timer_freq;
51+
constexpr double nbMillisecPerSec = 1000.;
52+
return nbMillisecPerSec * sofa::helper::system::thread::CTime::toSecond(t - referenceTime);
4453
};
4554

4655
const auto records = AdvancedTimer::getRecords(id);
4756

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

5369
for (const auto& r : records)
5470
{
@@ -57,126 +73,96 @@ py::dict getRecords(const std::string & id) {
5773
case Record::RNONE:
5874
break;
5975
case Record::RBEGIN: // Timer begins
60-
token = tokens.top();
61-
if (token.contains(r.label.c_str()))
76+
case Record::RSTEP_BEGIN: // Step begins
77+
currentLevel = hierarchyStack.top();
78+
if (currentLevel.contains(r.label.c_str()))
6279
{
63-
if (py::list::check_(token[r.label.c_str()]))
80+
if (py::list::check_(currentLevel[r.label.c_str()]))
6481
{
6582
token_temp = py::dict();
66-
py::list(token[r.label.c_str()]).append(token_temp);
67-
token = token_temp;
83+
py::list(currentLevel[r.label.c_str()]).append(token_temp);
84+
currentLevel = token_temp;
6885
}
69-
else if (py::dict::check_(token[r.label.c_str()]))
86+
else if (py::dict::check_(currentLevel[r.label.c_str()]))
7087
{
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);
88+
token_temp = currentLevel[r.label.c_str()];
89+
currentLevel[r.label.c_str()] = py::list();
90+
py::list(currentLevel[r.label.c_str()]).append(token_temp);
7491
token_temp = py::dict();
75-
py::list(token[r.label.c_str()]).append(token_temp);
76-
token = token_temp;
92+
py::list(currentLevel[r.label.c_str()]).append(token_temp);
93+
currentLevel = token_temp;
7794
}
7895
else
7996
{
80-
msg_error("Timer::getRecords") << "Got an unexpected token of type '" << std::string(py::str(token.get_type())) << "'.";
97+
msg_error("Timer::getRecords") << "Got an unexpected token of type '" << std::string(py::str(currentLevel.get_type())) << "'.";
8198
break;
8299
}
83100
}
84101
else
85102
{
86-
token[r.label.c_str()] = py::dict();
87-
token = token[r.label.c_str()];
103+
// Creating a new level in the hierarchy for the current timer label
104+
currentLevel[r.label.c_str()] = py::dict();
105+
// Update the current level to the one just added
106+
currentLevel = currentLevel[r.label.c_str()];
88107
}
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()))
108+
if (r.type == Record::RBEGIN)
102109
{
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-
}
110+
referenceTime = r.time;
123111
}
124-
else
112+
if (!referenceTime.has_value())
125113
{
126-
token[r.label.c_str()] = py::dict();
127-
token = token[r.label.c_str()];
114+
msg_error("Timer::getRecords") << "Reference time not set.";
115+
break;
128116
}
129-
token["start_time"] = getTime(r.time - t0);
130-
tokens.push(token);
117+
currentLevel["start_time"] = getTime(r.time, *referenceTime);
118+
hierarchyStack.push(currentLevel);
131119
break;
120+
case Record::REND: // Timer ends
132121
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();
122+
currentLevel = hierarchyStack.top();
123+
currentLevel["end_time"] = getTime(r.time, *referenceTime);
124+
currentLevel["total_time"] = getTime(r.time, *referenceTime) - py::cast<float>(currentLevel["start_time"]);
125+
hierarchyStack.pop();
137126
break;
138127
case Record::RVAL_SET: // Sets a value
139-
token = tokens.top();
140-
token[r.label.c_str()] = r.val;
141-
break;
142128
case Record::RVAL_ADD: // Sets a value
143-
token = tokens.top();
144-
token[r.label.c_str()] = r.val;
129+
currentLevel = hierarchyStack.top();
130+
currentLevel[r.label.c_str()] = r.val;
145131
break;
146132
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;
133+
currentLevel = hierarchyStack.top();
134+
currentLevel[r.label.c_str()] = py::list();
135+
currentLevel = currentLevel[r.label.c_str()];
136+
currentLevel["start_time"] = r.time;
151137
break;
152138
}
153139
}
154140

155141
// There should be two remaining records: Top level "record" + "timer starts". The "timer starts" record remains in
156142
// the stack since we normally get the records before the timer ends (ending the timer in Sofa destroys the
157143
// records...)
158-
if (tokens.size() == 2)
144+
if (hierarchyStack.size() == 2)
159145
{
160-
token = tokens.top();
161-
tokens.pop();
146+
currentLevel = hierarchyStack.top();
147+
hierarchyStack.pop();
162148
}
163-
else if (tokens.size() == 1)
149+
else if (hierarchyStack.size() == 1)
164150
{
165151
// This should not happen unless we successfully got the timer records AFTER the timer has ends, which would mean
166152
// that Sofa's advanced timer has improved, let not warn the user for that.
167-
token = tokens.top();
153+
currentLevel = hierarchyStack.top();
168154
}
169155

170156
// Pop the last token ("records")
171-
tokens.pop();
157+
hierarchyStack.pop();
172158

173159
// The stack should be empty by now
174-
if (!tokens.empty())
160+
if (!hierarchyStack.empty())
175161
{
176-
msg_error("Timer::getRecords") << "Records stack leaked.";
162+
msg_error("Timer::getRecords") << "Records stack leaked (" << hierarchyStack.size() << " elements).";
177163
}
178164

179-
return token;
165+
return currentLevel;
180166
}
181167

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

0 commit comments

Comments
 (0)