Bladeren bron

Ported thread pool and refcount tests. Failures, not sure why yet.

Daniel Buckmaster 11 jaren geleden
bovenliggende
commit
96011623ef

+ 0 - 227
Engine/source/platform/test/testThreadSafeRefCount.cpp

@@ -1,227 +0,0 @@
-//-----------------------------------------------------------------------------
-// Copyright (c) 2012 GarageGames, LLC
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-// IN THE SOFTWARE.
-//-----------------------------------------------------------------------------
-
-#include "unit/test.h"
-#include "platform/threads/threadSafeRefCount.h"
-#include "platform/threads/thread.h"
-#include "core/util/tVector.h"
-#include "console/console.h"
-
-#ifndef TORQUE_SHIPPING
-
-using namespace UnitTesting;
-
-#define TEST( x ) test( ( x ), "FAIL: " #x )
-
-CreateUnitTest( TestThreadSafeRefCountSerial, "Platform/ThreadSafeRefCount/Serial" )
-{
-   struct TestObject : public ThreadSafeRefCount< TestObject >
-   {
-      static bool smDeleted;
-
-      TestObject()
-      {
-         smDeleted = false;
-      }
-      ~TestObject()
-      {
-         smDeleted = true;
-      }
-   };
-
-   typedef ThreadSafeRef< TestObject > TestObjectRef;
-
-   void run()
-   {
-      TestObjectRef ref1 = new TestObject;
-      TEST( !ref1->isShared() );
-      TEST( ref1 != NULL );
-
-      TestObjectRef ref2 = ref1;
-      TEST( ref1->isShared() );
-      TEST( ref2->isShared() );
-      TEST( ref1 == ref2 );
-
-      ref1 = NULL;
-      TEST( !ref2->isShared() );
-
-      ref2 = NULL;
-      TEST( TestObject::smDeleted );
-   }
-};
-
-bool TestThreadSafeRefCountSerial::TestObject::smDeleted;
-
-CreateUnitTest( TestThreadSafeRefCountConcurrent, "Platform/ThreadSafeRefCount/Concurrent" )
-{
-public:
-   typedef TestThreadSafeRefCountConcurrent TestType;
-   enum
-   {
-      NUM_ADD_REFS_PER_THREAD = 1000,
-      NUM_EXTRA_REFS_PER_THREAD = 1000,
-      NUM_THREADS = 10
-   };
-   
-   class TestObject : public ThreadSafeRefCount< TestObject >
-   {
-      public:
-   };
-   
-   ThreadSafeRef< TestObject > mRef;
-   
-   class TestThread : public Thread
-   {
-      public:
-         TestType* mTest;
-         Vector< ThreadSafeRef< TestObject > > mExtraRefs;
-         
-         TestThread( TestType* test )
-            : mTest( test ) {}
-         
-         void run( void* arg )
-         {
-            if( !arg )
-            {
-               for( U32 i = 0; i < NUM_ADD_REFS_PER_THREAD; ++ i )
-                  mTest->mRef->addRef();
-                  
-               mExtraRefs.setSize( NUM_EXTRA_REFS_PER_THREAD );
-               for( U32 i = 0; i < NUM_EXTRA_REFS_PER_THREAD; ++ i )
-                  mExtraRefs[ i ] = mTest->mRef;
-            }
-            else
-            {
-               mExtraRefs.clear();
-               
-               for( U32 i = 0; i < NUM_ADD_REFS_PER_THREAD; ++ i )
-                  mTest->mRef->release();
-            }
-         } 
-   };
-   
-   void run()
-   {
-      mRef = new TestObject;
-      TEST( mRef->getRefCount() == 2 ); // increments of 2
-      
-      Vector< TestThread* > threads;
-      threads.setSize( NUM_THREADS );
-      
-      // Create threads.
-      for( U32 i = 0; i < NUM_THREADS; ++ i )
-         threads[ i ] = new TestThread( this );
-         
-      // Run phase 1: create references.
-      for( U32 i = 0; i < NUM_THREADS; ++ i )
-         threads[ i ]->start( NULL );
-               
-      // Wait for completion.
-      for( U32 i = 0; i < NUM_THREADS; ++ i )
-         threads[ i ]->join();
-         
-      Con::printf( "REF: %i", mRef->getRefCount() );
-      TEST( mRef->getRefCount() == 2 + ( ( NUM_ADD_REFS_PER_THREAD + NUM_EXTRA_REFS_PER_THREAD ) * NUM_THREADS * 2 ) );
-
-      // Run phase 2: release references.
-      for( U32 i = 0; i < NUM_THREADS; ++ i )
-         threads[ i ]->start( ( void* ) 1 );
-         
-      // Wait for completion.
-      for( U32 i = 0; i < NUM_THREADS; ++ i )
-      {
-         threads[ i ]->join();
-         delete threads[ i ];
-      }
-      
-      TEST( mRef->getRefCount() == 2 ); // increments of two
-
-      mRef = NULL;
-   }
-};
-
-CreateUnitTest( TestThreadSafeRefCountTagging, "Platform/ThreadSafeRefCount/Tagging" )
-{
-   struct TestObject : public ThreadSafeRefCount< TestObject > {};
-
-   typedef ThreadSafeRef< TestObject > TestObjectRef;
-
-   void run()
-   {
-      TestObjectRef ref;
-
-      TEST( !ref.isTagged() );
-      TEST( !ref );
-      TEST( !ref.ptr() );
-      
-      TEST( ref.trySetFromTo( ref, NULL ) );
-      TEST( !ref.isTagged() );
-
-      TEST( ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_Set ) );
-      TEST( ref.isTagged() );
-      TEST( ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_Set ) );
-      TEST( ref.isTagged() );
-
-      TEST( ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_Unset ) );
-      TEST( !ref.isTagged() );
-      TEST( ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_Unset ) );
-      TEST( !ref.isTagged() );
-
-      TEST( ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_SetOrFail ) );
-      TEST( ref.isTagged() );
-      TEST( !ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_SetOrFail ) );
-      TEST( ref.isTagged() );
-      TEST( !ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_FailIfSet ) );
-
-      TEST( ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_UnsetOrFail ) );
-      TEST( !ref.isTagged() );
-      TEST( !ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_UnsetOrFail ) );
-      TEST( !ref.isTagged() );
-      TEST( !ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_FailIfUnset ) );
-
-      TestObjectRef objectA = new TestObject;
-      TestObjectRef objectB = new TestObject;
-
-      TEST( !objectA->isShared() );
-      TEST( !objectB->isShared() );
-
-      ref = objectA;
-      TEST( !ref.isTagged() );
-      TEST( ref == objectA );
-      TEST( ref == objectA.ptr() );
-      TEST( objectA->isShared() );
-
-      TEST( ref.trySetFromTo( objectA, objectB, TestObjectRef::TAG_Set ) );
-      TEST( ref.isTagged() );
-      TEST( ref == objectB );
-      TEST( ref == objectB.ptr() );
-      TEST( objectB->isShared() );
-      TEST( !objectA->isShared() );
-
-      TEST( ref.trySetFromTo( ref, objectA ) );
-      TEST( ref.isTagged() );
-      TEST( ref == objectA );
-      TEST( ref == objectA.ptr() );
-   }
-};
-
-#endif // !TORQUE_SHIPPING

