ovr_sdk
diff LibOVR/Src/Kernel/OVR_Lockless.cpp @ 0:1b39a1b46319
initial 0.4.4
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 14 Jan 2015 06:51:16 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/LibOVR/Src/Kernel/OVR_Lockless.cpp Wed Jan 14 06:51:16 2015 +0200 1.3 @@ -0,0 +1,225 @@ 1.4 +/************************************************************************************ 1.5 + 1.6 +Filename : OVR_Lockless.cpp 1.7 +Content : Test logic for lock-less classes 1.8 +Created : December 27, 2013 1.9 +Authors : Michael Antonov 1.10 + 1.11 +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. 1.12 + 1.13 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 1.14 +you may not use the Oculus VR Rift SDK except in compliance with the License, 1.15 +which is provided at the time of installation or download, or which 1.16 +otherwise accompanies this software in either electronic or hard copy form. 1.17 + 1.18 +You may obtain a copy of the License at 1.19 + 1.20 +http://www.oculusvr.com/licenses/LICENSE-3.2 1.21 + 1.22 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 1.23 +distributed under the License is distributed on an "AS IS" BASIS, 1.24 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.25 +See the License for the specific language governing permissions and 1.26 +limitations under the License. 1.27 + 1.28 +*************************************************************************************/ 1.29 + 1.30 +#include "OVR_Lockless.h" 1.31 + 1.32 +#ifdef OVR_LOCKLESS_TEST 1.33 + 1.34 +#include "OVR_Threads.h" 1.35 +#include "OVR_Timer.h" 1.36 +#include "OVR_Log.h" 1.37 + 1.38 +namespace OVR { namespace LocklessTest { 1.39 + 1.40 + 1.41 +const int TestIterations = 10000000; 1.42 + 1.43 +// Use volatile dummies to force compiler to do spinning. 1.44 +volatile int Dummy1; 1.45 +int Unused1[32]; 1.46 +volatile int Dummy2; 1.47 +int Unused2[32]; 1.48 +volatile int Dummy3; 1.49 +int Unused3[32]; 1.50 + 1.51 + 1.52 +// Data block out of 20 consecutive integers, should be internally consistent. 1.53 +struct TestData 1.54 +{ 1.55 + enum { ItemCount = 20 }; 1.56 + 1.57 + int Data[ItemCount]; 1.58 + 1.59 + 1.60 + void Set(int val) 1.61 + { 1.62 + for (int i=0; i<ItemCount; i++) 1.63 + { 1.64 + Data[i] = val*100 + i; 1.65 + } 1.66 + } 1.67 + 1.68 + int ReadAndCheckConsistency(int prevValue) const 1.69 + { 1.70 + int val = Data[0]; 1.71 + 1.72 + for (int i=1; i<ItemCount; i++) 1.73 + { 1.74 + 1.75 + if (Data[i] != (val + i)) 1.76 + { 1.77 + // Only complain once per same-value entry 1.78 + if (prevValue != val / 100) 1.79 + { 1.80 + LogText("LocklessTest Fail - corruption at %d inside block %d\n", 1.81 + i, val/100); 1.82 + // OVR_ASSERT(Data[i] == val + i); 1.83 + } 1.84 + break; 1.85 + } 1.86 + } 1.87 + 1.88 + return val / 100; 1.89 + } 1.90 +}; 1.91 + 1.92 + 1.93 + 1.94 +volatile bool FirstItemWritten = false; 1.95 +LocklessUpdater<TestData, TestData> TestDataUpdater; 1.96 + 1.97 +// Use this lock to verify that testing algorithm is otherwise correct... 1.98 +Lock TestLock; 1.99 + 1.100 + 1.101 +//------------------------------------------------------------------------------------- 1.102 + 1.103 +// Consumer thread reads values from TestDataUpdater and 1.104 +// ensures that each one is internally consistent. 1.105 + 1.106 +class Consumer : public Thread 1.107 +{ 1.108 + virtual int Run() 1.109 + { 1.110 + LogText("LocklessTest::Consumer::Run started.\n"); 1.111 + 1.112 + while (!FirstItemWritten) 1.113 + { 1.114 + // spin until producer wrote first value... 1.115 + } 1.116 + 1.117 + TestData d; 1.118 + int oldValue = 0; 1.119 + int newValue; 1.120 + 1.121 + do 1.122 + { 1.123 + { 1.124 + //Lock::Locker scope(&TestLock); 1.125 + d = TestDataUpdater.GetState(); 1.126 + } 1.127 + 1.128 + newValue = d.ReadAndCheckConsistency(oldValue); 1.129 + 1.130 + // Values should increase or stay the same! 1.131 + if (newValue < oldValue) 1.132 + { 1.133 + LogText("LocklessTest Fail - %d after %d; delta = %d\n", 1.134 + newValue, oldValue, newValue - oldValue); 1.135 + // OVR_ASSERT(0); 1.136 + } 1.137 + 1.138 + 1.139 + if (oldValue != newValue) 1.140 + { 1.141 + oldValue = newValue; 1.142 + 1.143 + if (oldValue % (TestIterations/30) == 0) 1.144 + { 1.145 + LogText("LocklessTest::Consumer - %5.2f%% done\n", 1.146 + 100.0f * (float)oldValue/(float)TestIterations); 1.147 + } 1.148 + } 1.149 + 1.150 + // Spin a while 1.151 + for (int j = 0; j< 300; j++) 1.152 + { 1.153 + Dummy3 = j; 1.154 + } 1.155 + 1.156 + 1.157 + } while (oldValue < (TestIterations * 99 / 100)); 1.158 + 1.159 + LogText("LocklessTest::Consumer::Run exiting.\n"); 1.160 + return 0; 1.161 + } 1.162 + 1.163 +}; 1.164 + 1.165 + 1.166 +//------------------------------------------------------------------------------------- 1.167 + 1.168 +class Producer : public Thread 1.169 +{ 1.170 + 1.171 + virtual int Run() 1.172 + { 1.173 + LogText("LocklessTest::Producer::Run started.\n"); 1.174 + 1.175 + for (int testVal = 0; testVal < TestIterations; testVal++) 1.176 + { 1.177 + TestData d; 1.178 + d.Set(testVal); 1.179 + 1.180 + { 1.181 + //Lock::Locker scope(&TestLock); 1.182 + TestDataUpdater.SetState(d); 1.183 + } 1.184 + 1.185 + FirstItemWritten = true; 1.186 + 1.187 + // Spin a bit 1.188 + for(int j = 0; j < 1000; j++) 1.189 + { 1.190 + Dummy2 = j; 1.191 + } 1.192 + 1.193 + if (testVal % (TestIterations/30) == 0) 1.194 + { 1.195 + LogText("LocklessTest::Producer - %5.2f%% done\n", 1.196 + 100.0f * (float)testVal/(float)TestIterations); 1.197 + } 1.198 + } 1.199 + 1.200 + LogText("LocklessTest::Producer::Run exiting.\n"); 1.201 + return 0; 1.202 + } 1.203 +}; 1.204 + 1.205 + 1.206 +} // namespace LocklessTest 1.207 + 1.208 + 1.209 + 1.210 +void StartLocklessTest() 1.211 +{ 1.212 + // These threads will release themselves once done 1.213 + Ptr<LocklessTest::Producer> producerThread = *new LocklessTest::Producer; 1.214 + Ptr<LocklessTest::Consumer> consumerThread = *new LocklessTest::Consumer; 1.215 + 1.216 + producerThread->Start(); 1.217 + consumerThread->Start(); 1.218 + 1.219 + while (!producerThread->IsFinished() && consumerThread->IsFinished()) 1.220 + { 1.221 + Thread::MSleep(500); 1.222 + } 1.223 +} 1.224 + 1.225 + 1.226 +} // namespace OVR 1.227 + 1.228 +#endif // OVR_LOCKLESS_TEST