CProfileManager::dumpAll() Prints Nothing

Post Reply
R3d_protractor
Posts: 3
Joined: Wed Dec 30, 2020 4:49 pm

CProfileManager::dumpAll() Prints Nothing

Post by R3d_protractor »

Hello all,

I am new to bullet physics, and I would like to measure the performance of my simple simulation. I have read in the user manual and have seen posts here describing the CProfileManager class and the dumpAll() method. However, while it seems that these should be straightforward to use, I can't get dumpAll() to print anything.

I built the bullet 3.07 libraries using Cmake on a windows 7 with mingw.

I have included btQuickprof.h. At first my compiler said CProfileManager had not been defined, and looking in the btQuickprof.h file, I found that BT_NO_PROFILE was defined by default, preventing these classes from compiling. I commented out BT_NO_PROFILE, and the compiler could find the classes. Now, although all classes and methods are recognized, CProfileManager::dumpAll() gives no output. There are no errors or warnings.

This loop (not my whole program) runs without errors, but prints nothing:

Code: Select all

	for(int i = 0; i < 100; i++)
	{
		dynamicsWorld->stepSimulation(1.f/60.f, 10);
		CProfileManager::dumpAll();
	}
Does anyone know how to make dumpAll() work? Is it depreciated or something- why would BT_NO_PROFILE be defined by default?

I am able to use CProfileManager::Reset() and CProfileManager::Get_Time_Since_Reset() to measure dynamicsWorld->stepSimulation(), as below:

Code: Select all

	for(int i = 0; i < 100; i++)
	{
		CProfileManager::Reset();
		
		dynamicsWorld->stepSimulation(1.f/60.f, 10);
		
		printf("stepSimulation time (ms): %f\n", CProfileManager::Get_Time_Since_Reset());
	}
but I really need to see the breakdown.

If anyone has any thoughts on how to make dumpAll work, they would be greatly appreciated. Alternatively, if there is another method I could use to access specifically collision detection performance, I would happily use that instead.

Thanks!
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: CProfileManager::dumpAll() Prints Nothing

Post by drleviathan »

When I look at the code I find this in src/LinearMath/btQuickprof.h:

Code: Select all

#ifndef BT_ENABLE_PROFILE
#define BT_NO_PROFILE 1
#endif  //BT_NO_PROFILE
What that means, I believe, is you need to compile with -DBT_ENABLE_PROFILE.
R3d_protractor
Posts: 3
Joined: Wed Dec 30, 2020 4:49 pm

Re: CProfileManager::dumpAll() Prints Nothing

Post by R3d_protractor »

Thanks for your help drleviathan!

I see that in btQuickprof.h, and in fact the middle line there is what I commented out.