+ 37 - 51
Engine/source/platform/test/testThreadPool.cpp → Engine/source/platform/threads/test/threadPoolTest.cpp

@@ -1,5 +1,5 @@
 //-----------------------------------------------------------------------------
-// Copyright (c) 2012 GarageGames, LLC
+// Copyright (c) 2014 GarageGames, LLC
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to
@@ -20,66 +20,52 @@
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
 
-#include "unit/test.h"
+#ifdef TORQUE_TESTS_ENABLED
+#include "testing/unitTesting.h"
 #include "platform/threads/threadPool.h"
 #include "console/console.h"
 #include "core/util/tVector.h"
 
-#ifndef TORQUE_SHIPPING
-
-using namespace UnitTesting;
-
-#define TEST( x ) test( ( x ), "FAIL: " #x )
-
-// Simple test that creates and verifies an array of numbers using
-// thread pool work items.
-
-CreateUnitTest( TestThreadPool, "Platform/ThreadPool/Simple" )
+TEST(ThreadPool, BasicAPI)
 {
-   enum { DEFAULT_NUM_ITEMS = 4000 };
-   
-   static Vector< U32 > results;
-   
+   // Represents a single unit of work. In this test we just set an element in
+   // a result vector.
    struct TestItem : public ThreadPool::WorkItem
    {
-         typedef ThreadPool::WorkItem Parent;
-         
-         U32 mIndex;
-         
-         TestItem( U32 index )
-            : mIndex( index ) {}
-      
-      protected:
-         virtual void execute()
-         {
-            results[ mIndex ] = mIndex;
-         }
-   };
-   
-   void run()
-   {
-      U32 numItems = Con::getIntVariable( "$testThreadPool::numValues", DEFAULT_NUM_ITEMS );
-      ThreadPool* pool = &ThreadPool::GLOBAL();
-      results.setSize( numItems );
+      U32 mIndex;
+      Vector<U32>& mResults;
+      TestItem(U32 index, Vector<U32>& results)
+         : mIndex(index), mResults(results) {}
 
-      for( U32 i = 0; i < numItems; ++ i )
-         results[ i ] = U32( -1 );
-      
-      for( U32 i = 0; i < numItems; ++ i )
+   protected:
+      virtual void execute()
       {
-         ThreadSafeRef< TestItem > item( new TestItem( i ) );
-         pool->queueWorkItem( item );
+         mResults[mIndex] = mIndex;
       }
-      
-      pool->flushWorkItems();
-      
-      for( U32 i = 0; i < numItems; ++ i )
-         test( results[ i ] == i, "result mismatch" );
-         
-      results.clear();
+   };
+
+   // Construct the vector of results from the work items.
+   const U32 numItems = 100;
+   Vector<U32> results(__FILE__, __LINE__);
+   results.setSize(numItems);
+   for (U32 i = 0; i < numItems; i++)
+      results[i] = U32(-1);
+
+   // Launch the work items.
+   ThreadPool* pool = &ThreadPool::GLOBAL();
+   for (U32 i = 0; i < numItems; i++)
+   {
+      ThreadSafeRef<TestItem> item(new TestItem(i, results));
+      pool->queueWorkItem(item);
    }
-};
 
