ovr_sdk

annotate 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
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