When I add -DBT_ENABLE_PROFILE to my compile options, it is recognized but does not help dumpAll() (still nothing printing). That includes if I uncomment out that one line (and I haven't tampered otherwise). I can't find any build options in the Cmake gui when building the whole library that would address this either.

I have checked by adding debug print lines to the source code and rebuilding, and when I call dumpAll(), the dumpAll() method is truly being called as well as the function it calls, CProfileManager::dumpRecursive(), right above it in the source. It seems that it derails here,

Code: Select all

void CProfileManager::dumpRecursive(CProfileIterator* profileIterator, int spacing)
{
	profileIterator->First();
	if (profileIterator->Is_Done())
		return;
right at the start of dumpRecursive in btQuickprof.cpp, which again is successfully called from dumpAll(). I'm not sure why it always returns here rather than going on and printing anything- basically it looks like the profileIterator instantiation passed from dumpAll is empty?

Does anyone else have this problem?

Thanks again drleviathan.
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: CProfileManager::dumpAll() Prints Nothing

Post by drleviathan »

I looked back at an old project where we were using CProfileManager and found code that looks something like the snippets below. You should consider this as pseudo code: I modified it to remove Qt stuff and make it more clear, but dunno if this compiles and it may well have bugs. I offer it with hope you find it helpful. Of particular interest to you: we would call CProfileManager::Increment_Frame_Counter() before using the stats.

Note, we did not find it useful to print stats from every frame but set it up so it could be triggered as manually as a one-off. We also had a way to print the results to file (see below).

Code: Select all

class StatsWriter : public CProfileOperator {
public:
    StatsWriter(const std::string& filename) {
        _stream.open(filename);
        if (!_stream.is_open()) {
            std::cout << "StatsWriter unable to open file '" << filename << "'" << std::endl;
        }
    }

    ~StatsWriter() {
        _stream.close();
    }

    void process(CProfileIterator* itr, const std::string& context) final override {
        if (_stream.is_open()) {
            std::string name = context;
            name.append(itr->Get_Current_Parent_Name());
            float time = (btScalar)MSECS_PER_SECOND * itr->Get_Current_Parent_Total_Time();
            _stream << name << "=" << time << "\n";
        }
    }

protected:
    std::ofstream _stream;
};

void Physics::printPerformanceStatsToFile(const std::string& filename) {
    CProfileIterator* itr = CProfileManager::Get_Iterator();
    if (itr) {
        // hunt for "mainloop" context
        itr->First();
        for (int32_t childIndex = 0; !itr->Is_Done(); ++childIndex) {
            std::string current_name = itr->Get_Current_name();
            if (name == "mainloop") {
                itr->Enter_Child(childIndex);
                StatsWriter writer(filename);
                writer.recurse(itr, "");
                break;
            }
            itr->Next();
        }
    }
}

void Physics::runInThread() {
    // setup...

    // mainloop
    while (_running) {
        CProfileManager::Reset();
        BT_PROFILE("mainloop");
        world->stepSimulation( timeStep, maxSubSteps, fixedTimeStep);

        // do "other stuff" in context and capture its time in the Bullet profiler
        {
            BT_PROFILE("other stuff");
            // other stuff ....
        }

        // harvest the profile only when _dumpNextStats is set
        // (which is done by some other thread)
        if (_dumpNextStats) {
            _dumpNextStats = false;
            CProfileManager::Increment_Frame_Counter();
            if (_saveNextStatsToFile) {
                _saveNextStatsToFile = false;
                printPerformanceStatsToFile(_statsFilename);
            }
            CProfileManager::dumpAll();
        }
    }

    // shutdown...
}
R3d_protractor
Posts: 3
Joined: Wed Dec 30, 2020 4:49 pm

Re: CProfileManager::dumpAll() Prints Nothing

Post by R3d_protractor »

Thanks drleviathan.

After looking through that, I've tried different methods like Increment_Frame_Counter(), BT_PROFILE(), and reset(), but to no avail. These are all recognized (i.e. no undefined reference), but dumpAll() still will not print.

I said I was most interested in collision detection performance, and today I was looking in btDbvtBroadphase.h and found this right at the top:

Code: Select all

//
// Compile time config
//

#define DBVT_BP_PROFILE 0
//#define DBVT_BP_SORTPAIRS				1
#define DBVT_BP_PREVENTFALSEUPDATE 0
#define DBVT_BP_ACCURATESLEEPING 0
#define DBVT_BP_ENABLE_BENCHMARK 0
//#define DBVT_BP_MARGIN					(btScalar)0.05
extern btScalar gDbvtMargin;

#if DBVT_BP_PROFILE
#define DBVT_BP_PROFILING_RATE 256
#include "LinearMath/btQuickprof.h"
#endif
Then, throughout btDbvtBroadphase.cpp, there are pieces of code protected by #if DBVT_BP_PROFILE.

I thought this could be an easy fix and changed the value of DBVT_BP_PROFILE to 1, but then the compiler started throwing errors here at the top of btDbvtBroadphase.cpp

Code: Select all

#if DBVT_BP_PROFILE || DBVT_BP_ENABLE_BENCHMARK
#include <stdio.h>
#endif

#if DBVT_BP_PROFILE
struct ProfileScope
{
	__forceinline ProfileScope(btClock& clock, unsigned long& value) : m_clock(&clock), m_value(&value), m_base(clock.getTimeMicroseconds())
	{
	}
	__forceinline ~ProfileScope()
	{
		(*m_value) += m_clock->getTimeMicroseconds() - m_base;
	}
	btClock* m_clock;
	unsigned long* m_value;
	unsigned long m_base;
};
#define SPC(_value_) ProfileScope spc_scope(m_clock, _value_)
#else
#define SPC(_value_)
#endif
The compiler (when I rebuilt the libraries) was saying "__forceinline not a valid type" and a bunch of other errors surrounding the ProfileScope class, too.
I guess DBVT_BP_PROFILE was set to 0 for a reason. I'm thinking there must be similar pieces of code at other points in the bullet pipeline preventing the use of profile features for them, too, and thus the dumpIterative() method I mentioned earlier returns immediately because all the places in the pipeline that are supposed to have been set up for profiling are switched off. It feels like dumpAll() is not supported in the version I have (3.07), or maybe something about my build or system prevents its usage? Not really sure.

The good news is I have figured out a workaround. Since CProfileManager::Reset() and CProfileManager::Get_Time_Since_Reset() work, I have edited the source code and placed them in btDiscreteDynamicsWorld.cpp in the internalSingleStepSimulation() method. So I can get the ms time that performDiscreteCollisionDetection() takes printed out, if only by editing source which feels a bit jank.

Thanks for your help drleviathan, it means a lot to us newbs. I will check here periodically if anyone has or wants more info, but for now I think I'm alright without dumpAll.
Post Reply