-Vector< U32 > TestThreadPool::results( __FILE__, __LINE__ );
+   // Wait for all items to complete.
+   pool->flushWorkItems();
+
+   // Verify.
+   for (U32 i = 0; i < numItems; i++)
+      EXPECT_EQ(results[i], i) << "result mismatch";
+   results.clear();
+}
 
-#endif // !TORQUE_SHIPPING
+#endif

+ 204 - 0
Engine/source/platform/threads/test/threadSafeRefCountTest.cpp

@@ -0,0 +1,204 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2014 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifdef TORQUE_TESTS_ENABLED
+#include "testing/unitTesting.h"
+#include "platform/threads/threadSafeRefCount.h"
+#include "platform/threads/thread.h"
+#include "core/util/tVector.h"
+#include "console/console.h"
+
+TEST(ThreadSafeRefCount, Serial)
+{
+   struct TestObject : public ThreadSafeRefCount<TestObject>
+   {
+      bool &flag;
+      TestObject(bool &f) : flag(f)
+      {
+         flag = false;
+      }
+      ~TestObject()
+      {
+         flag = true;
+      }
+   };
+   typedef ThreadSafeRef<TestObject> TestObjectRef;
+
+   bool deleted = false;
+   TestObjectRef ref1 = new TestObject(deleted);
+   ASSERT_FALSE(deleted);
+   EXPECT_FALSE(ref1->isShared());
+   EXPECT_TRUE(ref1 != NULL);
+
+   TestObjectRef ref2 = ref1;
+   EXPECT_TRUE(ref1->isShared());
+   EXPECT_TRUE(ref2->isShared());
+   EXPECT_EQ(ref1, ref2);
+
+   ref1 = NULL;
+   EXPECT_FALSE(ref2->isShared());
+
+   ref2 = NULL;
+   ASSERT_TRUE(deleted);
+}
+
+TEST(ThreadSafeRefCount, Concurrent)
+{
+   enum
+   {
+      NUM_ADD_REFS_PER_THREAD = 10,
+      NUM_EXTRA_REFS_PER_THREAD = 10,
+      NUM_THREADS = 10
+   };
+   
+   class TestObject : public ThreadSafeRefCount<TestObject> {};
+   typedef ThreadSafeRef<TestObject> TestObjectRef;
+   TestObjectRef mRef;
+   
+   class TestThread : public Thread
+   {
+   public:
+      TestObjectRef mRef;
+      Vector<TestObjectRef> mExtraRefs;
+
+      TestThread(TestObjectRef ref) : mRef(ref) {}
+
+      void run(void* arg)
+      {
+         if (!arg)
+         {
+            // Create references.
+            for (U32 i = 0; i < NUM_ADD_REFS_PER_THREAD; i++)
+               mRef->addRef();
+
+            mExtraRefs.setSize(NUM_EXTRA_REFS_PER_THREAD);
+            for (U32 i = 0; i < NUM_EXTRA_REFS_PER_THREAD; i++)
+               mExtraRefs[i] = mRef;
+         }
+         else
+         {
+            // Clear references.
+            mExtraRefs.clear();
+            for (U32 i = 0; i < NUM_ADD_REFS_PER_THREAD; i++)
+               mRef->release();
+         }
+      } 
+   };
+
+   mRef = new TestObject;
+   EXPECT_EQ(mRef->getRefCount(), 2); // increments of 2
+
+   Vector<TestThread*> threads;
+   threads.setSize(NUM_THREADS);
+
+   // Create threads.
+   for (U32 i = 0; i < NUM_THREADS; i++)
+      threads[i] = new TestThread(mRef);
+
+   // Run phase 1: create references.
+   for (U32 i = 0; i < NUM_THREADS; i++)
+      threads[i]->start(NULL);
+
+   // Wait for completion.
+   for (U32 i = 0; i < NUM_THREADS; i++)
+      threads[i]->join();
+
+   Con::printf("REF: %i", mRef->getRefCount());
+   EXPECT_EQ(mRef->getRefCount(), 2 + ((NUM_ADD_REFS_PER_THREAD + NUM_EXTRA_REFS_PER_THREAD) * NUM_THREADS * 2));
+
+   // Run phase 2: release references.
+   for (U32 i = 0; i < NUM_THREADS; i++)
+      threads[i]->start((void*) 1);
+
+   // Wait for completion.
+   for (U32 i = 0; i < NUM_THREADS; i++)
+   {
+      threads[i]->join();
+      delete threads[i];
+   }
+
+   EXPECT_EQ(mRef->getRefCount(), 2); // increments of two
+
+   mRef = NULL;
+}
+
+TEST(ThreadSafeRefCount, Tagging)
+{
+   struct TestObject : public ThreadSafeRefCount<TestObject> {};
+   typedef ThreadSafeRef<TestObject> TestObjectRef;
+
+   TestObjectRef ref;
+   EXPECT_FALSE(ref.isTagged());
+   EXPECT_TRUE(bool(ref));
+   EXPECT_FALSE(bool(ref.ptr()));
+
+   EXPECT_TRUE(ref.trySetFromTo(ref, NULL));
+   EXPECT_FALSE(ref.isTagged());
+
+   EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_Set));
+   EXPECT_TRUE(ref.isTagged());
+   EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_Set));
+   EXPECT_TRUE(ref.isTagged());
+
+   EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_Unset));
+   EXPECT_FALSE(ref.isTagged());
+   EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_Unset));
+   EXPECT_FALSE(ref.isTagged());
+
+   EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_SetOrFail));
+   EXPECT_TRUE(ref.isTagged());
+   EXPECT_FALSE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_SetOrFail));
+   EXPECT_TRUE(ref.isTagged());
+   EXPECT_FALSE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_FailIfSet));
+
+   EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_UnsetOrFail));
+   EXPECT_FALSE(ref.isTagged());
+   EXPECT_FALSE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_UnsetOrFail));
+   EXPECT_FALSE(ref.isTagged());
+   EXPECT_FALSE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_FailIfUnset));
+
+   TestObjectRef objectA = new TestObject;
+   TestObjectRef objectB = new TestObject;
+
+   EXPECT_FALSE(objectA->isShared());
+   EXPECT_FALSE(objectB->isShared());
+
+   ref = objectA;
+   EXPECT_FALSE(ref.isTagged());
+   EXPECT_TRUE(ref == objectA);
+   EXPECT_TRUE(ref == objectA.ptr());
+   EXPECT_TRUE(objectA->isShared());
+
+   EXPECT_TRUE(ref.trySetFromTo(objectA, objectB, TestObjectRef::TAG_Set));
+   EXPECT_TRUE(ref.isTagged());
+   EXPECT_EQ(ref, objectB);
+   EXPECT_EQ(ref, objectB.ptr());
+   EXPECT_TRUE(objectB->isShared());
+   EXPECT_FALSE(objectA->isShared());
+
+   EXPECT_TRUE(ref.trySetFromTo(ref, objectA));
+   EXPECT_TRUE(ref.isTagged());
+   EXPECT_EQ(ref, objectA);
+   EXPECT_EQ(ref, objectA.ptr());
+}
+
+#endif