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