#include "../memory/PoolAllocator.hpp" #include "../memory/StlWrapper.hpp" #include "../memory/opaque_type.hpp" #include <algorithm> #include "../threading/thread.hpp" #include "../string/String.hpp" #include "../time/time.hpp" #include "gtest_helpers.hpp" #include <gtest/gtest.h> const int iterations_alloc = 10000; const int iterations_threaded = 1000; struct MyBigStruct { int64_t data[512]; }; struct MyMediumStruct { int64_t data[256]; }; struct MySmallStruct { int64_t data[128]; }; struct MyTinyStruct { int64_t data[64]; }; #define ADD_TEST_DYNAMIC_2(testType, SIZE, counter) \ static void testType##_test_dynamic_##SIZE() \ { \ typedef sprawl::memory::PoolAllocator<sizeof(testType)> allocator##counter; \ \ testType* arr##counter[SIZE]; \ \ size_t nums##counter[SIZE]; \ \ for(int i = 0; i < SIZE; ++i) \ { \ nums##counter[i] = i; \ } \ \ for(int j = 0; j < 1; ++j) \ { \ std::random_shuffle(&nums##counter[0], &nums##counter[SIZE]); \ { \ for(int i = 0; i < SIZE; ++i) \ { \ arr##counter[nums##counter[i]] = (testType*)allocator##counter::alloc(); \ } \ } \ std::random_shuffle(&nums##counter[0], &nums##counter[SIZE]); \ { \ for(int i = SIZE; i > 0; --i) \ { \ allocator##counter::free(arr##counter[nums##counter[i-1]]); \ } \ } \ } \ } \ static void PoolAllocator_##testType##_##SIZE() \ { \ int64_t total = 0; \ int64_t high = 0; \ int64_t low = 0; \ for(int i = 0; i < iterations_alloc; ++i) \ { \ int64_t start = sprawl::time::Now(sprawl::time::Resolution::Nanoseconds); \ testType##_test_dynamic_##SIZE(); \ int64_t elapsed = sprawl::time::Now(sprawl::time::Resolution::Nanoseconds) - start; \ total += elapsed; \ if(high == 0 || elapsed > high) high = elapsed; \ if(low == 0 || elapsed < low) low = elapsed; \ } \ printf("\t" #testType " (" #SIZE ") - %d runs. Best: %" SPRAWL_I64FMT "d ns, Worst: %" SPRAWL_I64FMT "d ns, Average: %" SPRAWL_I64FMT "d ns\n", iterations_alloc, low, high, total / iterations_alloc); \ fflush(stdout); \ fprintf(stderr, "Success"); \ exit(0); \ } \ TEST(PoolAllocatorDeathTest, PoolAllocator_##testType##_##SIZE) \ { \ ASSERT_EXIT(PoolAllocator_##testType##_##SIZE(), testing::ExitedWithCode(0), "Success"); \ } #define ADD_TEST_DYNAMIC(testType, SIZE, counter) ADD_TEST_DYNAMIC_2(testType, SIZE, counter) #define ADD_TESTS(type) \ ADD_TEST_DYNAMIC(type, 8, __COUNTER__) \ ADD_TEST_DYNAMIC(type, 32, __COUNTER__) \ ADD_TEST_DYNAMIC(type, 128, __COUNTER__) ADD_TESTS(MyBigStruct) ADD_TESTS(MyMediumStruct) ADD_TESTS(MySmallStruct) ADD_TESTS(MyTinyStruct) ADD_TESTS(int64_t) #ifdef SPRAWL_MULTITHREADED void alloc_dealloc_sprawl_strings() { for(int i = 0; i < 1000; ++i) { sprawl::String outerStr("outer"); { sprawl::String str("blah blah blah blah"); EXPECT_FALSE(str.empty()); EXPECT_EQ(sprawl::String("blah blah blah blah"), str); } { sprawl::String str("bleh bleh bleh bleh"); EXPECT_FALSE(str.empty()); EXPECT_EQ(sprawl::String("bleh bleh bleh bleh"), str); } { sprawl::String str(""); EXPECT_TRUE(str.empty()); EXPECT_EQ(sprawl::String(""), str); } EXPECT_FALSE(outerStr.empty()); EXPECT_EQ(sprawl::String("outer"), outerStr); } } TEST(PoolAllocatorTest, TestAllocatorThreadSafe) { printf("(This should take a second)...\n"); fflush(stdout); sprawl::threading::Thread thread1(alloc_dealloc_sprawl_strings); sprawl::threading::Thread thread2(alloc_dealloc_sprawl_strings); sprawl::threading::Thread thread3(alloc_dealloc_sprawl_strings); sprawl::threading::Thread thread4(alloc_dealloc_sprawl_strings); sprawl::threading::Thread thread5(alloc_dealloc_sprawl_strings); int64_t total = 0; int64_t high = 0; int64_t low = 0; for(int i = 0; i < iterations_threaded; ++i) { int64_t start = sprawl::time::Now(sprawl::time::Resolution::Microseconds); thread1.Start(); thread2.Start(); thread3.Start(); thread4.Start(); thread5.Start(); thread1.Join(); thread2.Join(); thread3.Join(); thread4.Join(); thread5.Join(); int64_t elapsed = sprawl::time::Now(sprawl::time::Resolution::Microseconds) - start; total += elapsed; \ if(high == 0 || elapsed > high) high = elapsed; if(low == 0 || elapsed < low) low = elapsed; } printf("\tThreaded string allod/dealloc - %d runs. Best: %" SPRAWL_I64FMT "d us, Worst: %" SPRAWL_I64FMT "d us, Average: %" SPRAWL_I64FMT "d us\n", iterations_threaded, low, high, total / iterations_threaded); } #endif namespace OpaquePointersCallCorrectConstructorsAndDestructors { bool constructed = false; bool destructed = false; } TEST(OpaqueTypeTest, OpaquePointersCallCorrectConstructorsAndDestructors) { struct ConstructDestruct { ConstructDestruct() { OpaquePointersCallCorrectConstructorsAndDestructors::constructed = true; } ~ConstructDestruct() { OpaquePointersCallCorrectConstructorsAndDestructors::destructed = true; } }; { sprawl::memory::OpaqueType<sizeof(ConstructDestruct)> value = sprawl::memory::OpaqueType<sizeof(ConstructDestruct)>(sprawl::memory::CreateAs<ConstructDestruct>()); ASSERT_TRUE(OpaquePointersCallCorrectConstructorsAndDestructors::constructed); ASSERT_FALSE(OpaquePointersCallCorrectConstructorsAndDestructors::destructed); } ASSERT_TRUE(OpaquePointersCallCorrectConstructorsAndDestructors::destructed); } TEST(OpaqueTypeTest, AccessingElementsWorksCorrectly) { struct AccessTest { AccessTest(int i, sprawl::String const& s, bool b, sprawl::String const& s2, double d) : i(i) , s(s) , b(b) , s2(s2) , d(d) { } int i; sprawl::String s; bool b; sprawl::String s2; double d; }; double d = 123485.1235199283758919293875; // Random. sprawl::memory::OpaqueType<sizeof(AccessTest)> value(sprawl::memory::CreateAs<AccessTest>(), 5, "Hello", false, "World", d); ASSERT_EQ(5, value.As<AccessTest>().i); ASSERT_FALSE(value.As<AccessTest>().b); ASSERT_EQ(sprawl::String("Hello"), value.As<AccessTest>().s); ASSERT_EQ(sprawl::String("World"), value.As<AccessTest>().s2); ASSERT_EQ(d, value.As<AccessTest>().d); } TEST(OpaqueTypeTest, ConversionOperatorWorks) { struct AccessTest { AccessTest(int i, sprawl::String const& s, bool b, sprawl::String const& s2, double d) : i(i) , s(s) , b(b) , s2(s2) , d(d) { } int i; sprawl::String s; bool b; sprawl::String s2; double d; }; double d = 123485.1235199283758919293875; // Random. sprawl::memory::OpaqueType<sizeof(AccessTest)> value(sprawl::memory::CreateAs<AccessTest>(), 5, "Hello", false, "World", d); AccessTest& test = value; ASSERT_EQ(5, test.i); ASSERT_FALSE(test.b); ASSERT_EQ(sprawl::String("Hello"), test.s); ASSERT_EQ(sprawl::String("World"), test.s2); ASSERT_EQ(d, test.d); } TEST(OpaqueTypeTest, PolymorphismWorks) { struct AccessTest { AccessTest(int i, sprawl::String const& s, bool b) : i(i) , s(s) , b(b) { } int i; sprawl::String s; bool b; }; struct AddExtraData : public AccessTest { AddExtraData(int i, sprawl::String const& s, bool b, sprawl::String const& s2, double d) : AccessTest(i, s, b) , s2(s2) , d(d) { } sprawl::String s2; double d; }; double d = 123485.1235199283758919293875; // Random. sprawl::memory::OpaqueType<sizeof(AddExtraData)> value(sprawl::memory::CreateAs<AddExtraData>(), 5, "Hello", false, "World", d); AccessTest& test = value.As<AddExtraData>(); ASSERT_EQ(5, test.i); ASSERT_FALSE(test.b); ASSERT_EQ(sprawl::String("Hello"), test.s); } #if (defined(_WIN32) && _MSC_VER < 1900 && !defined(alignof)) # define alignof __alignof # define SPRAWL_DEFINED_ALIGNOF #endif template<typename T, typename U> struct is_same_with_compile_error_if_not { static bool const value = false; typename T::FirstType_IntentionalCompileTimeError t; typename U::SecondType_IntentionalCompileTimeError u; }; template<typename T> struct is_same_with_compile_error_if_not<T, T> { static bool const value = true; }; TEST(OpaqueTypeTest, OpaqueTypeListWorks) { struct ListTest { char c; int i; sprawl::String s; bool b; sprawl::String s2; double d; }; struct ListTest2 { char c; int i; sprawl::String s; bool b; }; struct ListTest3 { char c; int i; sprawl::String s; bool b; sprawl::String s2; double d; char c2; }; struct ListTest4 { char c; int i; sprawl::String s; bool b; sprawl::String s2; }; struct ListTest5 { int i; double d; int i2; double d2; }; struct ListTest6 { double d; int i; double d2; int i2; }; struct JustAChar { char c; }; struct SeveralChars { char c; char c2; char c3; char c4; char c5; char c6; char c7; char c8; char c9; char c10; }; static_assert( is_same_with_compile_error_if_not< sprawl::memory::OpaqueType<sizeof(ListTest), alignof(ListTest)>, sprawl::memory::OpaqueTypeList<char, int, sprawl::String, bool, sprawl::String, double> >::value, "OpaqueTypeList broke." ); static_assert( is_same_with_compile_error_if_not< sprawl::memory::OpaqueType<sizeof(ListTest2), alignof(ListTest2)>, sprawl::memory::OpaqueTypeList<char, int, sprawl::String, bool> >::value, "OpaqueTypeList broke." ); static_assert( is_same_with_compile_error_if_not< sprawl::memory::OpaqueType<sizeof(ListTest3), alignof(ListTest3)>, sprawl::memory::OpaqueTypeList<char, int, sprawl::String, bool, sprawl::String, double, char> >::value, "OpaqueTypeList broke." ); static_assert( is_same_with_compile_error_if_not< sprawl::memory::OpaqueType<sizeof(ListTest4), alignof(ListTest4)>, sprawl::memory::OpaqueTypeList<char, int, sprawl::String, bool, sprawl::String> >::value, "OpaqueTypeList broke." ); static_assert( is_same_with_compile_error_if_not< sprawl::memory::OpaqueType<sizeof(ListTest5), alignof(ListTest5)>, sprawl::memory::OpaqueTypeList<int, double, int, double> >::value, "OpaqueTypeList broke." ); static_assert( is_same_with_compile_error_if_not< sprawl::memory::OpaqueType<sizeof(ListTest6), alignof(ListTest6)>, sprawl::memory::OpaqueTypeList<double, int, double, int> >::value, "OpaqueTypeList broke." ); static_assert( is_same_with_compile_error_if_not< sprawl::memory::OpaqueType<sizeof(JustAChar), alignof(JustAChar)>, sprawl::memory::OpaqueTypeList<char> >::value, "OpaqueTypeList broke." ); static_assert( is_same_with_compile_error_if_not< sprawl::memory::OpaqueType<sizeof(SeveralChars), alignof(SeveralChars)>, sprawl::memory::OpaqueTypeList<char, char, char, char, char, char, char, char, char, char> >::value, "OpaqueTypeList broke." ); } TEST(OpaqueTypeTest, DefaultAlignSafeForSmallerTypes) { struct JustAChar { JustAChar(char c_) : c(c_) {} char c; }; sprawl::memory::OpaqueType<sizeof(char)> t(sprawl::memory::CreateAs<JustAChar>(), 'c'); ASSERT_EQ('c', t.As<JustAChar>().c); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 18645 | brandon_m_bare | Integrated latest version of libsprawl. | ||
#1 | 15089 | brandon_m_bare | First integration of sprawl. | ||
//guest/ShadauxCat/Sprawl/Mainline/UnitTests/UnitTests_Memory.cpp | |||||
#7 | 14761 | ShadauxCat |
First drop of code for sprawl::filesystem and sprawl::path. Library will continue to grow. Also fixed a warning on linux. #review-14762 |
||
#6 | 14216 | ShadauxCat |
-Moved some global sprawl::Strings into local scope in json serialization test because of initialization order issues in the memory allocator on mac. This is a temporary fix, and a real fix will come by making the pool allocator work in explicitly-sized pieces and putting all the code for those pieces into a cpp file. -Fixed a large number of warnings on mac/linux that were exposed by fixes to csbuild -Fixed compile errors on mac due to malloc and alloca not being defined, fixed by #include <stdlib.h> in appropriate places -Fixed mac os x trying to link against pthread erroneously -Provided os x implementation of time library -Fixed compile errors on os x due to std::unordered_map whining about the difference between an allocator that allocates std::pair<key, value> and one that allocates std::pair<key const, value>, which, of course, is that the allocator will be no different at all. -Fixed an actual issue where one unordered_map was allocating only key_type instead of std::pair<key_type, value_type> -Fixed a memory leak where coroutine objects would never be cleaned up because either Yield() or reactivate_() will never return (and thus never clean up their stack memory and thus never release any dynamic memory held in stack objects) depending on the situation - if the function runs to completion, reactivate_() never returns after calling swapcontext(); meanwhile, if the function does not run to completion, Yield() never returns after calling Pause(). This behavior will need to be well-documented because it will affect client-side code as well. Stack memory within a coroutine should not rely on RAII behavior. -Fixed compile failure when creating a StlWrapper with a const value_type #review-14217 |
||
#5 | 14206 | ShadauxCat |
Disabling unit test for MyBigStruct/128 because it causes crashes on 32-bit windows. #review-14207 |
||
#4 | 14146 | ShadauxCat |
Moving a gtest-specific function out of String.hpp #review-14147 |
||
#3 | 14144 | ShadauxCat |
Switching unit tests to gtest. 100 is a decent number of tests to start with, but it needs to be more like 400 to test the current codebase. #review-14145 |
||
#2 | 13650 | ShadauxCat |
- Windows implementations of thread and time libraries - Added coroutines - Added some more unit tests, fixed some unit tests in windows environments - Fixed an issue where multi threading was not properly detected on Linux - Fixed the makefiles to build with threading by default on linux - Changed the pool allocator to use thread-local pools instead of locking mutexes - Fixed output of sprawl::string in the StringBuilder library to take length into account - Added string builder options for StringLiteral - Added thread local implementation #review |
||
#1 | 11496 | ShadauxCat | Initial checkin: Current states for csbuild and libSprawl |