rev |
line source |
nuclear@0
|
1 /************************************************************************************
|
nuclear@0
|
2
|
nuclear@0
|
3 Filename : OVR_Lockless.cpp
|
nuclear@0
|
4 Content : Test logic for lock-less classes
|
nuclear@0
|
5 Created : December 27, 2013
|
nuclear@0
|
6 Authors : Michael Antonov
|
nuclear@0
|
7
|
nuclear@0
|
8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
|
nuclear@0
|
11 you may not use the Oculus VR Rift SDK except in compliance with the License,
|
nuclear@0
|
12 which is provided at the time of installation or download, or which
|
nuclear@0
|
13 otherwise accompanies this software in either electronic or hard copy form.
|
nuclear@0
|
14
|
nuclear@0
|
15 You may obtain a copy of the License at
|
nuclear@0
|
16
|
nuclear@0
|
17 http://www.oculusvr.com/licenses/LICENSE-3.2
|
nuclear@0
|
18
|
nuclear@0
|
19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
|
nuclear@0
|
20 distributed under the License is distributed on an "AS IS" BASIS,
|
nuclear@0
|
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
nuclear@0
|
22 See the License for the specific language governing permissions and
|
nuclear@0
|
23 limitations under the License.
|
nuclear@0
|
24
|
nuclear@0
|
25 *************************************************************************************/
|
nuclear@0
|
26
|
nuclear@0
|
27 #include "OVR_Lockless.h"
|
nuclear@0
|
28
|
nuclear@0
|
29 #ifdef OVR_LOCKLESS_TEST
|
nuclear@0
|
30
|
nuclear@0
|
31 #include "OVR_Threads.h"
|
nuclear@0
|
32 #include "OVR_Timer.h"
|
nuclear@0
|
33 #include "OVR_Log.h"
|
nuclear@0
|
34
|
nuclear@0
|
35 namespace OVR { namespace LocklessTest {
|
nuclear@0
|
36
|
nuclear@0
|
37
|
nuclear@0
|
38 const int TestIterations = 10000000;
|
nuclear@0
|
39
|
nuclear@0
|
40 // Use volatile dummies to force compiler to do spinning.
|
nuclear@0
|
41 volatile int Dummy1;
|
nuclear@0
|
42 int Unused1[32];
|
nuclear@0
|
43 volatile int Dummy2;
|
nuclear@0
|
44 int Unused2[32];
|
nuclear@0
|
45 volatile int Dummy3;
|
nuclear@0
|
46 int Unused3[32];
|
nuclear@0
|
47
|
nuclear@0
|
48
|
nuclear@0
|
49 // Data block out of 20 consecutive integers, should be internally consistent.
|
nuclear@0
|
50 struct TestData
|
nuclear@0
|
51 {
|
nuclear@0
|
52 enum { ItemCount = 20 };
|
nuclear@0
|
53
|
nuclear@0
|
54 int Data[ItemCount];
|
nuclear@0
|
55
|
nuclear@0
|
56
|
nuclear@0
|
57 void Set(int val)
|
nuclear@0
|
58 {
|
nuclear@0
|
59 for (int i=0; i<ItemCount; i++)
|
nuclear@0
|
60 {
|
nuclear@0
|
61 Data[i] = val*100 + i;
|
nuclear@0
|
62 }
|
nuclear@0
|
63 }
|
nuclear@0
|
64
|
nuclear@0
|
65 int ReadAndCheckConsistency(int prevValue) const
|
nuclear@0
|
66 {
|
nuclear@0
|
67 int val = Data[0];
|
nuclear@0
|
68
|
nuclear@0
|
69 for (int i=1; i<ItemCount; i++)
|
nuclear@0
|
70 {
|
nuclear@0
|
71
|
nuclear@0
|
72 if (Data[i] != (val + i))
|
nuclear@0
|
73 {
|
nuclear@0
|
74 // Only complain once per same-value entry
|
nuclear@0
|
75 if (prevValue != val / 100)
|
nuclear@0
|
76 {
|
nuclear@0
|
77 LogText("LocklessTest Fail - corruption at %d inside block %d\n",
|
nuclear@0
|
78 i, val/100);
|
nuclear@0
|
79 // OVR_ASSERT(Data[i] == val + i);
|
nuclear@0
|
80 }
|
nuclear@0
|
81 break;
|
nuclear@0
|
82 }
|
nuclear@0
|
83 }
|
nuclear@0
|
84
|
nuclear@0
|
85 return val / 100;
|
nuclear@0
|
86 }
|
nuclear@0
|
87 };
|
nuclear@0
|
88
|
nuclear@0
|
89
|
nuclear@0
|
90
|
nuclear@0
|
91 volatile bool FirstItemWritten = false;
|
nuclear@0
|
92 LocklessUpdater<TestData, TestData> TestDataUpdater;
|
nuclear@0
|
93
|
nuclear@0
|
94 // Use this lock to verify that testing algorithm is otherwise correct...
|
nuclear@0
|
95 Lock TestLock;
|
nuclear@0
|
96
|
nuclear@0
|
97
|
nuclear@0
|
98 //-------------------------------------------------------------------------------------
|
nuclear@0
|
99
|
nuclear@0
|
100 // Consumer thread reads values from TestDataUpdater and
|
nuclear@0
|
101 // ensures that each one is internally consistent.
|
nuclear@0
|
102
|
nuclear@0
|
103 class Consumer : public Thread
|
nuclear@0
|
104 {
|
nuclear@0
|
105 virtual int Run()
|
nuclear@0
|
106 {
|
nuclear@0
|
107 LogText("LocklessTest::Consumer::Run started.\n");
|
nuclear@0
|
108
|
nuclear@0
|
109 while (!FirstItemWritten)
|
nuclear@0
|
110 {
|
nuclear@0
|
111 // spin until producer wrote first value...
|
nuclear@0
|
112 }
|
nuclear@0
|
113
|
nuclear@0
|
114 TestData d;
|
nuclear@0
|
115 int oldValue = 0;
|
nuclear@0
|
116 int newValue;
|
nuclear@0
|
117
|
nuclear@0
|
118 do
|
nuclear@0
|
119 {
|
nuclear@0
|
120 {
|
nuclear@0
|
121 //Lock::Locker scope(&TestLock);
|
nuclear@0
|
122 d = TestDataUpdater.GetState();
|
nuclear@0
|
123 }
|
nuclear@0
|
124
|
nuclear@0
|
125 newValue = d.ReadAndCheckConsistency(oldValue);
|
nuclear@0
|
126
|
nuclear@0
|
127 // Values should increase or stay the same!
|
nuclear@0
|
128 if (newValue < oldValue)
|
nuclear@0
|
129 {
|
nuclear@0
|
130 LogText("LocklessTest Fail - %d after %d; delta = %d\n",
|
nuclear@0
|
131 newValue, oldValue, newValue - oldValue);
|
nuclear@0
|
132 // OVR_ASSERT(0);
|
nuclear@0
|
133 }
|
nuclear@0
|
134
|
nuclear@0
|
135
|
nuclear@0
|
136 if (oldValue != newValue)
|
nuclear@0
|
137 {
|
nuclear@0
|
138 oldValue = newValue;
|
nuclear@0
|
139
|
nuclear@0
|
140 if (oldValue % (TestIterations/30) == 0)
|
nuclear@0
|
141 {
|
nuclear@0
|
142 LogText("LocklessTest::Consumer - %5.2f%% done\n",
|
nuclear@0
|
143 100.0f * (float)oldValue/(float)TestIterations);
|
nuclear@0
|
144 }
|
nuclear@0
|
145 }
|
nuclear@0
|
146
|
nuclear@0
|
147 // Spin a while
|
nuclear@0
|
148 for (int j = 0; j< 300; j++)
|
nuclear@0
|
149 {
|
nuclear@0
|
150 Dummy3 = j;
|
nuclear@0
|
151 }
|
nuclear@0
|
152
|
nuclear@0
|
153
|
nuclear@0
|
154 } while (oldValue < (TestIterations * 99 / 100));
|
nuclear@0
|
155
|
nuclear@0
|
156 LogText("LocklessTest::Consumer::Run exiting.\n");
|
nuclear@0
|
157 return 0;
|
nuclear@0
|
158 }
|
nuclear@0
|
159
|
nuclear@0
|
160 };
|
nuclear@0
|
161
|
nuclear@0
|
162
|
nuclear@0
|
163 //-------------------------------------------------------------------------------------
|
nuclear@0
|
164
|
nuclear@0
|
165 class Producer : public Thread
|
nuclear@0
|
166 {
|
nuclear@0
|
167
|
nuclear@0
|
168 virtual int Run()
|
nuclear@0
|
169 {
|
nuclear@0
|
170 LogText("LocklessTest::Producer::Run started.\n");
|
nuclear@0
|
171
|
nuclear@0
|
172 for (int testVal = 0; testVal < TestIterations; testVal++)
|
nuclear@0
|
173 {
|
nuclear@0
|
174 TestData d;
|
nuclear@0
|
175 d.Set(testVal);
|
nuclear@0
|
176
|
nuclear@0
|
177 {
|
nuclear@0
|
178 //Lock::Locker scope(&TestLock);
|
nuclear@0
|
179 TestDataUpdater.SetState(d);
|
nuclear@0
|
180 }
|
nuclear@0
|
181
|
nuclear@0
|
182 FirstItemWritten = true;
|
nuclear@0
|
183
|
nuclear@0
|
184 // Spin a bit
|
nuclear@0
|
185 for(int j = 0; j < 1000; j++)
|
nuclear@0
|
186 {
|
nuclear@0
|
187 Dummy2 = j;
|
nuclear@0
|
188 }
|
nuclear@0
|
189
|
nuclear@0
|
190 if (testVal % (TestIterations/30) == 0)
|
nuclear@0
|
191 {
|
nuclear@0
|
192 LogText("LocklessTest::Producer - %5.2f%% done\n",
|
nuclear@0
|
193 100.0f * (float)testVal/(float)TestIterations);
|
nuclear@0
|
194 }
|
nuclear@0
|
195 }
|
nuclear@0
|
196
|
nuclear@0
|
197 LogText("LocklessTest::Producer::Run exiting.\n");
|
nuclear@0
|
198 return 0;
|
nuclear@0
|
199 }
|
nuclear@0
|
200 };
|
nuclear@0
|
201
|
nuclear@0
|
202
|
nuclear@0
|
203 } // namespace LocklessTest
|
nuclear@0
|
204
|
nuclear@0
|
205
|
nuclear@0
|
206
|
nuclear@0
|
207 void StartLocklessTest()
|
nuclear@0
|
208 {
|
nuclear@0
|
209 // These threads will release themselves once done
|
nuclear@0
|
210 Ptr<LocklessTest::Producer> producerThread = *new LocklessTest::Producer;
|
nuclear@0
|
211 Ptr<LocklessTest::Consumer> consumerThread = *new LocklessTest::Consumer;
|
nuclear@0
|
212
|
nuclear@0
|
213 producerThread->Start();
|
nuclear@0
|
214 consumerThread->Start();
|
nuclear@0
|
215
|
nuclear@0
|
216 while (!producerThread->IsFinished() && consumerThread->IsFinished())
|
nuclear@0
|
217 {
|
nuclear@0
|
218 Thread::MSleep(500);
|
nuclear@0
|
219 }
|
nuclear@0
|
220 }
|
nuclear@0
|
221
|
nuclear@0
|
222
|
nuclear@0
|
223 } // namespace OVR
|
nuclear@0
|
224
|
nuclear@0
|
225 #endif // OVR_LOCKLESS_TEST
|