printStats()

Post Reply
bram
Posts: 50
Joined: Sun Nov 23, 2008 4:43 pm

printStats()

Post by bram » Wed Nov 14, 2018 6:06 pm

I am trying to improve the performance of the collision testing.

So a good place to start would be to see how effective the broadphase is.

I tried calling:

Code: Select all

virtual void btBroadphaseInterface::printStats()
But I see nothing in stdout, when I call this?

I've tried it with btAxisSweep3 and btDbvtBroadphase.

Is there a way to see how many collisions tests were performed, and many were eliminated by broadphase? That kind of info?

User avatar
Erwin Coumans
Site Admin
Posts: 4155
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: printStats()

Post by Erwin Coumans » Wed Nov 14, 2018 8:04 pm

Ignore printStats, it is not used.

>> how many were eliminated by broadphase?

If you want to know how many pairs there are, use btOverlappingPairCache::getNumOverlappingPairs
Without a broadphase, you would check (n^2)/2, so you can compute the difference:
(n^2)/2 - btOverlappingPairCache::getNumOverlappingPairs

Inside the Bullet example browser, you can push down 'p' and release 'p' and you get performance statistics as a timings.json file.
You can open Google Chrome to see where time is spend exactly: about://tracing
Then open the timings.json file. Here is an example of such run, using your demo on my machine, at the worst frame (5ms):
tracing.png
tracing.png (101.02 KiB) Viewed 372 times
timings_0.zip
(2.16 MiB) Downloaded 8 times

bram
Posts: 50
Joined: Sun Nov 23, 2008 4:43 pm

Re: printStats()

Post by bram » Wed Nov 14, 2018 9:48 pm

Thank you Erwin,

That's useful to know.
I guess the broadphase works well enough.

For this scene:
Image

I get:

Code: Select all

numobj: 178
numpairs: 1245
maxpairs: 31684
pairs per obj: 7.0
percentage: 3.9
So every object is tested, on average against 7 others.
It's hard to judge of course, but feels kinda reasonable when you look at the scene.

EDIT: From your chrome trace, I see that collision detection is also done in parallel. Nice!

User avatar
Erwin Coumans
Site Admin
Posts: 4155
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: printStats()

Post by Erwin Coumans » Wed Nov 14, 2018 11:23 pm

It looks like you got inspired by Dennis Gustafsson :-) ? https://twitter.com/tuxedolabs/status/1 ... 4001363968

>> I see that collision detection is also done in parallel. Nice!
Yes apparently, it was a contribution, but the default broadphase/collision dispatcher in Bullet is single threaded.

For multi-threading you need to compile using BT_ENABLE_THREADSAFE
and use btCollisionDispatcherMt and btDiscreteDynamicsWorldMt.

Note that the convex collision detection uses GJK and for deep penetrations EPA.
Ideally you don't get too much in deep penetration.

If you want large scale destruction and lots of convex-convex, you likely need to spend more work on optimizations,
I know Dennis spend a lot of time on it, and so did Pierre Terdiman and crew for PhysX (using SAT and also GJK with persistent manifold nowadays).

Reducing the number of vertices may help. You could try using 'convexShape->optimizeConvexHull' but that call itself is expensive, so it may not be worth it.


Aside from GJK+EPA or SAT, you can also consider using MPR, but I find it less robust (incorrect penetration/normals).

MPR is implemented in the voronoi demo. To enable it, use this code snippet:

Code: Select all

//at the top of your file
#include "../VoronoiFracture/btConvexConvexMprAlgorithm.h"


		m_dispatcher = new MyCollisionDispatcher(m_collisionConfiguration, 40);

//somewhere after you create a collision dispatcher
		{
			printf("using GJK+MPR convex-convex collision detection\n");
			btConvexConvexMprAlgorithm::CreateFunc* cf = new btConvexConvexMprAlgorithm::CreateFunc;
			m_dispatcher->registerCollisionCreateFunc(CONVEX_HULL_SHAPE_PROXYTYPE, CONVEX_HULL_SHAPE_PROXYTYPE, cf);
			m_dispatcher->registerCollisionCreateFunc(CONVEX_HULL_SHAPE_PROXYTYPE, BOX_SHAPE_PROXYTYPE, cf);
			m_dispatcher->registerCollisionCreateFunc(BOX_SHAPE_PROXYTYPE, CONVEX_HULL_SHAPE_PROXYTYPE, cf);
		}
If you are OK with that (lower) quality, the code is likely easier to optimize.

Also, be careful with 'initializePolyhedralFeatures', it is mainly for when you use SAT, and it changes the way margins work (since margins don't affect SAT etc).

bram
Posts: 50
Joined: Sun Nov 23, 2008 4:43 pm

Re: printStats()

Post by bram » Thu Nov 15, 2018 1:32 am

>It looks like you got inspired by Dennis Gustafsson

What Dennis does is pretty much higher magic :-) The most impressive game tech I ever saw.

My inspiration is bringing this 2D game into the third dimension:
https://twitter.com/BramStolk/status/10 ... 6359673856
I'm beginning to think I underestimated the difference between 3D and 2D.
I guess in 3D you get punished twice: there are more fragments, and those fragments are harder to collide than 2D convex shapes.

>For multi-threading you need to compile using BT_ENABLE_THREADSAFE

