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