summaryrefslogtreecommitdiff
path: root/libs/pbd/test/windows_timer_utils_test.cc
blob: cd2ba5904001040cc59180041f90505eab3ee3da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include "windows_timer_utils_test.h"

#include "pbd/windows_timer_utils.h"

#include <windows.h>

#include <iostream>

using namespace std;

CPPUNIT_TEST_SUITE_REGISTRATION (WindowsTimerUtilsTest);

void
WindowsTimerUtilsTest::testQPC ()
{
	// performs basically the same test
	CPPUNIT_ASSERT (PBD::QPC::check_timer_valid());

	int64_t last_timer_val = PBD::QPC::get_microseconds ();
	CPPUNIT_ASSERT (last_timer_val >= 0);

	int64_t min_interval = 1000000;
	int64_t max_interval = 0;

	for (int i = 0; i < 10000; ++i) {
		int64_t timer_val = PBD::QPC::get_microseconds ();
		CPPUNIT_ASSERT (timer_val >= 0);
		// try and test for non-syncronized TSC(AMD K8/etc)
		CPPUNIT_ASSERT (timer_val >= last_timer_val);
		min_interval = std::min (min_interval, timer_val - last_timer_val);
		// We may get swapped out so a max interval is not so informative
		max_interval = std::max (max_interval, timer_val - last_timer_val);
		last_timer_val = timer_val;
	}

	cout << endl;
	cout << "Min QPC interval = " << min_interval << endl;
	cout << "Max QPC interval = " << max_interval << endl;
}

namespace {

void get_tgt_granularity(uint32_t& min_elapsed,
                         uint32_t& max_elapsed,
                         uint32_t& avg_elapsed)
{
	min_elapsed = 1000;
	max_elapsed = 0;
	uint32_t count = 64;
	uint32_t total_elapsed = 0;

	uint32_t last_time_ms = timeGetTime();
	for (uint32_t i = 0; i < count;) {
		uint32_t current_time_ms = timeGetTime();
		if (current_time_ms == last_time_ms) continue;
		uint32_t elapsed = current_time_ms - last_time_ms;
		cout << "TGT elapsed = " << elapsed << endl;
		min_elapsed = std::min (min_elapsed, elapsed);
		max_elapsed = std::max (max_elapsed, elapsed);
		total_elapsed += elapsed;
		last_time_ms = current_time_ms;
		++i;
	}
	avg_elapsed = total_elapsed / count;
}

void get_sleep_granularity(uint32_t& min_elapsed,
                           uint32_t& max_elapsed,
                           uint32_t& avg_elapsed)
{
	min_elapsed = 1000;
	max_elapsed = 0;
	uint32_t count = 64;
	uint32_t total_elapsed = 0;

	uint32_t last_time_ms = timeGetTime();
	for (uint32_t i = 0; i < count; ++i) {
		Sleep(1);
		uint32_t current_time_ms = timeGetTime();
		uint32_t elapsed = current_time_ms - last_time_ms;
		cout << "Sleep elapsed = " << elapsed << endl;
		min_elapsed = std::min (min_elapsed, elapsed);
		max_elapsed = std::max (max_elapsed, elapsed);
		total_elapsed += elapsed;
		last_time_ms = current_time_ms;
	}
	// the rounding here doesn't matter, we aren't interested in
	// accurate measurements
	avg_elapsed = total_elapsed / count;
}

void
test_tgt_granularity (const std::string& test_name, uint32_t& tgt_avg_elapsed)
{
	uint32_t tgt_min_elapsed = 0;
	uint32_t tgt_max_elapsed = 0;

	get_tgt_granularity(
	    tgt_min_elapsed, tgt_max_elapsed, tgt_avg_elapsed);

	cout << endl;
	cout << "TGT " << test_name << " min elapsed = " << tgt_min_elapsed << endl;
	cout << "TGT " << test_name << " max elapsed = " << tgt_max_elapsed << endl;
	cout << "TGT " << test_name << " avg elapsed = " << tgt_avg_elapsed << endl;
}

void
test_sleep_granularity (const std::string& test_name, uint32_t& sleep_avg_elapsed)
{
	uint32_t sleep_min_elapsed = 0;
	uint32_t sleep_max_elapsed = 0;

	get_sleep_granularity(
	    sleep_min_elapsed, sleep_max_elapsed, sleep_avg_elapsed);

	cout << endl;
	cout << "Sleep " << test_name << " min elapsed = " << sleep_min_elapsed << endl;
	cout << "Sleep " << test_name << " max elapsed = " << sleep_max_elapsed << endl;
	cout << "Sleep " << test_name << " avg elapsed = " << sleep_avg_elapsed << endl;
}

} // namespace

void
WindowsTimerUtilsTest::testMMTimers ()
{
	uint32_t min_timer_res = 0;
	CPPUNIT_ASSERT (PBD::MMTIMERS::get_min_resolution (min_timer_res));
	CPPUNIT_ASSERT (min_timer_res == 1);

	uint32_t avg_orig_res_tgt_elapsed = 0;

	test_tgt_granularity ("Original Timer Resolution", avg_orig_res_tgt_elapsed);

	uint32_t avg_orig_res_sleep_elapsed = 0;

	test_sleep_granularity ("Original Timer Resolution", avg_orig_res_sleep_elapsed);

	// set the min timer resolution
	CPPUNIT_ASSERT (PBD::MMTIMERS::set_min_resolution ());

	uint32_t avg_min_res_tgt_elapsed = 0;

	test_tgt_granularity ("Minimum Timer Resolution", avg_min_res_tgt_elapsed);

	// test that it the avg granularity is the same as miniumum resolution
	CPPUNIT_ASSERT (avg_min_res_tgt_elapsed == 1);

	uint32_t avg_min_res_sleep_elapsed = 0;

	test_sleep_granularity ("Minimum Timer Resolution", avg_min_res_sleep_elapsed);

	// In a heavily loaded system and without running this test with raised
	// scheduling priority we can't assume that the sleep granularity is the
	// same as the minimum timer resolution so give it 1ms of slack, if it is
	// greater than that then there likely is a problem that needs
	// investigating.
	CPPUNIT_ASSERT (avg_min_res_sleep_elapsed <= 2);

	CPPUNIT_ASSERT (PBD::MMTIMERS::reset_resolution());

	// You can't test setting the max timer resolution because AFAIR Windows
	// will use the minimum requested resolution of all the applications on the
	// system.
}