Just to be sure: recompile the bullet lib with that define, or just my app?

> Aside from GJK+EPA or SAT, you can also consider using MPR, but I find it less robust (incorrect penetration/normals).

Good to know there is a third candidate. It does seem that colliding takes a little bit more time than the solver, in my current app.

User avatar
Erwin Coumans
Site Admin
Posts: 4155
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: printStats()

Post by Erwin Coumans » Thu Nov 15, 2018 2:20 am

All defines, such as BT_ENABLE_THREADSAFE and BT_USE_DOUBLE_PRECISION etc should be added in both lib and app, and better be the same in both.
Usually I just put the physics source code together with the app, to avoid any mismatch/out-of-date version etc.

>> https://twitter.com/BramStolk/status/10 ... 6359673856

cool video/game!

Yes, in 3D it will be harder, and you need to apply tricks/magic. Perhaps you freeze or remove the parts of a collapsed building after a few seconds, so it doesn't take cpu cycles?

The abstract destruction in 3D looks great though.

bram
Posts: 50
Joined: Sun Nov 23, 2008 4:43 pm

Re: printStats()

Post by bram » Thu Nov 15, 2018 3:25 am

Thanks.

If the C Flags need to be present in both lib and app, and need to be consistent, then a possible way to guarantee that is to have pkg-config handle it.

Currently it does not:

Code: Select all

$ pkg-config --cflags bullet
-I/usr/local/include/bullet -I/usr/local/include
I would help you add it, but I am not familiar with authoring CMake stuff.

bram
Posts: 50
Joined: Sun Nov 23, 2008 4:43 pm

Re: printStats()

Post by bram » Thu Nov 15, 2018 7:11 pm

Erwin Coumans wrote:
Wed Nov 14, 2018 11:23 pm
For multi-threading you need to compile using BT_ENABLE_THREADSAFE
and use btCollisionDispatcherMt and btDiscreteDynamicsWorldMt.
It seems quite a bit more involved than just switching out those classes.
If you do only that:

Assertion `gBtTaskScheduler != NULL' failed.

It looks like all the task management is done externally, outside bullet, judging from the CommonRigidBodyMTBase.cpp example file.

User avatar
Erwin Coumans
Site Admin
Posts: 4155
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: printStats()

Post by Erwin Coumans » Thu Nov 15, 2018 7:38 pm

Since many developers have their own, you can interface to your own task scheduler.
There are however a few built-in task schedulers, pick one of those:

Code: Select all

addTaskScheduler(btGetSequentialTaskScheduler());
#if BT_THREADSAFE
		if (btITaskScheduler* ts = btCreateDefaultTaskScheduler())
		{
			m_allocatedTaskSchedulers.push_back(ts);
			addTaskScheduler(ts);
		}
		addTaskScheduler(btGetOpenMPTaskScheduler());
		addTaskScheduler(btGetTBBTaskScheduler());
		addTaskScheduler(btGetPPLTaskScheduler());
btCreateDefaultTaskScheduler uses Bullet's own threading abstraction, based on pthreads (Linux/Mac) and Win32Threads on Windows.
btGetOpenMPTaskScheduler uses OpenMP
btGetTBBTaskScheduler uses Intel Thread Building Blocks
btGetPPLTaskScheduler uses PPL.



The task scheduling interface isn't very complicated if you have already one. The safest start with still some multithreading is btCreateDefaultTaskScheduler. If your platform supports TBB, that could be a good choice too.

Code: Select all

class btITaskScheduler
{
public:
	btITaskScheduler(const char* name);
	virtual ~btITaskScheduler() {}
	const char* getName() const { return m_name; }

	virtual int getMaxNumThreads() const = 0;
	virtual int getNumThreads() const = 0;
	virtual void setNumThreads(int numThreads) = 0;
	virtual void parallelFor(int iBegin, int iEnd, int grainSize, const btIParallelForBody& body) = 0;
	virtual btScalar parallelSum(int iBegin, int iEnd, int grainSize, const btIParallelSumBody& body) = 0;
	virtual void sleepWorkerThreadsHint() {}  // hint the task scheduler that we may not be using these threads for a little while

	// internal use only
	virtual void activate();
	virtual void deactivate();

protected:
	const char* m_name;
	unsigned int m_savedThreadCounter;
	bool m_isActive;
};

bram
Posts: 50
Joined: Sun Nov 23, 2008 4:43 pm

Re: printStats()

Post by bram » Thu Nov 15, 2018 10:40 pm

Erwin Coumans wrote:
Thu Nov 15, 2018 7:38 pm
There are however a few built-in task schedulers, pick one of those:
Excellent!

For anyone else reading this, and trying to switch to MT:
After you create the manager, you need to set it with btSetTaskScheduler like so:

Code: Select all

        btITaskScheduler* scheduler = btCreateDefaultTaskScheduler();
        btSetTaskScheduler( scheduler );
When I create my world and dispatcher, I use:

Code: Select all

        dispatcher = new btCollisionDispatcherMt(collisionConfiguration);
        ....
        solverpool = new btConstraintSolverPoolMt( 4 );
        world = new btDiscreteDynamicsWorldMt( dispatcher, broadphase, solverpool, solver, collisionConfiguration );

Post Reply