@@ -32,23 +32,39 @@ using sofa::helper::AdvancedTimer;
3232namespace 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+ */
3545py::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
182168py::module addSubmoduleTimer (py::module &m)
0 commit comments