Large number of bodies -> CRASH

bajo
Posts: 10
Joined: Wed Sep 05, 2012 5:57 pm

Large number of bodies -> CRASH

Post by bajo »

Hello,

I'm doing a simple performance test for my project with the "Hello World - Demo" of bullet, where I'm adding a large number of spheres to the project. I want to do a simulation with about 5.000.0000 or more spheres/bodies, is this possible?

Everything is going fine up to 1.590.000 spheres are added to the world (the programm uses about 2GB of memory) and then I get the following error:

An unhandled exception occurred during 0x00F54CFE in AppHelloWorld.exe: 0xC0000005: Access violation writing location 0x00000004. -> and it is pointing to crt0dat.c

I think there is a problem with the memory, but how can I fix it?
Can anyone please help me with this problem?

Code: Select all

/*
#include "btBulletDynamicsCommon.h"
#include <stdio.h>
#include <iostream>					
#include <stdlib.h>

/// This is a Hello World program for running a basic Bullet physics simulation

int main(int argc, char** argv)
{
	
	int i;

	///collision configuration contains default setup for memory, collision setup. Advanced users can create their own configuration.
	btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();

	///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
	btCollisionDispatcher* dispatcher = new	btCollisionDispatcher(collisionConfiguration);

	///btDbvtBroadphase is a good general purpose broadphase. You can also try out btAxis3Sweep.
	btBroadphaseInterface* overlappingPairCache = new btDbvtBroadphase();

	///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
	btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;

	btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,overlappingPairCache,solver,collisionConfiguration);

	dynamicsWorld->setGravity(btVector3(0,-10,0));

	///create a few basic rigid bodies
	btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(50.),btScalar(50.),btScalar(50.)));

	//keep track of the shapes, we release memory at exit.
	//make sure to re-use collision shapes among rigid bodies whenever possible!
	btAlignedObjectArray<btCollisionShape*> collisionShapes;

	collisionShapes.push_back(groundShape);

	btTransform groundTransform;
	groundTransform.setIdentity();
	groundTransform.setOrigin(btVector3(0,-56,0));

	{
		btScalar mass(0.f);

		//rigidbody is dynamic if and only if mass is non zero, otherwise static
		bool isDynamic = (mass != 0.f);

		btVector3 localInertia(0,0,0);
		if (isDynamic)
			groundShape->calculateLocalInertia(mass,localInertia);

		//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
		btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
		btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia);
		btRigidBody* body = new btRigidBody(rbInfo);

		//add the body to the dynamics world
		
		dynamicsWorld->addRigidBody(body);
			
	}


	{
		//create a dynamic rigidbody

		//btCollisionShape* colShape = new btBoxShape(btVector3(1,1,1));
		btCollisionShape* colShape = new btSphereShape(btScalar(1.0));
		collisionShapes.push_back(colShape);

		/// Create Dynamic Objects
		btTransform startTransform;
		startTransform.setIdentity();

		btScalar	mass(1.f);

		//rigidbody is dynamic if and only if mass is non zero, otherwise static
		bool isDynamic = (mass != 0.f);

		btVector3 localInertia(0,0,0);
		if (isDynamic)
			colShape->calculateLocalInertia(mass,localInertia);

		//######## modified - start #######
		int particleCount=0; 
		int xMax=350;  // max. size in x
		int yMax=350;  // max. size in y
		int zMax=350;  // max. size in z
		
		for(int x=0;x<xMax;x=x+3.){ 

			for(int y=0;y<yMax;y=y+3.){

				for(int z=0;z<zMax;z=z+3.){[/color]
			
			
			startTransform.setOrigin(btVector3(btScalar(x),btScalar(y),btScalar(z)));
				
			//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
			btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
			btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,colShape,localInertia);
			btRigidBody* body = new btRigidBody(rbInfo);
			
                        body->setUserPointer((void*)(particleCount)); //adding ID as UserPointer 
			
			dynamicsWorld->addRigidBody(body);
			
			particleCount++; 
			
					}


				}
			printf ("total particles: %d \n",particleCount); 
			}
	}

	//######## modified - end #######


/// Do some simulation

	for (i=0;i<50;i++)
	{
		dynamicsWorld->stepSimulation(1.f/60.f,10);
		
		//print positions of all objects
		for (int j=dynamicsWorld->getNumCollisionObjects()-1; j>=0 ;j--)
		{
			btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[j];
			btRigidBody* body = btRigidBody::upcast(obj);
			if (body && body->getMotionState())
			{
				btTransform trans;
				body->getMotionState()->getWorldTransform(trans);
				//printf("world pos %i = %f,%f,%f\n", (int)(body->getUserPointer()),float(trans.getOrigin().getX()),float(trans.getOrigin().getY()),float(trans.getOrigin().getZ())); 
			}
			
		}
	}


	//cleanup in the reverse order of creation/initialization

	//remove the rigidbodies from the dynamics world and delete them
	for (i=dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
	{
		btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[i];
		btRigidBody* body = btRigidBody::upcast(obj);
		if (body && body->getMotionState())
		{
			delete body->getMotionState();
		}
		dynamicsWorld->removeCollisionObject( obj );
		delete obj;
	}

	//delete collision shapes
	for (int j=0;j<collisionShapes.size();j++)
	{
		btCollisionShape* shape = collisionShapes[j];
		collisionShapes[j] = 0;
		delete shape;
	}

	//delete dynamics world
	delete dynamicsWorld;

	//delete solver
	delete solver;

	//delete broadphase
	delete overlappingPairCache;

	//delete dispatcher
	delete dispatcher;

	delete collisionConfiguration;

	//next line is optional: it will be cleared by the destructor when the array goes out of scope
	collisionShapes.clear();

}


best regards
Alex
bajo
Posts: 10
Joined: Wed Sep 05, 2012 5:57 pm

Re: Large number of bodies -> CRASH

Post by bajo »

I have already solved the problem by myself.

I had to compile bullet as x64 not as x86, so the RAM isn't limited to 2GB.
Now I'm able to simulate more than 5.000.000 bodies.
Flix
Posts: 456
Joined: Tue Dec 25, 2007 1:06 pm

Re: Large number of bodies -> CRASH

Post by Flix »

bajo wrote:I had to compile bullet as x64 not as x86, so the RAM isn't limited to 2GB.
Do you know if the Visual C++ compiler (or linker?) flag /LARGEADDRESSAWARE can be used on x86 systems to solve the problem ?
From the MS docs:
The /LARGEADDRESSAWARE option tells the linker that the application can handle addresses larger than 2 gigabytes. By default, /LARGEADDRESSAWARE:NO is enabled if /LARGEADDRESSAWARE is not otherwise specified on the linker line.
bajo
Posts: 10
Joined: Wed Sep 05, 2012 5:57 pm

Re: Large number of bodies -> CRASH

Post by bajo »

thanks for your reply!

I have tried to set the LARGEADRESSAWARE to YES and so I'm able to increase the memory up to 4GB of RAM.
The 64bit version of bullet allows it to use your whole memory.

btw: Linker/System btLARGEADRESSAWARE:YES
bajo
Posts: 10
Joined: Wed Sep 05, 2012 5:57 pm

Re: Large number of bodies -> CRASH

Post by bajo »

Hello!

I'm trying to get some performance out of my simulation.
So I tried the parallel solver of the MultiThreadDemo (btParallelConstraintSolver), but if there are about 80.000 bodies in the system the simulation crashes with a memory error and points to btPersistentManifold::getContactBreakingThreshold().


Is there a maximum number of bodies you can simulate with the parallelSolver?
How can I increase the number of bodies with the parallelSolver, are there any settings I have to change?

I will post you the code snippets of the SPUdispatcher and parallelSolver, how I implemented them.

btw: another question, how can I use the full performance of the CPU. The bullet cpu utilization is just between 25 to max. 70%?

SPU dispatcher

Code: Select all

		btDefaultCollisionConstructionInfo cci;
		cci.m_defaultMaxPersistentManifoldPoolSize = 32768; 
		collisionConfiguration = new btDefaultCollisionConfiguration(cci);
		
		int maxNumOutstandingTasks=4;
		threadSupportCollision = new Win32ThreadSupport(Win32ThreadSupport::Win32ThreadConstructionInfo(
								"collision",
								processCollisionTask,
								createCollisionLocalStoreMemory,
								maxNumOutstandingTasks));

		dispatcher = new SpuGatheringCollisionDispatcher(threadSupportCollision, maxNumOutstandingTasks, collisionConfiguration); 
		dispatcher->setDispatcherFlags(btCollisionDispatcher::CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
		
parallelSolver

Code: Select all

		threadSupportSolver = createSolverThreadSupport(maxNumOutstandingTasks); 
		
		solver = new btParallelConstraintSolver(threadSupportSolver);
		
		btDynamicsWorld* dynamicsWorld;
		btDiscreteDynamicsWorld* world = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);
		 
		dynamicsWorld = world;

		world->getSimulationIslandManager()->setSplitIslands(false);
		world->getSolverInfo().m_numIterations = 4;
		world->getSolverInfo().m_solverMode = SOLVER_SIMD+SOLVER_USE_WARMSTARTING+SOLVER_RANDMIZE_ORDER;
			
		dynamicsWorld->getDispatchInfo().m_enableSPU = true;
Thanks for your help!
Alex