From 0599bd94af33656a9af07f7393a34f88397c2c0a Mon Sep 17 00:00:00 2001 From: louis-langholtz Date: Tue, 8 Aug 2017 21:15:16 -0600 Subject: [PATCH] For issue #35. Fixes the unit test values for __core2__ and __k8__. Adds unit test code specific to the new GetMaxSeparation4x4 function. Updates the benchmark README info. --- Benchmark/README.md | 90 ++++++++++++++++--------- PlayRho/Collision/Manifold.cpp | 5 +- UnitTests/CollideShapes.cpp | 118 +++++++++++++++++++++++++++++++++ UnitTests/World.cpp | 34 +++++++--- 4 files changed, 204 insertions(+), 43 deletions(-) diff --git a/Benchmark/README.md b/Benchmark/README.md index 2f8e7148c6..528d9dba06 100644 --- a/Benchmark/README.md +++ b/Benchmark/README.md @@ -10,39 +10,67 @@ Coming. ## Sample Output -Note that the following times are for running the named benchmarks which may have way more overhead than their names suggests. What's telling however from this output, is that operations like sine and cosine take significantly longer than square root or division. +Note that the following times are for running the named benchmarks which may have way more overhead than their names suggests. What's seemingly significant from this output however, is that operations like sine and cosine take significantly longer than square root or division. ```sh Run on (8 X 2600 MHz CPU s) -2017-07-30 23:55:17 ------------------------------------------------------------------- -Benchmark Time CPU Iterations ------------------------------------------------------------------- -TwoRandValues 13 ns 13 ns 51577916 -FloatAddition 14 ns 14 ns 51504672 -FloatMultiplication 13 ns 13 ns 50828874 -FloatDivision 14 ns 14 ns 51230633 -FloatSqrt 14 ns 14 ns 51709746 -FloatSin 36 ns 36 ns 19214616 -FloatCos 38 ns 38 ns 18015282 -DoubleAddition 14 ns 14 ns 51263649 -DoubleMultiplication 14 ns 14 ns 50961349 -DoubleDivision 17 ns 17 ns 41517402 -DoubleSqrt 17 ns 17 ns 41396113 -DoubleSin 47 ns 47 ns 14996936 -DoubleCos 46 ns 46 ns 15167701 -LengthSquaredViaDotProduct 14 ns 14 ns 51132587 -BM_GetLengthSquared 14 ns 14 ns 51320777 -BM_GetLength 14 ns 14 ns 52137643 -UnitVectorFromVec2 18 ns 18 ns 39641415 -FourRandValues 27 ns 27 ns 26449229 -DotProduct 27 ns 27 ns 26235013 -CrossProduct 27 ns 27 ns 25916999 -ConstructAndAssignVC 31 ns 31 ns 22595296 -SolveVC 41 ns 41 ns 16685299 -GetMaxSeparation 104 ns 103 ns 6795655 -ManifoldForTwoSquares1 175 ns 175 ns 3920075 -ManifoldForTwoSquares2 198 ns 198 ns 3505100 -TilesComesToRest 54129850 ns 54124818 ns 11 +2017-08-08 20:51:19 +-------------------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------------------- +FloatAdd 2 ns 2 ns 368982294 +FloatMult 2 ns 2 ns 366233291 +FloatDiv 2 ns 2 ns 358505544 +FloatSqrt 2 ns 2 ns 382018915 +FloatSin 7 ns 7 ns 113156916 +FloatCos 6 ns 6 ns 110023105 +FloatAtan2 7 ns 7 ns 99072960 +DotProduct 2 ns 2 ns 373072680 +CrossProduct 2 ns 2 ns 363119508 +LengthSquaredViaDotProduct 2 ns 2 ns 351751724 +GetLengthSquared 2 ns 2 ns 379617779 +GetLength 2 ns 2 ns 384497078 +hypot 4 ns 4 ns 175868792 +UnitVectorFromVector 2 ns 2 ns 294130005 +UnitVectorFromVectorAndBack 2 ns 2 ns 297693724 +UnitVecFromAngle 8 ns 8 ns 80838877 +TwoRandValues 13 ns 13 ns 54730686 +FloatAddTwoRand 13 ns 13 ns 54026102 +FloatMultTwoRand 13 ns 13 ns 53356505 +FloatDivTwoRand 13 ns 13 ns 53571702 +FloatSqrtTwoRand 13 ns 13 ns 53826280 +FloatSinTwoRand 36 ns 36 ns 18716828 +FloatCosTwoRand 35 ns 35 ns 20197240 +FloatAtan2TwoRand 28 ns 28 ns 25564146 +DoubleAddTwoRand 14 ns 14 ns 53771288 +DoubleMultTwoRand 14 ns 14 ns 51642604 +DoubleDivTwoRand 18 ns 17 ns 40536706 +DoubleSqrtTwoRand 18 ns 18 ns 38975718 +DoubleSinTwoRand 49 ns 49 ns 14750226 +DoubleCosTwoRand 48 ns 48 ns 14213313 +DoubleAtan2TwoRand 69 ns 69 ns 10425199 +LengthSquaredViaDotProductTwoRand 14 ns 14 ns 50312657 +GetLengthSquaredTwoRand 15 ns 15 ns 48167237 +GetLengthTwoRand 14 ns 14 ns 50834780 +hypotTwoRand 15 ns 15 ns 44679900 +UnitVectorFromVectorTwoRand 17 ns 17 ns 43387444 +UnitVectorFromVectorAndBackTwoRand 17 ns 17 ns 41706884 +FourRandValues 28 ns 28 ns 24096717 +DotProductFourRand 29 ns 29 ns 24427097 +CrossProductFourRand 29 ns 29 ns 24291133 +ConstructAndAssignVC 33 ns 33 ns 20916126 +SolveVC 44 ns 44 ns 15413987 +MaxSepBetweenAbsRectangles 74 ns 74 ns 9816020 +MaxSepBetweenRel4x4 80 ns 80 ns 8796069 +MaxSepBetweenRel2_4x4 82 ns 82 ns 8408913 +MaxSepBetweenRelRectanglesNoStop 104 ns 104 ns 6918432 +MaxSepBetweenRelRectangles2NoStop 103 ns 103 ns 6850119 +MaxSepBetweenRelRectangles 104 ns 104 ns 6884275 +MaxSepBetweenRelRectangles2 100 ns 100 ns 7195058 +ManifoldForTwoSquares1 156 ns 155 ns 4617475 +ManifoldForTwoSquares2 157 ns 157 ns 4675863 +TilesComesToRest12 57637128 ns 57506769 ns 13 +TilesComesToRest20 375657450 ns 375055500 ns 2 +TilesComesToRest36 3974857636 ns 3973611000 ns 1 Program ended with exit code: 0 ``` diff --git a/PlayRho/Collision/Manifold.cpp b/PlayRho/Collision/Manifold.cpp index 5e6a647858..439601af8c 100644 --- a/PlayRho/Collision/Manifold.cpp +++ b/PlayRho/Collision/Manifold.cpp @@ -450,8 +450,9 @@ Manifold playrho::CollideShapes(const DistanceProxy& shapeA, const Transformatio } const auto totalRadius = shapeA.GetVertexRadius() + shapeB.GetVertexRadius(); + const auto do4x4 = (countA == 4) && (countB == 4); - const auto edgeSepA = (countA == 4 && countB ==4)? + const auto edgeSepA = do4x4? ::GetMaxSeparation4x4(shapeA, xfA, shapeB, xfB): ::GetMaxSeparation(shapeA, xfA, shapeB, xfB, totalRadius); if (edgeSepA.separation > totalRadius) @@ -459,7 +460,7 @@ Manifold playrho::CollideShapes(const DistanceProxy& shapeA, const Transformatio return Manifold{}; } - const auto edgeSepB = (countA == 4 && countB ==4)? + const auto edgeSepB = do4x4? ::GetMaxSeparation4x4(shapeB, xfB, shapeA, xfA): ::GetMaxSeparation(shapeB, xfB, shapeA, xfA, totalRadius); if (edgeSepB.separation > totalRadius) diff --git a/UnitTests/CollideShapes.cpp b/UnitTests/CollideShapes.cpp index 63b2e01127..d4867319c3 100644 --- a/UnitTests/CollideShapes.cpp +++ b/UnitTests/CollideShapes.cpp @@ -19,6 +19,7 @@ #include "gtest/gtest.h" #include #include +#include #include #include #include @@ -502,6 +503,123 @@ TEST(CollideShapes, IdenticalHorizontalTouchingSquares) EXPECT_EQ(manifold.GetPoint(1).contactFeature.indexB, 3); } +TEST(CollideShapes, GetMaxSeparationFreeFunction1) +{ + const auto rot0 = Angle{Real{45.0f} * Degree}; + const auto xfm0 = Transformation{Vec2{0, -2} * (Real(1) * Meter), UnitVec2::Get(rot0)}; // bottom + const auto xfm1 = Transformation{Vec2{0, +2} * (Real(1) * Meter), UnitVec2::GetRight()}; // top + + const auto dim = Real(2) * Meter; + const auto shape0 = PolygonShape(dim, dim); + const auto shape1 = PolygonShape(dim, dim); + ASSERT_EQ(shape0.GetVertex(0), Vec2(+2, -2) * (Real(1) * Meter)); // bottom right + ASSERT_EQ(shape0.GetVertex(1), Vec2(+2, +2) * (Real(1) * Meter)); // top right + ASSERT_EQ(shape0.GetVertex(2), Vec2(-2, +2) * (Real(1) * Meter)); // top left + ASSERT_EQ(shape0.GetVertex(3), Vec2(-2, -2) * (Real(1) * Meter)); // bottom left + + // Rotate square A and put it below square B. + // In ASCII art terms: + // + // +---4---+ <----- v1 of shape1 + // | | | + // | B 3 | + // | | | + // | 2 | + // | | | + // | 1 | + // | /|\ | + // v3 ---> 2-1-0-1-2 <----- v0 of shape1 + // / | \ + // / 1 \ + // / A | \ + // + 2 + <----- v0 of shape0 + // \ | / + // \ 3 / + // \ | / + // \ 4 / + // \|/ + // + <----- v3 of shape0 + + const auto child0 = shape0.GetChild(0); + const auto child1 = shape1.GetChild(0); + const auto totalRadius = shape0.GetVertexRadius() + shape1.GetVertexRadius(); + + const auto maxSep01_4x4 = GetMaxSeparation4x4(child0, xfm0, child1, xfm1); + const auto maxSep10_4x4 = GetMaxSeparation4x4(child1, xfm1, child0, xfm0); + const auto maxSep01_NxN = GetMaxSeparation(child0, xfm0, child1, xfm1, totalRadius); + const auto maxSep10_NxN = GetMaxSeparation(child1, xfm1, child0, xfm0, totalRadius); + + switch (sizeof(Real)) + { + case 4: + EXPECT_EQ(maxSep01_4x4.index1, decltype(maxSep01_4x4.index1){0}); // v0 of shape0 + EXPECT_EQ(maxSep01_4x4.index2, decltype(maxSep01_4x4.index1){3}); // v3 of shape1 + break; + case 8: + EXPECT_EQ(maxSep01_4x4.index1, decltype(maxSep01_4x4.index1){1}); // v1 of shape0 + EXPECT_EQ(maxSep01_4x4.index2, decltype(maxSep01_4x4.index1){0}); // v0 of shape1 + break; + } + EXPECT_EQ(maxSep01_4x4.index1, maxSep01_NxN.index1); + EXPECT_EQ(maxSep01_4x4.index2, maxSep01_NxN.index2); + EXPECT_NEAR(static_cast(Real(maxSep01_4x4.separation / Meter)), + -2.0, std::abs(-2.0) / 1000000.0); + EXPECT_NEAR(static_cast(Real(maxSep01_4x4.separation / Meter)), + static_cast(Real(maxSep01_NxN.separation / Meter)), + std::abs(static_cast(Real(maxSep01_4x4.separation / Meter)) / 1000000.0)); + + EXPECT_EQ(maxSep10_4x4.index1, decltype(maxSep10_4x4.index1){3}); // v3 of shape1 + EXPECT_EQ(maxSep10_4x4.index2, decltype(maxSep10_4x4.index1){1}); // v1 of shape0 + EXPECT_EQ(maxSep10_4x4.index1, maxSep10_NxN.index1); + EXPECT_EQ(maxSep10_4x4.index2, maxSep10_NxN.index2); + EXPECT_NEAR(static_cast(Real(maxSep10_4x4.separation / Meter)), + -0.82842707633972168, std::abs(-0.82842707633972168) / 1000000.0); + EXPECT_NEAR(static_cast(Real(maxSep10_4x4.separation / Meter)), + static_cast(Real(maxSep10_NxN.separation / Meter)), + std::abs(static_cast(Real(maxSep10_4x4.separation / Meter)) / 1000000.0)); +} + +TEST(CollideShapes, GetMaxSeparationFreeFunction2) +{ + const auto dim = Real(2) * Meter; + const auto shape = PolygonShape(dim, dim); + ASSERT_EQ(shape.GetVertex(0), Vec2(+2, -2) * (Real(1) * Meter)); // bottom right + ASSERT_EQ(shape.GetVertex(1), Vec2(+2, +2) * (Real(1) * Meter)); // top right + ASSERT_EQ(shape.GetVertex(2), Vec2(-2, +2) * (Real(1) * Meter)); // top left + ASSERT_EQ(shape.GetVertex(3), Vec2(-2, -2) * (Real(1) * Meter)); // bottom left + + const auto xfm0 = Transformation{Vec2{0, -1} * (Real(1) * Meter), UnitVec2::GetRight()}; // bottom + const auto xfm1 = Transformation{Vec2{0, +1} * (Real(1) * Meter), UnitVec2::GetRight()}; // top + const auto totalRadius = shape.GetVertexRadius() * Real(2); + + const auto child0 = shape.GetChild(0); + const auto maxSep01_4x4 = GetMaxSeparation4x4(child0, xfm0, child0, xfm1); + const auto maxSep10_4x4 = GetMaxSeparation4x4(child0, xfm1, child0, xfm0); + const auto maxSep01_NxN = GetMaxSeparation(child0, xfm0, child0, xfm1, totalRadius); + const auto maxSep10_NxN = GetMaxSeparation(child0, xfm1, child0, xfm0, totalRadius); + + + EXPECT_EQ(maxSep01_4x4.index1, decltype(maxSep01_4x4.index1){1}); // v0 of shape0 + EXPECT_EQ(maxSep01_4x4.index1, maxSep01_NxN.index1); + EXPECT_EQ(maxSep01_4x4.index2, decltype(maxSep01_4x4.index1){0}); // v3 of shape1 + EXPECT_EQ(maxSep01_4x4.index2, maxSep01_NxN.index2); + EXPECT_NEAR(static_cast(Real(maxSep01_4x4.separation / Meter)), + -2.0, 0.0); + EXPECT_NEAR(static_cast(Real(maxSep01_4x4.separation / Meter)), + static_cast(Real(maxSep01_NxN.separation / Meter)), + std::abs(static_cast(Real(maxSep01_4x4.separation / Meter)) / 1000000.0)); + + EXPECT_EQ(maxSep10_4x4.index1, decltype(maxSep10_4x4.index1){3}); // v3 of shape1 + EXPECT_EQ(maxSep10_4x4.index1, maxSep10_NxN.index1); + EXPECT_EQ(maxSep10_4x4.index2, decltype(maxSep10_4x4.index1){1}); // v1 of shape0 + EXPECT_EQ(maxSep10_4x4.index2, maxSep10_NxN.index2); + EXPECT_NEAR(static_cast(Real(maxSep10_4x4.separation / Meter)), + -2.0, 0.0); + EXPECT_NEAR(static_cast(Real(maxSep10_4x4.separation / Meter)), + static_cast(Real(maxSep10_NxN.separation / Meter)), + std::abs(static_cast(Real(maxSep10_4x4.separation / Meter)) / 1000000.0)); +} + TEST(CollideShapes, SquareCornerTouchingSquareFaceAbove) { const auto dim = Real(2) * Meter; diff --git a/UnitTests/World.cpp b/UnitTests/World.cpp index b10b83c203..4ed4c78947 100644 --- a/UnitTests/World.cpp +++ b/UnitTests/World.cpp @@ -2001,12 +2001,19 @@ TEST(World, TilesComesToRest) { case 4: { + // From commit ee74290c17422ccbd6a73f07d6fd9abe960da84a onward: + EXPECT_EQ(numSteps, 1802ul); + EXPECT_EQ(sumRegPosIters, 36524ul); + EXPECT_EQ(sumRegVelIters, 46981ul); + EXPECT_EQ(sumToiPosIters, 44084ul); + EXPECT_EQ(sumToiVelIters, 114366ul); + // From commit 6b16f3722d5daac80ebaefd1dfda424939498dd4 onward: - EXPECT_EQ(numSteps, 1801ul); - EXPECT_EQ(sumRegPosIters, 36523ul); - EXPECT_EQ(sumRegVelIters, 46973ul); - EXPECT_EQ(sumToiPosIters, 44044ul); - EXPECT_EQ(sumToiVelIters, 114344ul); + //EXPECT_EQ(numSteps, 1801ul); + //EXPECT_EQ(sumRegPosIters, 36523ul); + //EXPECT_EQ(sumRegVelIters, 46973ul); + //EXPECT_EQ(sumToiPosIters, 44044ul); + //EXPECT_EQ(sumToiVelIters, 114344ul); // From commit 04f9188c47961cafe76c55eb6b766a608593ee08 onward. //EXPECT_EQ(numSteps, 1856ul); @@ -2067,12 +2074,19 @@ TEST(World, TilesComesToRest) { case 4: { - // From commit 6b16f3722d5daac80ebaefd1dfda424939498dd4 onward: + // From commit ee74290c17422ccbd6a73f07d6fd9abe960da84a onward: EXPECT_EQ(numSteps, 1803ul); - EXPECT_EQ(sumRegPosIters, 36528ul); - EXPECT_EQ(sumRegVelIters, 46988ul); - EXPECT_EQ(sumToiPosIters, 44178ul); - EXPECT_EQ(sumToiVelIters, 114936ul); + EXPECT_EQ(sumRegPosIters, 36673ul); + EXPECT_EQ(sumRegVelIters, 48148ul); + EXPECT_EQ(sumToiPosIters, 43959ul); + EXPECT_EQ(sumToiVelIters, 113189ul); + + // From commit 6b16f3722d5daac80ebaefd1dfda424939498dd4 onward: + //EXPECT_EQ(numSteps, 1803ul); + //EXPECT_EQ(sumRegPosIters, 36528ul); + //EXPECT_EQ(sumRegVelIters, 46988ul); + //EXPECT_EQ(sumToiPosIters, 44178ul); + //EXPECT_EQ(sumToiVelIters, 114936ul); // From commit 04f9188c47961cafe76c55eb6b766a608593ee08 onward. //EXPECT_EQ(numSteps, 1855ul);