From b2a55b40c16f193aabcc159e2eb9e6781168c715 Mon Sep 17 00:00:00 2001 From: Erin Catto Date: Thu, 26 Dec 2024 17:05:54 -0800 Subject: [PATCH] benchmark step time --- benchmark/main.c | 46 ++++++++++++++++++- include/box2d/math_functions.h | 2 +- samples/sample_benchmark.cpp | 2 +- samples/sample_collision.cpp | 82 +++++++++------------------------- shared/benchmarks.c | 13 +++--- src/body.c | 2 +- src/broad_phase.c | 26 ++++++++--- src/constants.h | 4 ++ src/core.h | 7 ++- src/distance.c | 26 +++++------ src/joint.c | 16 +++---- src/shape.c | 4 +- src/solver.c | 27 +++++++++++ src/table.c | 15 ++++--- src/timer.c | 24 ++++++++++ src/world.c | 2 +- test/test_table.c | 13 +++--- 17 files changed, 198 insertions(+), 113 deletions(-) diff --git a/benchmark/main.c b/benchmark/main.c index 88cb0732e..bc8665c7a 100644 --- a/benchmark/main.c +++ b/benchmark/main.c @@ -120,6 +120,8 @@ static void FinishTask( void* userTask, void* userContext ) // Examples: // start /affinity 0x5555 .\build\bin\Release\benchmark.exe -t=4 -w=4 // start /affinity 0x5555 .\build\bin\Release\benchmark.exe -t=8 +// start /affinity 0x5555 .\build\bin\Release\benchmark.exe -t=4 -w=4 -b=3 -r=1 -nc -s + int main( int argc, char** argv ) { Benchmark benchmarks[] = { @@ -134,12 +136,21 @@ int main( int argc, char** argv ) int benchmarkCount = ARRAY_COUNT( benchmarks ); + int maxSteps = benchmarks[0].totalStepCount; + for (int i = 1; i < benchmarkCount; ++i) + { + maxSteps = b2MaxInt( maxSteps, benchmarks[i].totalStepCount ); + } + + float* stepTimes = malloc( maxSteps * sizeof( float ) ); + int maxThreadCount = GetNumberOfCores(); int runCount = 4; int singleBenchmark = -1; int singleWorkerCount = -1; b2Counters counters = { 0 }; bool enableContinuous = true; + bool recordStepTimes = false; assert( maxThreadCount <= THREAD_LIMIT ); @@ -168,13 +179,18 @@ int main( int argc, char** argv ) { enableContinuous = false; } + else if ( strncmp( arg, "-s", 3 ) == 0 ) + { + recordStepTimes = true; + } else if ( strcmp( arg, "-h" ) == 0 ) { printf( "Usage\n" "-t=: the maximum number of threads to use\n" "-b=: run a single benchmark\n" "-w=: run a single worker count\n" - "-r=: number of repeats (default is 4)\n" ); + "-r=: number of repeats (default is 4)\n" + "-s: record step times\n" ); exit( 0 ); } } @@ -246,7 +262,13 @@ int main( int argc, char** argv ) { benchmark->stepFcn( worldId, 0 ); } + + assert( stepCount <= maxSteps ); + + b2Timer stepTimer = b2CreateTimer(); b2World_Step( worldId, timeStep, subStepCount ); + stepTimes[0] = b2GetMillisecondsAndReset( &stepTimer ); + taskCount = 0; b2Timer timer = b2CreateTimer(); @@ -259,6 +281,8 @@ int main( int argc, char** argv ) } b2World_Step( worldId, timeStep, subStepCount ); taskCount = 0; + + stepTimes[step] = b2GetMillisecondsAndReset( &stepTimer ); } float ms = b2GetMilliseconds( &timer ); @@ -284,6 +308,24 @@ int main( int argc, char** argv ) enkiDeleteTaskScheduler( scheduler ); scheduler = NULL; + + if (recordStepTimes && runIndex == 0) + { + char fileName[64] = { 0 }; + snprintf( fileName, 64, "%s_t%d.dat", benchmarks[benchmarkIndex].name, threadCount ); + FILE* file = fopen( fileName, "w" ); + if ( file == NULL ) + { + continue; + } + + for ( int stepIndex = 0; stepIndex < stepCount; ++stepIndex) + { + fprintf( file, "%g\n", stepTimes[stepIndex] ); + } + + fclose( file ); + } } } @@ -310,5 +352,7 @@ int main( int argc, char** argv ) printf( "======================================\n" ); printf( "All Box2D benchmarks complete!\n" ); + free( stepTimes ); + return 0; } diff --git a/include/box2d/math_functions.h b/include/box2d/math_functions.h index 977736f64..4c6258156 100644 --- a/include/box2d/math_functions.h +++ b/include/box2d/math_functions.h @@ -307,7 +307,7 @@ B2_INLINE b2Rot b2NormalizeRot( b2Rot q ) return qn; } -/// Integration rotation from angular velocity +/// Integrate rotation from angular velocity /// @param q1 initial rotation /// @param deltaAngle the angular displacement in radians B2_INLINE b2Rot b2IntegrateRotation( b2Rot q1, float deltaAngle ) diff --git a/samples/sample_benchmark.cpp b/samples/sample_benchmark.cpp index fc421bb5a..71f0212ec 100644 --- a/samples/sample_benchmark.cpp +++ b/samples/sample_benchmark.cpp @@ -1521,7 +1521,7 @@ class BenchmarkRain : public Sample Sample::Step( settings ); - if (m_stepCount == 1000) + if (m_stepCount % 1000 == 0) { m_stepCount += 0; } diff --git a/samples/sample_collision.cpp b/samples/sample_collision.cpp index f3008fb89..990b3b289 100644 --- a/samples/sample_collision.cpp +++ b/samples/sample_collision.cpp @@ -1475,15 +1475,15 @@ class RayCastWorld : public Sample bodyDef.rotation = b2MakeRot( RandomFloatRange( -B2_PI, B2_PI ) ); int mod = m_bodyIndex % 3; - if (mod == 0) + if ( mod == 0 ) { bodyDef.type = b2_staticBody; } - else if (mod == 1) + else if ( mod == 1 ) { bodyDef.type = b2_kinematicBody; } - else if (mod == 2) + else if ( mod == 2 ) { bodyDef.type = b2_dynamicBody; bodyDef.gravityScale = 0.0f; @@ -3417,7 +3417,7 @@ class TimeOfImpact : public Sample if ( settings.restart == false ) { g_camera.m_center = { 0.6f, 2.0f }; - g_camera.m_center = { -123.750000f, 134.750000f }; + g_camera.m_center = { -16, 45 }; g_camera.m_zoom = 5.0f; } } @@ -3427,47 +3427,6 @@ class TimeOfImpact : public Sample return new TimeOfImpact( settings ); } -#if 0 -- input 0x00000044f14fd550 {proxyA={points=0x00000044f14fd550 {{...}, {...}, {...}, {...}, {...}, {...}, {...}, ...} ...} ...} const b2TOIInput * -- proxyA {points=0x00000044f14fd550 {{x=-123.750000 y=134.750000 }, {x=-123.250000 y=134.750000 }, {x=-123.250000 ...}, ...} ...} b2ShapeProxy -- points 0x00000044f14fd550 {{x=-123.750000 y=134.750000 }, {x=-123.250000 y=134.750000 }, {x=-123.250000 y=135.250000 }, ...} b2Vec2[8] -+ [0] {x=-123.750000 y=134.750000 } b2Vec2 -+ [1] {x=-123.250000 y=134.750000 } b2Vec2 -+ [2] {x=-123.250000 y=135.250000 } b2Vec2 -+ [3] {x=-123.750000 y=135.250000 } b2Vec2 -+ [4] {x=-123.905960 y=135.246246 } b2Vec2 -+ [5] {x=-123.583496 y=135.491089 } b2Vec2 -+ [6] {x=-1.02951760e+30 y=9.529e-44#DEN } b2Vec2 -+ [7] {x=8.40272566e-18 y=7.539e-43#DEN } b2Vec2 - count 4 int - radius 0.00000000 float -- proxyB {points=0x00000044f14fd598 {{x=0.00000000 y=-0.125000000 }, {x=0.00000000 y=0.125000000 }, {x=-123.250000 ...}, ...} ...} b2ShapeProxy -- points 0x00000044f14fd598 {{x=0.00000000 y=-0.125000000 }, {x=0.00000000 y=0.125000000 }, {x=-123.250000 y=...}, ...} b2Vec2[8] -+ [0] {x=0.00000000 y=-0.125000000 } b2Vec2 -+ [1] {x=0.00000000 y=0.125000000 } b2Vec2 -+ [2] {x=-123.250000 y=135.250000 } b2Vec2 -+ [3] {x=-123.750000 y=135.250000 } b2Vec2 -+ [4] {x=-123.905960 y=135.246246 } b2Vec2 -+ [5] {x=-123.583496 y=135.491089 } b2Vec2 -+ [6] {x=-1.02951760e+30 y=9.529e-44#DEN } b2Vec2 -+ [7] {x=8.40272566e-18 y=7.539e-43#DEN } b2Vec2 - count 2 int - radius 0.0350000001 float -- sweepA {localCenter={x=0.00000000 y=0.00000000 } c1={x=0.00000000 y=0.00000000 } c2={x=0.00000000 y=0.00000000 } ...} b2Sweep -+ localCenter {x=0.00000000 y=0.00000000 } b2Vec2 -+ c1 {x=0.00000000 y=0.00000000 } b2Vec2 -+ c2 {x=0.00000000 y=0.00000000 } b2Vec2 -+ q1 {c=1.00000000 s=0.00000000 } b2Rot -+ q2 {c=1.00000000 s=0.00000000 } b2Rot -- sweepB {localCenter={x=0.00000000 y=0.00000000 } c1={x=-123.721443 y=135.385178 } c2={x=-123.757744 y=135.334244 } ...} b2Sweep -+ localCenter {x=0.00000000 y=0.00000000 } b2Vec2 -+ c1 {x=-123.721443 y=135.385178 } b2Vec2 -+ c2 {x=-123.757744 y=135.334244 } b2Vec2 -+ q1 {c=0.567239463 s=0.823552966 } b2Rot -+ q2 {c=0.423919678 s=0.905699849 } b2Rot - tMax 1.00000000 float - -#endif void Step( Settings& settings ) override { Sample::Step( settings ); @@ -3475,11 +3434,13 @@ class TimeOfImpact : public Sample b2Sweep sweepA = { b2Vec2_zero, { 0.0f, 0.0f }, { 0.0f, 0.0f }, b2Rot_identity, b2Rot_identity, }; - b2Sweep sweepB = { b2Vec2_zero, - { -123.721443f, 135.385178f }, - { -123.757744f, 135.334244f }, - { 0.567239463f, 0.823552966f }, - { 0.423919678f, 0.905699849f } }; + b2Sweep sweepB = { + b2Vec2_zero, + { -15.8332710, 45.3520279 }, + { -15.8324337, 45.3413048 }, + { -0.540891349, 0.841092527 }, + { -0.457797021, 0.889056742 }, + }; b2TOIInput input; input.proxyA = b2MakeProxy( m_verticesA, m_countA, m_radiusA ); @@ -3535,15 +3496,15 @@ class TimeOfImpact : public Sample if ( output.state == b2_toiStateHit ) { - b2DistanceInput dinput; - dinput.proxyA = input.proxyA; - dinput.proxyB = input.proxyB; - dinput.transformA = b2GetSweepTransform( &sweepA, output.fraction ); - dinput.transformB = b2GetSweepTransform( &sweepB, output.fraction ); - dinput.useRadii = false; + b2DistanceInput distanceInput; + distanceInput.proxyA = input.proxyA; + distanceInput.proxyB = input.proxyB; + distanceInput.transformA = b2GetSweepTransform( &sweepA, output.fraction ); + distanceInput.transformB = b2GetSweepTransform( &sweepB, output.fraction ); + distanceInput.useRadii = false; b2SimplexCache cache = { 0 }; - b2DistanceOutput doutput = b2ShapeDistance( &cache, &dinput, nullptr, 0 ); - g_draw.DrawString( 5, m_textLine, "distance = %g", doutput.distance ); + b2DistanceOutput distanceOutput = b2ShapeDistance( &cache, &distanceInput, nullptr, 0 ); + g_draw.DrawString( 5, m_textLine, "distance = %g", distanceOutput.distance ); m_textLine += m_textIncrement; } @@ -3560,15 +3521,14 @@ class TimeOfImpact : public Sample #endif } - b2Vec2 m_verticesA[4] = { - { -123.750000, 134.750000 }, { -123.250000, 134.750000 }, { -123.250000, 135.250000 }, { -123.750000, 135.250000 } }; + b2Vec2 m_verticesA[4] = { { -16.25, 44.75 }, { -15.75, 44.75 }, { -15.75, 45.25 }, { -16.25, 45.25 } }; b2Vec2 m_verticesB[2] = { { 0.0f, -0.125000000f }, { 0.0f, 0.125000000f } }; int m_countA = ARRAY_COUNT( m_verticesA ); int m_countB = ARRAY_COUNT( m_verticesB ); float m_radiusA = 0.0f; - float m_radiusB = 0.0350000001f; + float m_radiusB = 0.0299999993f; }; static int sampleTimeOfImpact = RegisterSample( "Collision", "Time of Impact", TimeOfImpact::Create ); diff --git a/shared/benchmarks.c b/shared/benchmarks.c index b6645d841..40a2b4ab8 100644 --- a/shared/benchmarks.c +++ b/shared/benchmarks.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MIT #include "benchmarks.h" + #include "human.h" #include "box2d/box2d.h" @@ -18,8 +19,6 @@ void CreateJointGrid( b2WorldId worldId ) { - // Turning gravity off to isolate joint performance. - //b2World_SetGravity( worldId, b2Vec2_zero ); b2World_EnableSleeping( worldId, false ); int N = BENCHMARK_DEBUG ? 10 : 100; @@ -238,16 +237,20 @@ void CreateRain( b2WorldId worldId ) b2ShapeDef shapeDef = b2DefaultShapeDef(); float y = 0.0f; - float w = 0.5f * g_rainData.gridSize; - float h = 0.5f * g_rainData.gridSize; + float width = g_rainData.gridSize; + float height = g_rainData.gridSize; for ( int i = 0; i < RAIN_ROW_COUNT; ++i ) { float x = -0.5f * g_rainData.gridCount * g_rainData.gridSize; for ( int j = 0; j <= g_rainData.gridCount; ++j ) { - b2Polygon box = b2MakeOffsetBox( w, h, ( b2Vec2 ){ x, y }, b2Rot_identity ); + b2Polygon box = b2MakeOffsetBox( 0.5f * width, 0.5f * height, ( b2Vec2 ){ x, y }, b2Rot_identity ); b2CreatePolygonShape( groundId, &shapeDef, &box ); + + //b2Segment segment = { { x - 0.5f * width, y }, { x + 0.5f * width, y } }; + //b2CreateSegmentShape( groundId, &shapeDef, &segment ); + x += g_rainData.gridSize; } diff --git a/src/body.c b/src/body.c index cec6fd3d0..7893530df 100644 --- a/src/body.c +++ b/src/body.c @@ -167,7 +167,7 @@ static void b2DestroyBodyContacts( b2World* world, b2Body* body, bool wakeBodies b2BodyId b2CreateBody( b2WorldId worldId, const b2BodyDef* def ) { - b2CheckDef( def ); + B2_CHECK_DEF( def ); B2_ASSERT( b2IsValidVec2( def->position ) ); B2_ASSERT( b2IsValidRotation( def->rotation ) ); B2_ASSERT( b2IsValidVec2( def->linearVelocity ) ); diff --git a/src/broad_phase.c b/src/broad_phase.c index 9a4e72658..2cfe3cb94 100644 --- a/src/broad_phase.c +++ b/src/broad_phase.c @@ -302,6 +302,13 @@ static bool b2PairQueryCallback( int proxyId, int shapeId, void* context ) return true; } +// Warning: writing to these globals significantly slows multithreading performance +#if B2_SNOOP_PAIR_COUNTERS +b2TreeStats b2_dynamicStats; +b2TreeStats b2_kinematicStats; +b2TreeStats b2_staticStats; +#endif + static void b2FindPairsTask( int startIndex, int endIndex, uint32_t threadIndex, void* context ) { b2TracyCZoneNC( pair_task, "Pair Task", b2_colorAquamarine, true ); @@ -341,20 +348,27 @@ static void b2FindPairsTask( int startIndex, int endIndex, uint32_t threadIndex, // Query trees. Only dynamic proxies collide with kinematic and static proxies. // Using B2_DEFAULT_MASK_BITS so that b2Filter::groupIndex works. + b2TreeStats stats = { 0 }; if ( proxyType == b2_dynamicBody ) { // consider using bits = groupIndex > 0 ? B2_DEFAULT_MASK_BITS : maskBits queryContext.queryTreeType = b2_kinematicBody; - b2DynamicTree_Query( bp->trees + b2_kinematicBody, fatAABB, B2_DEFAULT_MASK_BITS, b2PairQueryCallback, &queryContext ); + b2TreeStats statsKinematic = b2DynamicTree_Query( bp->trees + b2_kinematicBody, fatAABB, B2_DEFAULT_MASK_BITS, b2PairQueryCallback, &queryContext ); + stats.nodeVisits += statsKinematic.nodeVisits; + stats.leafVisits += statsKinematic.leafVisits; queryContext.queryTreeType = b2_staticBody; - b2DynamicTree_Query( bp->trees + b2_staticBody, fatAABB, B2_DEFAULT_MASK_BITS, b2PairQueryCallback, &queryContext ); + b2TreeStats statsStatic = b2DynamicTree_Query( bp->trees + b2_staticBody, fatAABB, B2_DEFAULT_MASK_BITS, b2PairQueryCallback, &queryContext ); + stats.nodeVisits += statsStatic.nodeVisits; + stats.leafVisits += statsStatic.leafVisits; } // All proxies collide with dynamic proxies // Using B2_DEFAULT_MASK_BITS so that b2Filter::groupIndex works. queryContext.queryTreeType = b2_dynamicBody; - b2DynamicTree_Query( bp->trees + b2_dynamicBody, fatAABB, B2_DEFAULT_MASK_BITS, b2PairQueryCallback, &queryContext ); + b2TreeStats statsDynamic = b2DynamicTree_Query( bp->trees + b2_dynamicBody, fatAABB, B2_DEFAULT_MASK_BITS, b2PairQueryCallback, &queryContext ); + stats.nodeVisits += statsDynamic.nodeVisits; + stats.leafVisits += statsDynamic.leafVisits; } b2TracyCZoneEnd( pair_task ); @@ -382,9 +396,9 @@ void b2UpdateBroadPhasePairs( b2World* world ) bp->movePairs = b2AllocateArenaItem( alloc, bp->movePairCapacity * sizeof( b2MovePair ), "move pairs" ); bp->movePairIndex = 0; -#ifndef NDEBUG - extern _Atomic int g_probeCount; - g_probeCount = 0; +#if B2_SNOOP_TABLE_COUNTERS + extern _Atomic int b2_probeCount; + b2_probeCount = 0; #endif int minRange = 64; diff --git a/src/constants.h b/src/constants.h index f875dd0d3..1aaf6d20e 100644 --- a/src/constants.h +++ b/src/constants.h @@ -18,6 +18,7 @@ extern float b2_lengthUnitsPerMeter; // A small length used as a collision and constraint tolerance. Usually it is // chosen to be numerically significant, but visually insignificant. In meters. +// Normally this is 0.5cm. // @warning modifying this can have a significant impact on stability #define B2_LINEAR_SLOP ( 0.005f * b2_lengthUnitsPerMeter ) @@ -29,11 +30,14 @@ extern float b2_lengthUnitsPerMeter; // @warning increasing this to 0.5f * b2_pi or greater will break continuous collision. #define B2_MAX_ROTATION ( 0.25f * B2_PI ) +// Box2D uses limited speculative collision. This reduces jitter. +// Normally this is 2cm. // @warning modifying this can have a significant impact on performance and stability #define B2_SPECULATIVE_DISTANCE ( 4.0f * B2_LINEAR_SLOP ) // This is used to fatten AABBs in the dynamic tree. This allows proxies // to move by a small amount without triggering a tree adjustment. This is in meters. +// Normally this is 5cm. // @warning modifying this can have a significant impact on performance #define B2_AABB_MARGIN ( 0.05f * b2_lengthUnitsPerMeter ) diff --git a/src/core.h b/src/core.h index 38bc81738..b0518a871 100644 --- a/src/core.h +++ b/src/core.h @@ -114,7 +114,12 @@ // Use to validate definitions. Do not take my cookie. #define B2_SECRET_COOKIE 1152023 -#define b2CheckDef( DEF ) B2_ASSERT( DEF->internalValue == B2_SECRET_COOKIE ) +// Snoop counters. These should be disabled in optimized builds because they are expensive. +#define B2_SNOOP_TABLE_COUNTERS B2_DEBUG +#define B2_SNOOP_PAIR_COUNTERS B2_DEBUG +#define B2_SNOOP_TOI_COUNTERS B2_DEBUG + +#define B2_CHECK_DEF( DEF ) B2_ASSERT( DEF->internalValue == B2_SECRET_COOKIE ) void* b2Alloc( int size ); void b2Free( void* mem, int size ); diff --git a/src/distance.c b/src/distance.c index 889d5aa11..7542985bd 100644 --- a/src/distance.c +++ b/src/distance.c @@ -776,10 +776,8 @@ b2CastOutput b2ShapeCast( const b2ShapeCastPairInput* input ) return output; } -#define B2_TOI_DEBUG 0 - // Warning: writing to these globals significantly slows multithreading performance -#if B2_TOI_DEBUG +#if B2_SNOOP_TOI_COUNTERS float b2_toiTime, b2_toiMaxTime; int b2_toiCalls, b2_toiDistanceIterations, b2_toiMaxDistanceIterations; int b2_toiRootIterations, b2_toiMaxRootIterations; @@ -1003,7 +1001,7 @@ static float b2EvaluateSeparation( const b2SeparationFunction* f, int indexA, in // by computing the largest time at which separation is maintained. b2TOIOutput b2TimeOfImpact( const b2TOIInput* input ) { -#if B2_TOI_DEBUG +#if B2_SNOOP_TOI_COUNTERS b2Timer timer = b2CreateTimer(); ++b2_toiCalls; #endif @@ -1058,7 +1056,7 @@ b2TOIOutput b2TimeOfImpact( const b2TOIInput* input ) b2DistanceOutput distanceOutput = b2ShapeDistance( &cache, &distanceInput, NULL, 0 ); distanceIterations += 1; -#if B2_TOI_DEBUG +#if B2_SNOOP_TOI_COUNTERS b2_toiDistanceIterations += 1; #endif @@ -1067,7 +1065,7 @@ b2TOIOutput b2TimeOfImpact( const b2TOIInput* input ) { // Failure! output.state = b2_toiStateOverlapped; -#if B2_TOI_DEBUG +#if B2_SNOOP_TOI_COUNTERS b2_toiOverlappedCount += 1; #endif output.fraction = 0.0f; @@ -1078,7 +1076,7 @@ b2TOIOutput b2TimeOfImpact( const b2TOIInput* input ) { // Victory! output.state = b2_toiStateHit; -#if B2_TOI_DEBUG +#if B2_SNOOP_TOI_COUNTERS b2_toiHitCount += 1; #endif output.fraction = t1; @@ -1129,7 +1127,7 @@ b2TOIOutput b2TimeOfImpact( const b2TOIInput* input ) { // Victory! output.state = b2_toiStateSeparated; -#if B2_TOI_DEBUG +#if B2_SNOOP_TOI_COUNTERS b2_toiSeparatedCount += 1; #endif output.fraction = tMax; @@ -1153,7 +1151,7 @@ b2TOIOutput b2TimeOfImpact( const b2TOIInput* input ) if ( s1 < target - tolerance ) { output.state = b2_toiStateFailed; -#if B2_TOI_DEBUG +#if B2_SNOOP_TOI_COUNTERS b2_toiFailedCount += 1; #endif output.fraction = t1; @@ -1166,7 +1164,7 @@ b2TOIOutput b2TimeOfImpact( const b2TOIInput* input ) { // Victory! t1 should hold the TOI (could be 0.0). output.state = b2_toiStateHit; -#if B2_TOI_DEBUG +#if B2_SNOOP_TOI_COUNTERS b2_toiHitCount += 1; #endif output.fraction = t1; @@ -1194,7 +1192,7 @@ b2TOIOutput b2TimeOfImpact( const b2TOIInput* input ) rootIterationCount += 1; -#if B2_TOI_DEBUG +#if B2_SNOOP_TOI_COUNTERS ++b2_toiRootIterations; #endif @@ -1225,7 +1223,7 @@ b2TOIOutput b2TimeOfImpact( const b2TOIInput* input ) } } -#if B2_TOI_DEBUG +#if B2_SNOOP_TOI_COUNTERS b2_toiMaxRootIterations = b2MaxInt( b2_toiMaxRootIterations, rootIterationCount ); #endif @@ -1246,7 +1244,7 @@ b2TOIOutput b2TimeOfImpact( const b2TOIInput* input ) { // Root finder got stuck. Semi-victory. output.state = b2_toiStateFailed; -#if B2_TOI_DEBUG +#if B2_SNOOP_TOI_COUNTERS b2_toiFailedCount += 1; #endif output.fraction = t1; @@ -1254,7 +1252,7 @@ b2TOIOutput b2TimeOfImpact( const b2TOIInput* input ) } } -#if B2_TOI_DEBUG +#if B2_SNOOP_TOI_COUNTERS b2_toiMaxDistanceIterations = b2MaxInt( b2_toiMaxDistanceIterations, distanceIterations ); float time = b2GetMilliseconds( &timer ); diff --git a/src/joint.c b/src/joint.c index a7f8e21d5..7afdda5cb 100644 --- a/src/joint.c +++ b/src/joint.c @@ -344,7 +344,7 @@ static void b2DestroyContactsBetweenBodies( b2World* world, b2Body* bodyA, b2Bod b2JointId b2CreateDistanceJoint( b2WorldId worldId, const b2DistanceJointDef* def ) { - b2CheckDef( def ); + B2_CHECK_DEF( def ); b2World* world = b2GetWorldFromId( worldId ); B2_ASSERT( world->locked == false ); @@ -397,7 +397,7 @@ b2JointId b2CreateDistanceJoint( b2WorldId worldId, const b2DistanceJointDef* de b2JointId b2CreateMotorJoint( b2WorldId worldId, const b2MotorJointDef* def ) { - b2CheckDef( def ); + B2_CHECK_DEF( def ); b2World* world = b2GetWorldFromId( worldId ); B2_ASSERT( world->locked == false ); @@ -435,7 +435,7 @@ b2JointId b2CreateMotorJoint( b2WorldId worldId, const b2MotorJointDef* def ) b2JointId b2CreateMouseJoint( b2WorldId worldId, const b2MouseJointDef* def ) { - b2CheckDef( def ); + B2_CHECK_DEF( def ); b2World* world = b2GetWorldFromId( worldId ); B2_ASSERT( world->locked == false ); @@ -471,7 +471,7 @@ b2JointId b2CreateMouseJoint( b2WorldId worldId, const b2MouseJointDef* def ) b2JointId b2CreateNullJoint( b2WorldId worldId, const b2NullJointDef* def ) { - b2CheckDef( def ); + B2_CHECK_DEF( def ); b2World* world = b2GetWorldFromId( worldId ); B2_ASSERT( world->locked == false ); @@ -498,7 +498,7 @@ b2JointId b2CreateNullJoint( b2WorldId worldId, const b2NullJointDef* def ) b2JointId b2CreateRevoluteJoint( b2WorldId worldId, const b2RevoluteJointDef* def ) { - b2CheckDef( def ); + B2_CHECK_DEF( def ); b2World* world = b2GetWorldFromId( worldId ); B2_ASSERT( world->locked == false ); @@ -553,7 +553,7 @@ b2JointId b2CreateRevoluteJoint( b2WorldId worldId, const b2RevoluteJointDef* de b2JointId b2CreatePrismaticJoint( b2WorldId worldId, const b2PrismaticJointDef* def ) { - b2CheckDef( def ); + B2_CHECK_DEF( def ); b2World* world = b2GetWorldFromId( worldId ); B2_ASSERT( world->locked == false ); @@ -606,7 +606,7 @@ b2JointId b2CreatePrismaticJoint( b2WorldId worldId, const b2PrismaticJointDef* b2JointId b2CreateWeldJoint( b2WorldId worldId, const b2WeldJointDef* def ) { - b2CheckDef( def ); + B2_CHECK_DEF( def ); b2World* world = b2GetWorldFromId( worldId ); B2_ASSERT( world->locked == false ); @@ -648,7 +648,7 @@ b2JointId b2CreateWeldJoint( b2WorldId worldId, const b2WeldJointDef* def ) b2JointId b2CreateWheelJoint( b2WorldId worldId, const b2WheelJointDef* def ) { - b2CheckDef( def ); + B2_CHECK_DEF( def ); b2World* world = b2GetWorldFromId( worldId ); B2_ASSERT( world->locked == false ); diff --git a/src/shape.c b/src/shape.c index de68276d4..5a5993e46 100644 --- a/src/shape.c +++ b/src/shape.c @@ -148,7 +148,7 @@ static b2Shape* b2CreateShapeInternal( b2World* world, b2Body* body, b2Transform static b2ShapeId b2CreateShape( b2BodyId bodyId, const b2ShapeDef* def, const void* geometry, b2ShapeType shapeType ) { - b2CheckDef( def ); + B2_CHECK_DEF( def ); B2_ASSERT( b2IsValidFloat( def->density ) && def->density >= 0.0f ); B2_ASSERT( b2IsValidFloat( def->friction ) && def->friction >= 0.0f ); B2_ASSERT( b2IsValidFloat( def->restitution ) && def->restitution >= 0.0f ); @@ -281,7 +281,7 @@ void b2DestroyShape( b2ShapeId shapeId, bool updateBodyMass ) b2ChainId b2CreateChain( b2BodyId bodyId, const b2ChainDef* def ) { - b2CheckDef( def ); + B2_CHECK_DEF( def ); B2_ASSERT( b2IsValidFloat( def->friction ) && def->friction >= 0.0f ); B2_ASSERT( b2IsValidFloat( def->restitution ) && def->restitution >= 0.0f ); B2_ASSERT( def->count >= 4 ); diff --git a/src/solver.c b/src/solver.c index b9857d101..46e96bf16 100644 --- a/src/solver.c +++ b/src/solver.c @@ -292,6 +292,33 @@ static bool b2ContinuousQueryCallback( int proxyId, int shapeId, void* context ) } } + // todo_erin testing early out for segments +#if 0 + if ( shape->type == b2_segmentShape ) + { + b2Transform transform = bodySim->transform; + b2Vec2 p1 = b2TransformPoint( transform, shape->segment.point1 ); + b2Vec2 p2 = b2TransformPoint( transform, shape->segment.point2 ); + b2Vec2 e = b2Sub( p2, p1 ); + b2Vec2 c1 = continuousContext->centroid1; + b2Vec2 c2 = continuousContext->centroid2; + float offset1 = b2Cross( b2Sub( c1, p1 ), e ); + float offset2 = b2Cross( b2Sub( c2, p1 ), e ); + + if ( offset1 > 0.0f && offset2 > 0.0f ) + { + // Started behind or finished in front + return true; + } + + if ( offset1 < 0.0f && offset2 < 0.0f ) + { + // Started behind or finished in front + return true; + } + } +#endif + b2TOIInput input; input.proxyA = b2MakeShapeDistanceProxy( shape ); input.proxyB = b2MakeShapeDistanceProxy( fastShape ); diff --git a/src/table.c b/src/table.c index 221fe106b..a322c88a8 100644 --- a/src/table.c +++ b/src/table.c @@ -6,12 +6,13 @@ #include "core.h" #include "ctz.h" -#include #include #include -#if B2_DEBUG -_Atomic int g_probeCount; +#if B2_SNOOP_TABLE_COUNTERS +#include +_Atomic int b2_findCount; +_Atomic int b2_probeCount; #endif // todo compare with https://github.com/skeeto/scratch/blob/master/set32/set32.h @@ -74,13 +75,17 @@ static uint32_t b2KeyHash( uint64_t key ) static int b2FindSlot( const b2HashSet* set, uint64_t key, uint32_t hash ) { +#if B2_SNOOP_TABLE_COUNTERS + atomic_fetch_add( &b2_findCount, 1 ); +#endif + uint32_t capacity = set->capacity; int index = hash & ( capacity - 1 ); const b2SetItem* items = set->items; while ( items[index].hash != 0 && items[index].key != key ) { -#if B2_DEBUG - atomic_fetch_add( &g_probeCount, 1 ); +#if B2_SNOOP_TABLE_COUNTERS + atomic_fetch_add( &b2_probeCount, 1 ); #endif index = ( index + 1 ) & ( capacity - 1 ); } diff --git a/src/timer.c b/src/timer.c index caff728c7..a09ce40bb 100644 --- a/src/timer.c +++ b/src/timer.c @@ -92,6 +92,22 @@ b2Timer b2CreateTimer( void ) return timer; } +int64_t b2GetTicks( b2Timer* timer ) +{ + struct timespec ts; + clock_gettime( CLOCK_MONOTONIC, &ts ); + int64_t start_sec = timer->tv_sec; + int64_t start_nsec = timer->tv_nsec; + + int64_t sec_diff = ts.tv_sec - start_sec; + int64_t nsec_diff = ts.tv_nsec - start_nsec; + + timer->tv_sec = ts.tv_sec; + timer->tv_nsec = ts.tv_nsec; + + return sec_diff * 1000000000LL + nsec_diff; +} + float b2GetMilliseconds( const b2Timer* timer ) { struct timespec ts; @@ -158,6 +174,14 @@ b2Timer b2CreateTimer( void ) return timer; } +int64_t b2GetTicks( b2Timer* timer ) +{ + uint64_t count = mach_absolute_time(); + int64_t ticks = count - timer->start; + timer->start = count; + return ticks; +} + float b2GetMilliseconds( const b2Timer* timer ) { uint64_t count = mach_absolute_time(); diff --git a/src/world.c b/src/world.c index a064e6d42..3adf40027 100644 --- a/src/world.c +++ b/src/world.c @@ -89,7 +89,7 @@ static void b2DefaultFinishTaskFcn( void* userTask, void* userContext ) b2WorldId b2CreateWorld( const b2WorldDef* def ) { _Static_assert( B2_MAX_WORLDS < UINT16_MAX, "B2_MAX_WORLDS limit exceeded" ); - b2CheckDef( def ); + B2_CHECK_DEF( def ); int worldId = B2_NULL_INDEX; for ( int i = 0; i < B2_MAX_WORLDS; ++i ) diff --git a/test/test_table.c b/test/test_table.c index 3cfe78865..378e293c8 100644 --- a/test/test_table.c +++ b/test/test_table.c @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2023 Erin Catto // SPDX-License-Identifier: MIT +#include "core.h" #include "ctz.h" #include "table.h" #include "test_macros.h" @@ -63,9 +64,9 @@ int TableTest( void ) ENSURE( set.count == ( itemCount - removeCount ) ); -#ifndef NDEBUG - extern _Atomic int g_probeCount; - g_probeCount = 0; +#if B2_SNOOP_TABLE_COUNTERS + extern _Atomic int b2_probeCount; + b2_probeCount = 0; #endif // Test key search @@ -89,9 +90,9 @@ int TableTest( void ) float ms = b2GetMilliseconds( &timer ); printf( "set: count = %d, b2ContainsKey = %.5f ms, ave = %.5f us\n", itemCount, ms, 1000.0f * ms / itemCount ); -#if !NDEBUG - float aveProbeCount = (float)g_probeCount / (float)itemCount; - printf( "item count = %d, probe count = %d, ave probe count %.2f\n", itemCount, g_probeCount, aveProbeCount ); +#if B2_SNOOP_TABLE_COUNTERS + float aveProbeCount = (float)b2_probeCount / (float)itemCount; + printf( "item count = %d, probe count = %d, ave probe count %.2f\n", itemCount, b2_probeCount, aveProbeCount ); #endif // Remove all keys from set