1 #include "timer_test.h"
2
3 #include <iostream>
4 #include <sstream>
5 #include <algorithm>
6
7 #include "pbd/timer.h"
8
9 #ifdef PLATFORM_WINDOWS
10 #include <windows.h>
11 #endif
12
13 #ifndef G_SOURCE_FUNC
14 #define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f))
15 #endif
16
17 CPPUNIT_TEST_SUITE_REGISTRATION (TimerTest);
18
19 using namespace std;
20
21 #ifdef PLATFORM_WINDOWS
22 UINT&
min_timer_resolution()23 min_timer_resolution ()
24 {
25 static UINT min_res_ms = 0;
26 return min_res_ms;
27 }
28
29 bool
set_min_timer_resolution()30 set_min_timer_resolution ()
31 {
32 TIMECAPS caps;
33
34 if (timeGetDevCaps(&caps, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
35 cerr << "Could not get timer device capabilities..." << endl;
36 } else {
37 if (timeBeginPeriod(caps.wPeriodMin) != TIMERR_NOERROR) {
38 cerr << "Could not set minimum timer resolution to: " << caps.wPeriodMin << "ms" << endl;
39 return false;
40 }
41 else {
42 cerr << "Multimedia timer resolution set to: " << caps.wPeriodMin << "ms" << endl;
43 min_timer_resolution() = caps.wPeriodMin;
44 return true;
45 }
46 }
47 return false;
48 }
49
50 bool
reset_timer_resolution()51 reset_timer_resolution ()
52 {
53 if (min_timer_resolution()) {
54 if (timeEndPeriod(min_timer_resolution()) != TIMERR_NOERROR) {
55 cerr << "Could not reset timer resolution" << endl;
56 return false;
57 } else {
58 cerr << "Multimedia timer resolution reset" << endl;
59 return true;
60 }
61 }
62 return true;
63 }
64
65 #endif
66
67 void
simulate_load(const string & name,guint64 load_usecs)68 TimerTest::simulate_load (const string& name, guint64 load_usecs)
69 {
70 PBD::Timing timing;
71 std::ostringstream oss;
72 oss << name << " Load.";
73
74 guint64 i = 0;
75 do {
76 timing.update ();
77
78 // totally arbitrary
79 if (i % 10000 == 0) {
80 oss << ".";
81 }
82
83 ++i;
84 } while (timing.elapsed () < load_usecs);
85
86 oss << "Expected = " << load_usecs;
87 oss << ", Elapsed = " << timing.elapsed ();
88 oss << endl;
89 //cerr << oss.str();
90 }
91
92 void
on_second_timeout()93 TimerTest::on_second_timeout ()
94 {
95 cerr << endl;
96 cerr << "Timing Summary: " << m_current_test_name << endl;
97
98 if (m_idle_timing_data.size()) {
99 cerr << "Idle Timing: " << m_idle_timing_data.summary();
100 }
101 if (m_fast_timing_data.size()) {
102 cerr << "Fast Timing: " << m_fast_timing_data.summary();
103 }
104 if (m_rapid1_timing_data.size()) {
105 cerr << "Rapid1 Timing: " << m_rapid1_timing_data.summary();
106 }
107 if (m_rapid2_timing_data.size()) {
108 cerr << "Rapid2 Timing: " << m_rapid2_timing_data.summary();
109 }
110 reset_timing ();
111 }
112
113 bool
on_second_timeout_glibmm()114 TimerTest::on_second_timeout_glibmm ()
115 {
116 TimerTest::on_second_timeout ();
117 return true;
118 }
119
120 void
on_fast_timeout()121 TimerTest::on_fast_timeout ()
122 {
123 m_fast_timing_data.add_interval ();
124 if (m_block_idle) {
125 // do nothing, handled in rapid timers
126 } else {
127 simulate_load ("Rapid1", 4000);
128 }
129 }
130
131 bool
on_fast_timeout_glibmm()132 TimerTest::on_fast_timeout_glibmm ()
133 {
134 on_fast_timeout ();
135 return true;
136 }
137
138 void
on_rapid1_timeout()139 TimerTest::on_rapid1_timeout ()
140 {
141 m_rapid1_timing_data.add_interval ();
142 if (m_block_idle) {
143 simulate_load ("Rapid1", rapid1_timer_usecs () * 0.5);
144 } else {
145 simulate_load ("Rapid1", 2000);
146 }
147 }
148
149 bool
on_rapid1_timeout_glibmm()150 TimerTest::on_rapid1_timeout_glibmm ()
151 {
152 on_rapid1_timeout ();
153 return true;
154 }
155
156 void
on_rapid2_timeout()157 TimerTest::on_rapid2_timeout ()
158 {
159 m_rapid2_timing_data.add_interval ();
160 if (m_block_idle) {
161 simulate_load ("Rapid2", rapid2_timer_usecs () * 0.5);
162 } else {
163 simulate_load ("Rapid2", 2000);
164 }
165 }
166
167 bool
on_rapid2_timeout_glibmm()168 TimerTest::on_rapid2_timeout_glibmm ()
169 {
170 on_rapid2_timeout ();
171 return true;
172 }
173
174 bool
on_idle_handler()175 TimerTest::on_idle_handler ()
176 {
177 m_idle_timing_data.add_interval ();
178 if (m_block_idle) {
179 simulate_load ("Idle", rapid2_timer_usecs ());
180 }
181 return true;
182 }
183
184 bool
on_quit_handler()185 TimerTest::on_quit_handler ()
186 {
187 cerr << "Quit Handler" << endl;
188 m_main->quit ();
189 return false;
190 }
191
192 void
reset_timing()193 TimerTest::reset_timing ()
194 {
195 m_idle_timing_data.reset ();
196 m_fast_timing_data.reset ();
197 m_rapid1_timing_data.reset ();
198 m_rapid2_timing_data.reset ();
199 }
200
201 void
start_timing()202 TimerTest::start_timing ()
203 {
204 m_idle_timing_data.start_timing ();
205 m_fast_timing_data.start_timing ();
206 m_rapid1_timing_data.start_timing ();
207 m_rapid2_timing_data.start_timing ();
208 }
209
210 gboolean
_second_timeout_handler(void * data)211 TimerTest::_second_timeout_handler (void *data)
212 {
213 TimerTest *const tt = static_cast<TimerTest*>(data);
214 tt->on_second_timeout ();
215 return TRUE;
216 }
217
218 gboolean
_fast_timeout_handler(void * data)219 TimerTest::_fast_timeout_handler (void *data)
220 {
221 TimerTest *const tt = static_cast<TimerTest*>(data);
222 tt->on_fast_timeout ();
223 return TRUE;
224 }
225
226 gboolean
_rapid1_timeout_handler(void * data)227 TimerTest::_rapid1_timeout_handler (void *data)
228 {
229 TimerTest *const tt = static_cast<TimerTest*>(data);
230 tt->on_rapid1_timeout ();
231 return TRUE;
232 }
233
234 gboolean
_rapid2_timeout_handler(void * data)235 TimerTest::_rapid2_timeout_handler (void *data)
236 {
237 TimerTest *const tt = static_cast<TimerTest*>(data);
238 tt->on_rapid2_timeout ();
239 return TRUE;
240 }
241
242 void
reset_timing_run_main()243 TimerTest::reset_timing_run_main ()
244 {
245 reset_timing ();
246 start_timing ();
247
248 connect_quit_timeout ();
249
250 m_main = Glib::MainLoop::create (m_context);
251 m_main->run ();
252 }
253
254 void
testGlibTimeoutSources()255 TimerTest::testGlibTimeoutSources ()
256 {
257 m_current_test_name = "testGlibTimeoutSources";
258 _testGlibTimeoutSources ();
259 }
260
261 void
_testGlibTimeoutSources()262 TimerTest::_testGlibTimeoutSources ()
263 {
264 m_context = Glib::MainContext::create ();
265
266 GSource * second_timeout_source = g_timeout_source_new (second_timer_ms ());
267
268 g_source_set_callback (second_timeout_source , &TimerTest::_second_timeout_handler, this, NULL);
269
270 g_source_attach (second_timeout_source, m_context->gobj());
271
272 if (m_connect_idle) {
273 connect_idle_handler ();
274 reset_timing_run_main ();
275 }
276
277 GSource * fast_timeout_source = g_timeout_source_new (fast_timer_ms ());
278
279 g_source_set_callback (fast_timeout_source , &TimerTest::_fast_timeout_handler, this, NULL);
280
281 g_source_attach (fast_timeout_source, m_context->gobj());
282
283 // now run with fast timeout
284 reset_timing_run_main ();
285
286 GSource * rapid1_timeout_source = g_timeout_source_new (rapid1_timer_ms ());
287
288 g_source_set_callback (rapid1_timeout_source , &TimerTest::_rapid1_timeout_handler, this, NULL);
289
290 g_source_attach (rapid1_timeout_source, m_context->gobj());
291
292 // now run with fast and rapid1 timeouts
293 reset_timing_run_main ();
294
295 GSource * rapid2_timeout_source = g_timeout_source_new (rapid2_timer_ms ());
296
297 g_source_set_callback (rapid2_timeout_source , &TimerTest::_rapid2_timeout_handler, this, NULL);
298
299 g_source_attach (rapid2_timeout_source, m_context->gobj());
300
301 // now run with fast, rapid1 and rapid2 timeouts
302 reset_timing_run_main ();
303
304 // cleanup
305 g_source_destroy (second_timeout_source);
306 g_source_unref (second_timeout_source);
307
308 g_source_destroy (fast_timeout_source);
309 g_source_unref (fast_timeout_source);
310
311 g_source_destroy (rapid1_timeout_source);
312 g_source_unref (rapid1_timeout_source);
313
314 g_source_destroy (rapid2_timeout_source);
315 g_source_unref (rapid2_timeout_source);
316 }
317
318 void
testGlibmmSignalTimeouts()319 TimerTest::testGlibmmSignalTimeouts ()
320 {
321 m_current_test_name = "testGlibmmSignalTimeouts";
322 _testGlibmmSignalTimeouts ();
323 }
324
325 void
_testGlibmmSignalTimeouts()326 TimerTest::_testGlibmmSignalTimeouts ()
327 {
328 m_context = Glib::MainContext::get_default ();
329
330 Glib::signal_timeout().connect(sigc::mem_fun(*this, &TimerTest::on_second_timeout_glibmm), second_timer_ms());
331
332 if (m_connect_idle) {
333 connect_idle_handler ();
334 reset_timing_run_main ();
335 }
336
337 Glib::signal_timeout().connect(sigc::mem_fun(*this, &TimerTest::on_fast_timeout_glibmm), fast_timer_ms());
338
339 reset_timing_run_main ();
340
341 Glib::signal_timeout().connect(sigc::mem_fun(*this, &TimerTest::on_rapid1_timeout_glibmm), rapid1_timer_ms());
342
343 reset_timing_run_main ();
344
345 Glib::signal_timeout().connect(sigc::mem_fun(*this, &TimerTest::on_rapid2_timeout_glibmm), rapid2_timer_ms());
346
347 reset_timing_run_main ();
348 }
349
350 void
testGlibmmTimeoutSources()351 TimerTest::testGlibmmTimeoutSources ()
352 {
353 m_current_test_name = "testGlibmmTimeoutSources";
354 _testGlibmmTimeoutSources ();
355 }
356
357 void
_testGlibmmTimeoutSources()358 TimerTest::_testGlibmmTimeoutSources ()
359 {
360 m_context = Glib::MainContext::create ();
361
362 const Glib::RefPtr<Glib::TimeoutSource> second_source = Glib::TimeoutSource::create(second_timer_ms());
363 second_source->connect(sigc::mem_fun(*this, &TimerTest::on_second_timeout_glibmm));
364
365 second_source->attach(m_context);
366
367 if (m_connect_idle) {
368 connect_idle_handler ();
369 reset_timing_run_main ();
370 }
371
372 const Glib::RefPtr<Glib::TimeoutSource> fast_source = Glib::TimeoutSource::create(fast_timer_ms());
373 fast_source->connect(sigc::mem_fun(*this, &TimerTest::on_fast_timeout_glibmm));
374
375 fast_source->attach(m_context);
376
377 reset_timing_run_main ();
378
379 const Glib::RefPtr<Glib::TimeoutSource> rapid1_source = Glib::TimeoutSource::create(rapid1_timer_ms());
380 sigc::connection rapid1_connection = rapid1_source->connect(sigc::mem_fun(*this, &TimerTest::on_rapid1_timeout_glibmm));
381
382 rapid1_source->attach(m_context);
383
384 reset_timing_run_main ();
385
386 const Glib::RefPtr<Glib::TimeoutSource> rapid2_source = Glib::TimeoutSource::create(rapid2_timer_ms());
387 sigc::connection rapid2_connection = rapid2_source->connect(sigc::mem_fun(*this, &TimerTest::on_rapid2_timeout_glibmm));
388
389 rapid2_source->attach(m_context);
390
391 reset_timing_run_main ();
392 }
393
394 void
connect_idle_handler()395 TimerTest::connect_idle_handler ()
396 {
397 const Glib::RefPtr<Glib::IdleSource> idle_source = Glib::IdleSource::create();
398 idle_source->connect(sigc::mem_fun(*this, &TimerTest::on_idle_handler));
399
400 idle_source->attach(m_context);
401 }
402
403 void
connect_quit_timeout()404 TimerTest::connect_quit_timeout ()
405 {
406 const Glib::RefPtr<Glib::TimeoutSource> quit_source = Glib::TimeoutSource::create(test_length_ms());
407 quit_source->connect(sigc::mem_fun(*this, &TimerTest::on_quit_handler));
408
409 quit_source->attach(m_context);
410 }
411
412 void
testTimers()413 TimerTest::testTimers ()
414 {
415 m_current_test_name = "testTimers";
416 _testTimers ();
417 }
418
419 void
_testTimers()420 TimerTest::_testTimers ()
421 {
422 m_context = Glib::MainContext::create ();
423
424 PBD::StandardTimer second_timer (second_timer_ms (), m_context);
425 sigc::connection second_connection = second_timer.connect (sigc::mem_fun (this, &TimerTest::on_second_timeout));
426
427 if (m_connect_idle) {
428 connect_idle_handler ();
429 // let the idle handler run as fast as it can
430 reset_timing_run_main();
431 }
432
433 PBD::StandardTimer fast_timer (fast_timer_ms (), m_context);
434 sigc::connection fast_connection = fast_timer.connect (sigc::mem_fun (this, &TimerTest::on_fast_timeout));
435
436 reset_timing_run_main();
437
438 PBD::StandardTimer rapid1_timer (rapid1_timer_ms (), m_context);
439 sigc::connection rapid1_connection = rapid1_timer.connect (sigc::mem_fun (this, &TimerTest::on_rapid1_timeout));
440
441 reset_timing_run_main();
442
443 PBD::StandardTimer rapid2_timer (rapid2_timer_ms (), m_context);
444 sigc::connection rapid2_connection = rapid2_timer.connect (sigc::mem_fun (this, &TimerTest::on_rapid2_timeout));
445
446 reset_timing_run_main();
447 }
448
449 void
testTimersIdleFrequency()450 TimerTest::testTimersIdleFrequency ()
451 {
452 m_current_test_name = "testTimersIdleFrequency";
453 _testTimersIdleFrequency ();
454 }
455
456 void
_testTimersIdleFrequency()457 TimerTest::_testTimersIdleFrequency ()
458 {
459 m_block_idle = false;
460 m_connect_idle = true;
461
462 _testTimers ();
463
464 m_block_idle = false;
465 m_connect_idle = false;
466 }
467
468 void
testTimersBlockIdle()469 TimerTest::testTimersBlockIdle ()
470 {
471 m_current_test_name = "testTimersBlockIdle";
472 _testTimersBlockIdle ();
473 }
474
475 void
_testTimersBlockIdle()476 TimerTest::_testTimersBlockIdle ()
477 {
478 m_block_idle = true;
479 m_connect_idle = true;
480
481 _testTimers ();
482
483 m_block_idle = false;
484 m_connect_idle = false;
485 }
486
487 #ifdef PLATFORM_WINDOWS
488 void
testGlibTimeoutSourcesHR()489 TimerTest::testGlibTimeoutSourcesHR ()
490 {
491 CPPUNIT_ASSERT(set_min_timer_resolution());
492
493 m_current_test_name = "testGlibTimeoutSourcesHR";
494 _testGlibTimeoutSources ();
495
496 CPPUNIT_ASSERT(reset_timer_resolution());
497 }
498
499 void
testGlibmmSignalTimeoutsHR()500 TimerTest::testGlibmmSignalTimeoutsHR ()
501 {
502 CPPUNIT_ASSERT(set_min_timer_resolution());
503
504 m_current_test_name = "testGlibmmSignalTimeoutsHR";
505 _testGlibmmSignalTimeouts ();
506
507 CPPUNIT_ASSERT(reset_timer_resolution());
508 }
509
510 void
testGlibmmTimeoutSourcesHR()511 TimerTest::testGlibmmTimeoutSourcesHR ()
512 {
513 CPPUNIT_ASSERT(set_min_timer_resolution());
514
515 m_current_test_name = "testGlibmmTimeoutSourcesHR";
516 _testGlibmmTimeoutSources ();
517
518 CPPUNIT_ASSERT(reset_timer_resolution());
519 }
520
521 void
testTimersHR()522 TimerTest::testTimersHR ()
523 {
524 CPPUNIT_ASSERT(set_min_timer_resolution());
525
526 m_current_test_name = "testTimersHR";
527 _testTimers ();
528
529 CPPUNIT_ASSERT(reset_timer_resolution());
530 }
531
532 void
testTimersIdleFrequencyHR()533 TimerTest::testTimersIdleFrequencyHR ()
534 {
535 CPPUNIT_ASSERT(set_min_timer_resolution());
536
537 m_current_test_name = "testTimersIdleFrequencyHR";
538 _testTimersIdleFrequency ();
539
540 CPPUNIT_ASSERT(reset_timer_resolution());
541 }
542
543 void
testTimersBlockIdleHR()544 TimerTest::testTimersBlockIdleHR ()
545 {
546 CPPUNIT_ASSERT(set_min_timer_resolution());
547
548 m_current_test_name = "testTimersIdleFrequencyHR";
549 _testTimersBlockIdle ();
550
551 CPPUNIT_ASSERT(reset_timer_resolution());
552 }
553
554 #endif
555