1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-06-30 12:14:08 +03:00

Foundation Classes - Return value is overridden by OCCT #528

- Removed OSD_PerfMeter.h and integrated its functionality directly into OSD_PerfMeter.hxx.
- Updated OSD_PerfMeter to manage stopwatches through a singleton StopwatchStorage class.
- Enhanced meter initialization and management to support shared meters by name.
- Implemented methods for starting, stopping, and printing elapsed time for performance meters.
- Added OSD_PerfMeter_Test.cxx to implement unit tests for OSD_PerfMeter functionality.
- Test bug23237 is delete as it refers to removed code.
This commit is contained in:
Dmitrii Kulikov 2025-05-15 15:21:52 +01:00 committed by GitHub
parent e82126db69
commit 66d2a06b5a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 956 additions and 1033 deletions

View File

@ -28,6 +28,7 @@
#include <OSD_MAllocHook.hxx>
#include <OSD_MemInfo.hxx>
#include <OSD_Parallel.hxx>
#include <OSD_PerfMeter.hxx>
#include <OSD_ThreadPool.hxx>
#include <Standard_Macro.hxx>
#include <Standard_SStream.hxx>
@ -35,7 +36,6 @@
#include <Standard_Version.hxx>
#include <TCollection_AsciiString.hxx>
#include <OSD_PerfMeter.h>
#ifdef _WIN32
#include <windows.h>
@ -969,10 +969,14 @@ static int dparallel(Draw_Interpretor& theDI, Standard_Integer theArgNb, const c
static int dperf(Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
{
// reset if argument is provided and it is not '0'
int reset = (theArgNb > 1 ? theArgVec[1][0] != '0' && theArgVec[1][0] != '\0' : 0);
char buffer[25600];
perf_sprint_all_meters(buffer, 25600 - 1, reset);
theDI << buffer;
int reset = (theArgNb > 1 ? theArgVec[1][0] != '0' && theArgVec[1][0] != '\0' : 0);
const TCollection_AsciiString anOutput = OSD_PerfMeter::PrintALL();
theDI << anOutput;
if (reset)
{
OSD_PerfMeter::ResetALL();
}
return 0;
}

View File

@ -130,58 +130,6 @@ static Standard_Integer OCC23361(Draw_Interpretor& di,
return 0;
}
static Standard_Integer OCC23237(Draw_Interpretor& di,
Standard_Integer /*argc*/,
const char** /*argv*/)
{
OSD_PerfMeter aPM("TestMeter", 0);
OSD_Timer aTM;
// run some operation in cycle for about 2 seconds to have good values of times to compare
int count = 0;
printf("OSD_PerfMeter test.\nRunning Boolean operation on solids in loop.\n");
for (; aTM.ElapsedTime() < 2.; count++)
{
aPM.Start();
aTM.Start();
// do some operation that will take considerable time compared with time of starting / stopping
// timers
BRepPrimAPI_MakeBox aBox(10., 10., 10.);
BRepPrimAPI_MakeSphere aSphere(10.);
BRepAlgoAPI_Cut aCutter(aBox.Shape(), aSphere.Shape());
aTM.Stop();
aPM.Stop();
}
int aNbEnters = 0;
Standard_Real aPerfMeter_CPUtime = 0., aTimer_CPUTime = 0., aS;
Standard_Integer aM, aH;
aTM.Show(aS, aM, aH, aTimer_CPUTime);
perf_get_meter("TestMeter", &aNbEnters, &aPerfMeter_CPUtime);
perf_init_meter("TestMeter");
Standard_Real aTimeDiff = (fabs(aTimer_CPUTime - aPerfMeter_CPUtime) / aTimer_CPUTime);
printf("\nMeasurement results (%d cycles):\n", count);
printf("\nOSD_PerfMeter CPU time: %lf\nOSD_Timer CPU time: %lf\n",
aPerfMeter_CPUtime,
aTimer_CPUTime);
printf("Time delta is: %.3lf %%\n", aTimeDiff * 100);
if (aTimeDiff > 0.2)
di << "OCC23237: Error: too much difference between CPU and elapsed times";
else if (aNbEnters != count)
di << "OCC23237: Error: counter reported by PerfMeter (" << aNbEnters
<< ") does not correspond to actual number of cycles";
else
di << "OCC23237: OK";
return 0;
}
class IncrementerDecrementer
{
public:
@ -5462,7 +5410,6 @@ void QABugs::Commands_19(Draw_Interpretor& theCommands)
theCommands.Add("OCC230", "OCC230 TrimmedCurve Pnt2d Pnt2d", __FILE__, OCC230, group);
theCommands.Add("OCC23361", "OCC23361", __FILE__, OCC23361, group);
theCommands.Add("OCC23237", "OCC23237", __FILE__, OCC23237, group);
theCommands.Add("OCC22980", "OCC22980", __FILE__, OCC22980, group);
theCommands.Add("OCC23595", "OCC23595", __FILE__, OCC23595, group);
theCommands.Add("OCC22611", "OCC22611 string nb", __FILE__, OCC22611, group);

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,7 @@ set(OCCT_TKernel_GTests_FILES
NCollection_Sequence_Test.cxx
NCollection_SparseArray_Test.cxx
NCollection_Vector_Test.cxx
OSD_PerfMeter_Test.cxx
TCollection_AsciiString_Test.cxx
TCollection_ExtendedString_Test.cxx
)

View File

@ -0,0 +1,357 @@
#include <gtest/gtest.h>
#include <OSD_PerfMeter.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <chrono>
#include <thread>
#include <sstream>
#include <string>
#include <vector>
// Test fixture for OSD_PerfMeter tests
class OSD_PerfMeterTest : public ::testing::Test
{
protected:
void SetUp() override
{
// Reset all meters before each test
OSD_PerfMeter::ResetALL();
}
void TearDown() override
{
// Reset all meters after each test
OSD_PerfMeter::ResetALL();
}
// Helper function to perform some measurable work
static void DoSomeWork(const double theTimeInSec = 0.1)
{
OSD_PerfMeter meter("WorkMeter", true);
while (meter.Elapsed() < theTimeInSec)
{
// do some operation that will take considerable time compared with time of starting /
// stopping timers
BRepPrimAPI_MakeBox aBox(10., 10., 10.);
BRepPrimAPI_MakeSphere aSphere(10.);
BRepAlgoAPI_Cut aCutter(aBox.Shape(), aSphere.Shape());
}
meter.Kill();
}
};
//==================================================================================================
// Test basic creation and auto-start functionality
TEST_F(OSD_PerfMeterTest, BasicCreationWithAutoStart)
{
// Create an auto-started meter
OSD_PerfMeter meter("TestMeter", true);
// Do some work
DoSomeWork();
// Stop the meter
meter.Stop();
// Check elapsed time is positive
double elapsed = meter.Elapsed();
EXPECT_GT(elapsed, 0.0) << "Elapsed time should be positive";
}
//==================================================================================================
// Test manual start/stop functionality
TEST_F(OSD_PerfMeterTest, ManualStartStop)
{
// Create a meter without auto-start
OSD_PerfMeter meter("ManualMeter", false);
// Start the meter
meter.Start();
// Do some work
DoSomeWork();
// Stop the meter
meter.Stop();
// Check elapsed time is positive
double elapsed = meter.Elapsed();
EXPECT_GT(elapsed, 0.0) << "Elapsed time should be positive";
}
//==================================================================================================
// Test default constructor and Init
TEST_F(OSD_PerfMeterTest, DefaultConstructorAndInit)
{
// Create meter with default constructor
OSD_PerfMeter meter;
// Initialize it
meter.Init("InitializedMeter");
// Start it manually
meter.Start();
// Do some work
DoSomeWork();
// Stop and check elapsed time
meter.Stop();
EXPECT_GT(meter.Elapsed(), 0.0) << "Initialized meter should have positive elapsed time";
}
//==================================================================================================
// Test that two meters with the same name refer to the same internal meter
TEST_F(OSD_PerfMeterTest, SharedMetersByName)
{
const char* meterName = "SharedMeter";
// Create and start first meter
OSD_PerfMeter meter1(meterName);
// Do some work
DoSomeWork();
// Create second meter with the same name, but don't auto-start
OSD_PerfMeter meter2;
meter2.Init(meterName);
// Do more work
DoSomeWork();
// Stop both meters
meter1.Stop();
// The elapsed time should account for both work segments
double elapsed = meter1.Elapsed();
EXPECT_GT(elapsed, 0.0) << "Elapsed time should be positive";
// Stopping meter2 should have no effect since they share the same meter
// and meter1 already stopped it
meter2.Stop();
double elapsed2 = meter2.Elapsed();
EXPECT_DOUBLE_EQ(elapsed, elapsed2) << "Both meter instances should show same elapsed time";
}
//==================================================================================================
// Test restarting a meter
TEST_F(OSD_PerfMeterTest, RestartMeter)
{
// Create and start meter
OSD_PerfMeter meter("RestartMeter");
// Do some work
DoSomeWork(0.1);
// Stop and get elapsed time
meter.Stop();
double elapsed1 = meter.Elapsed();
EXPECT_GT(elapsed1, 0.0) << "First elapsed time should be positive";
// Restart the meter
meter.Start();
// Do more work
DoSomeWork(0.2);
// Stop and get elapsed time again
meter.Stop();
double elapsed2 = meter.Elapsed();
EXPECT_GT(elapsed2, 0.0) << "Second elapsed time should be positive";
// Second elapsed time should be different from first
EXPECT_NE(elapsed1, elapsed2) << "After restart, elapsed time should be different";
}
//==================================================================================================
// Test relative timing accuracy
TEST_F(OSD_PerfMeterTest, RelativeTimingAccuracy)
{
// Create two meters
OSD_PerfMeter meter1("ShortMeter");
OSD_PerfMeter meter2("LongMeter");
// Short work for meter1
DoSomeWork(0.1);
meter1.Stop();
// Long work for meter2
DoSomeWork(0.5);
meter2.Stop();
// Long work should take more time than short work
double shortElapsed = meter1.Elapsed();
double longElapsed = meter2.Elapsed();
EXPECT_GT(shortElapsed, 0.0) << "Short elapsed time should be positive";
EXPECT_GT(longElapsed, 0.0) << "Long elapsed time should be positive";
EXPECT_GT(longElapsed, shortElapsed) << "Long work should take more time than short work";
}
//==================================================================================================
// Test the static PrintALL method
TEST_F(OSD_PerfMeterTest, PrintALL)
{
// Create and use several meters
OSD_PerfMeter meter1("Meter1");
DoSomeWork(0.1);
meter1.Stop();
OSD_PerfMeter meter2("Meter2");
DoSomeWork(0.2);
meter2.Stop();
OSD_PerfMeter meter3("Meter3");
DoSomeWork(0.3);
meter3.Stop();
// Get the printed output
std::string output = OSD_PerfMeter::PrintALL().ToCString();
// Check that the output contains all meter names
EXPECT_TRUE(output.find("Meter1") != std::string::npos)
<< "PrintALL output should contain Meter1";
EXPECT_TRUE(output.find("Meter2") != std::string::npos)
<< "PrintALL output should contain Meter2";
EXPECT_TRUE(output.find("Meter3") != std::string::npos)
<< "PrintALL output should contain Meter3";
}
//==================================================================================================
// Test the static ResetALL method
TEST_F(OSD_PerfMeterTest, ResetALL)
{
// Create and use several meters
OSD_PerfMeter meter1("ResetMeter1");
DoSomeWork(0.1);
meter1.Stop();
OSD_PerfMeter meter2("ResetMeter2");
DoSomeWork(0.2);
meter2.Stop();
// Both meters should have positive elapsed times
EXPECT_GT(meter1.Elapsed(), 0.0);
EXPECT_GT(meter2.Elapsed(), 0.0);
// Reset all meters
OSD_PerfMeter::ResetALL();
// After reset, all meters should have zero elapsed time
EXPECT_EQ(meter1.Elapsed(), 0.0) << "Elapsed time should be zero after ResetALL";
EXPECT_EQ(meter2.Elapsed(), 0.0) << "Elapsed time should be zero after ResetALL";
}
//==================================================================================================
// Test unused meter behavior
TEST_F(OSD_PerfMeterTest, UnusedMeter)
{
// Create a meter but don't start it
OSD_PerfMeter meter("UnusedMeter", false);
// Elapsed time should be zero
EXPECT_EQ(meter.Elapsed(), 0.0) << "Unused meter should have zero elapsed time, actual";
// Stopping not started meter should have no effect
meter.Stop();
EXPECT_EQ(meter.Elapsed(), 0.0) << "Stopping an unused meter should leave elapsed time at zero";
}
//==================================================================================================
// Test the Print() method
TEST_F(OSD_PerfMeterTest, PrintMethod)
{
// Create and start the meter
const TCollection_AsciiString meterName = "PrintTestMeter";
OSD_PerfMeter meter(meterName);
// Do some work
DoSomeWork();
// Stop the meter
meter.Stop();
// Get the printed output
std::string output = meter.Print().ToCString();
// Verify output contains necessary information
EXPECT_TRUE(output.find(meterName.ToCString()) != std::string::npos)
<< "Print output should contain meter name";
// Verify output contains elapsed time info (we can't check exact time,
// but there should be numbers)
EXPECT_TRUE(output.find_first_of("0123456789") != std::string::npos)
<< "Print output should contain elapsed time values";
EXPECT_TRUE(output.find("sec") != std::string::npos)
<< "Print output should contain millisecond units";
}
//==================================================================================================
// Test the Kill() method
TEST_F(OSD_PerfMeterTest, KillMethod)
{
// Create and start the meter
OSD_PerfMeter meter("KillTestMeter");
// Do some work
DoSomeWork();
// Stop the meter
meter.Stop();
// Verify we have non-zero elapsed time
double elapsed = meter.Elapsed();
EXPECT_GT(elapsed, 0.0) << "Meter should have recorded time before Kill";
// Kill the meter
meter.Kill();
// Verify elapsed time is reset
double elapsedAfterKill = meter.Elapsed();
EXPECT_EQ(elapsedAfterKill, 0.0) << "Elapsed time should be reset after Kill";
// Verify killing a meter makes it disappear from the global list
std::string allMeters = OSD_PerfMeter::PrintALL().ToCString();
EXPECT_TRUE(allMeters.find("KillTestMeter") == std::string::npos)
<< "Killed meter should not appear in PrintALL output";
}
//==================================================================================================
// Test Kill method on a running meter
TEST_F(OSD_PerfMeterTest, KillRunningMeter)
{
// Create and start the meter
OSD_PerfMeter meter("KillRunningMeter");
// Don't stop the meter, kill it while running
meter.Kill();
// Verify elapsed time is reset
double elapsedAfterKill = meter.Elapsed();
EXPECT_EQ(elapsedAfterKill, 0.0) << "Elapsed time should be reset after Kill";
// Start the meter again to verify it's usable after being killed
meter.Init("KillRunningMeter");
meter.Start();
DoSomeWork();
meter.Stop();
// Verify it records time correctly after being killed and restarted
EXPECT_GT(meter.Elapsed(), 0.0) << "Meter should record time after Kill and restart";
}

View File

@ -66,7 +66,6 @@ set(OCCT_OSD_FILES
OSD_Path.cxx
OSD_Path.hxx
OSD_PerfMeter.cxx
OSD_PerfMeter.h
OSD_PerfMeter.hxx
OSD_Process.cxx
OSD_Process.hxx

View File

@ -15,389 +15,379 @@
commercial license or contractual agreement.
*/
/*======================================================================
*/
/*Purpose : Set of functions to measure the CPU user time
*/
/*25/09/2001 : AGV : (const char *) in prototypes;
*/
/*09/11/2001 : AGV : Add functions perf_*_imeter for performance
*/
/*Add function perf_tick_meter
*/
/*14/05/2002 : AGV : Portability UNIX/Windows
*/
/*======================================================================*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <OSD_PerfMeter.hxx>
#include <OSD_Chronometer.hxx>
#include <OSD_PerfMeter.h>
/*======================================================================
DEFINITIONS
======================================================================*/
#include <unordered_map>
typedef Standard_Real PERF_TIME;
#define PICK_TIME(_utime) \
{ \
Standard_Real ktime; \
OSD_Chronometer::GetThreadCPU(_utime, ktime); \
}
typedef struct
// Simple stopwatch class to measure elapsed time
// and provides methods to start, stop, and get the elapsed time in seconds.
class Stopwatch
{
char* name; /* identifier */
PERF_TIME cumul_time; /* cumulative time */
PERF_TIME start_time; /* to store start time */
int nb_enter; /* number of enters */
} t_TimeCounter;
public:
// Constructor initializes the stopwatch.
// It does not start the stopwatch.
Stopwatch();
#define MAX_METERS 100
// Starts the stopwatch. If it is already running, it resets the start time.
void Start();
static t_TimeCounter MeterTable[MAX_METERS];
static int nb_meters = 0;
// Stops the stopwatch. If it is already stopped, it does nothing.
void Stop();
static int find_meter(const char* const MeterName);
static int _perf_init_meter(const char* const MeterName, const int doFind);
// Returns the elapsed time in seconds since the stopwatch was started.
// If the stopwatch is still running, it returns the time since the last start.
// If the stopwatch was stopped, it returns the time between the last start and stop.
// If the stopwatch was never started, it returns 0.
double Elapsed() const;
/*======================================================================
Function : perf_init_meter
Purpose : Creates new counter (if it is absent) identified by
MeterName and resets its cumulative value
Returns : iMeter if OK, -1 if alloc problem
======================================================================*/
int perf_init_meter(const char* const MeterName)
// Returns true if the stopwatch is currently running.
// Returns false if the stopwatch is stopped or was never started.
inline bool IsRunning() const;
// Returns true if the stopwatch has been started at least once and has a non-zero elapsed time.
// Returns false if the stopwatch was never started or has zero elapsed time.
inline bool IsActive() const;
private:
// Returns the current time in seconds.
static double getTime();
private:
double myStartTime; //< The time when the stopwatch was started.
double myEndTime; //< The time when the stopwatch was stopped.
// Equal to myStartTime if the stopwatch is
// running or was never started.
bool myIsTicking; //< Indicates whether the stopwatch is
// currently running.
};
//==================================================================================================
Stopwatch::Stopwatch()
: myStartTime(getTime()),
myEndTime(myStartTime),
myIsTicking(false)
{
return _perf_init_meter(MeterName, ~0);
}
/*======================================================================
Function : perf_tick_meter
Purpose : Increments the counter of meter MeterName without changing
its state with respect to measurement of time.
creates new meter if there is no such meter
Returns : iMeter if OK, -1 if no such meter and cannot create a new one
======================================================================*/
int perf_tick_meter(const char* const MeterName)
{
int ic = find_meter(MeterName);
//==================================================================================================
if (ic == -1)
void Stopwatch::Start()
{
myStartTime = getTime();
myIsTicking = true;
}
//==================================================================================================
void Stopwatch::Stop()
{
if (!myIsTicking)
{
/* create new meter */
ic = _perf_init_meter(MeterName, 0);
return;
}
if (ic >= 0)
MeterTable[ic].nb_enter++;
return ic;
myEndTime = getTime();
myIsTicking = false;
}
/*======================================================================
Function : perf_tick_imeter
Purpose : Increments the counter of meter iMeter without changing
its state with respect to measurement of time.
Returns : iMeter if OK, -1 if no such meter
======================================================================*/
int perf_tick_imeter(const int iMeter)
//==================================================================================================
double Stopwatch::Elapsed() const
{
if (iMeter >= 0 && iMeter < nb_meters)
const double anEndTime = myIsTicking ? getTime() : myEndTime;
return anEndTime - myStartTime;
}
//==================================================================================================
bool Stopwatch::IsRunning() const
{
return myIsTicking;
}
//==================================================================================================
bool Stopwatch::IsActive() const
{
return myIsTicking || (myEndTime - myStartTime) > 0.0;
}
//==================================================================================================
double Stopwatch::getTime()
{
Standard_Real aUserSeconds = 0.0;
Standard_Real aSystemSeconds = 0.0;
OSD_Chronometer::GetThreadCPU(aUserSeconds, aSystemSeconds);
(void)(aSystemSeconds); // Unused variable
return aUserSeconds;
}
//==================================================================================================
// Singleton class to manage multiple stopwatches.
// It provides methods to create, retrieve, and print stopwatches by name.
// It also handles the lifetime of the stopwatches and prints their results when the program ends.
// The class is designed to be used as a singleton, ensuring that there is only one instance of the
// stopwatch manager throughout the program.
class StopwatchStorage
{
private:
StopwatchStorage() = default;
StopwatchStorage(const StopwatchStorage&) = delete;
StopwatchStorage& operator=(const StopwatchStorage&) = delete;
StopwatchStorage(StopwatchStorage&&) = delete;
StopwatchStorage& operator=(StopwatchStorage&&) = delete;
~StopwatchStorage() { PrintAll(); }
public:
// Returns the singleton instance of the StopwatchStorage class.
static StopwatchStorage& Instance();
// Retrieves a stopwatch by name. If the stopwatch does not exist, it returns nullptr.
// If the stopwatch exists, it returns a pointer to the stopwatch.
// This allows the user to access and manipulate the stopwatch directly.
// @param theName The name of the stopwatch to retrieve.
// @return A pointer to the stopwatch if it exists, nullptr otherwise.
Stopwatch* GetStopwatch(const std::string& theName);
// Creates a new stopwatch with the specified name.
// If a stopwatch with the same name already exists, it will be replaced.
// @param theName The name of the stopwatch to create.
// @return A reference to the created stopwatch.
Stopwatch& CreateStopwatch(const std::string& theName);
// Checks if a stopwatch with the specified name exists.
// This method allows the user to check if a stopwatch is already created before attempting to
// create or retrieve it.
// @param theName The name of the stopwatch to check.
// @return True if the stopwatch exists, false otherwise.
bool HasStopwatch(const std::string& theName) const;
// Deletes a stopwatch with the specified name.
// If the stopwatch does not exist, it does nothing.
// This method allows the user to remove a stopwatch from the storage.
// @param theName The name of the stopwatch to delete.
// @return True if the stopwatch was successfully deleted, false otherwise.
void KillStopwatch(const std::string& theName);
// Clears all stopwatches from the storage.
// This method removes all stopwatches and resets the storage to its initial state.
// It is useful for cleaning up the storage when it is no longer needed.
void Clear();
// Prints the results of a specific stopwatch by name.
// If the stopwatch does not exist, it does nothing.
// If the stopwatch is still running, it prints a warning message.
// If the stopwatch was never started, it prints a message indicating that.
// @param theName The name of the stopwatch to print.
// @return A string containing the results of the stopwatch.
std::string Print(const std::string& theName) const;
// Prints the results of all stopwatches in the storage.
// It iterates through all stopwatches and prints their results.
// If a stopwatch is still running, it prints a warning message.
// If a stopwatch was never started, it prints a message indicating that.
// @return A string containing the results of all stopwatches.
std::string PrintAll() const;
private:
// Helper method to print the results of a specific stopwatch.
// It formats the output and appends it to the provided output string.
// @param theName The name of the stopwatch to print.
// @param theOutput The output string to append the results to.
void print(const std::string& theName, std::string& theOutput) const;
private:
std::unordered_map<std::string, Stopwatch> myStopwatches; //< Map to store stopwatches by name.
};
//==================================================================================================
StopwatchStorage& StopwatchStorage::Instance()
{
static StopwatchStorage instance;
return instance;
}
//===================================================================================================
Stopwatch* StopwatchStorage::GetStopwatch(const std::string& theName)
{
auto it = myStopwatches.find(theName);
return (it != myStopwatches.end()) ? &it->second : nullptr;
}
//===================================================================================================
Stopwatch& StopwatchStorage::CreateStopwatch(const std::string& theName)
{
myStopwatches[theName] = Stopwatch();
return myStopwatches[theName];
}
//===================================================================================================
bool StopwatchStorage::HasStopwatch(const std::string& theName) const
{
return myStopwatches.find(theName) != myStopwatches.end();
}
//===================================================================================================
void StopwatchStorage::KillStopwatch(const std::string& theName)
{
myStopwatches.erase(theName);
}
//===================================================================================================
void StopwatchStorage::Clear()
{
myStopwatches.clear();
}
//===================================================================================================
std::string StopwatchStorage::Print(const std::string& theName) const
{
std::string anOutput;
auto it = myStopwatches.find(theName);
if (it != myStopwatches.end())
{
MeterTable[iMeter].nb_enter++;
return iMeter;
print(theName, anOutput);
}
return -1;
return anOutput;
}
/*======================================================================
Function : perf_start_meter
Purpose : Forces meter MeterName to begin to count by remembering
the current data of timer;
creates new meter if there is no such meter
Returns : iMeter if OK, -1 if no such meter and cannot create a new one
======================================================================*/
int perf_start_meter(const char* const MeterName)
{
int ic = find_meter(MeterName);
//===================================================================================================
if (ic == -1)
std::string StopwatchStorage::PrintAll() const
{
std::string anOutput;
for (const auto& aStopwatch : myStopwatches)
{
/* create new meter */
ic = _perf_init_meter(MeterName, 0);
print(aStopwatch.first, anOutput);
}
if (ic >= 0)
PICK_TIME(MeterTable[ic].start_time)
return ic;
return anOutput;
}
/*======================================================================
Function : perf_start_imeter
Purpose : Forces meter with number iMeter to begin count by remembering
the current data of timer;
the meter must be previously created
Returns : iMeter if OK, -1 if no such meter
======================================================================*/
int perf_start_imeter(const int iMeter)
//===================================================================================================
void StopwatchStorage::print(const std::string& theName, std::string& theOutput) const
{
if (iMeter >= 0 && iMeter < nb_meters)
auto it = myStopwatches.find(theName);
if (it == myStopwatches.end())
{
PICK_TIME(MeterTable[iMeter].start_time)
return iMeter;
return;
}
return -1;
}
/*======================================================================
Function : perf_stop_meter
Purpose : Forces meter MeterName to stop and cumulate time elapsed
since start
Returns : iMeter if OK, -1 if no such meter or it is has not been started
======================================================================*/
int perf_stop_meter(const char* const MeterName)
{
const int ic = find_meter(MeterName);
if (ic >= 0 && MeterTable[ic].start_time)
if (!it->second.IsActive())
{
t_TimeCounter* const ptc = &MeterTable[ic];
PERF_TIME utime;
PICK_TIME(utime)
ptc->cumul_time += utime - ptc->start_time;
ptc->start_time = 0;
ptc->nb_enter++;
theOutput += "Stopwatch " + theName + " have never been started.\n";
return;
}
return ic;
}
/*======================================================================
Function : perf_stop_imeter
Purpose : Forces meter with number iMeter to stop and cumulate the time
elapsed since the start
Returns : iMeter if OK, -1 if no such meter or it is has not been started
======================================================================*/
int perf_stop_imeter(const int iMeter)
{
if (iMeter >= 0 && iMeter < nb_meters)
if (it->second.IsRunning())
{
t_TimeCounter* const ptc = &MeterTable[iMeter];
if (ptc->start_time)
{
PERF_TIME utime;
PICK_TIME(utime)
ptc->cumul_time += utime - ptc->start_time;
ptc->start_time = 0;
ptc->nb_enter++;
return iMeter;
}
theOutput += "Warning: Stopwatch " + theName + " is still running.\n";
return;
}
return -1;
theOutput += "Stopwatch " + theName + ": " + std::to_string(it->second.Elapsed()) + " sec\n";
}
/*======================================================================
Function : perf_get_meter
Purpose : Tells the time cumulated by meter MeterName and the number
of enters to this meter
Output : *nb_enter, *seconds if the pointers != NULL
Returns : iMeter if OK, -1 if no such meter
======================================================================*/
int perf_get_meter(const char* const MeterName, int* nb_enter, double* seconds)
{
const int ic = find_meter(MeterName);
//==================================================================================================
if (ic >= 0)
OSD_PerfMeter::OSD_PerfMeter(const TCollection_AsciiString& theMeterName, const bool theToAutoStart)
{
Init(theMeterName);
if (theToAutoStart)
{
if (nb_enter)
*nb_enter = MeterTable[ic].nb_enter;
if (seconds)
*seconds = MeterTable[ic].cumul_time;
Start();
}
return ic;
}
/*======================================================================
Function : perf_print_all_meters
Purpose : Prints on stdout the cumulated time and the number of
enters for each meter in MeterTable;
resets all meters if reset is non-null
======================================================================*/
void perf_print_all_meters(int reset)
{
char buffer[MAX_METERS * 256];
perf_sprint_all_meters(buffer, MAX_METERS * 256, reset);
printf("%s", buffer);
}
//==================================================================================================
/*======================================================================
Function : perf_print_all_meters
Purpose : Prints to string buffer the cumulated time and the number of
enters for each meter in MeterTable;
resets all meters if reset is non-null
======================================================================*/
void perf_sprint_all_meters(char* buffer, int length, int reset)
{
char string[256];
OSD_PerfMeter::~OSD_PerfMeter() {}
int i;
for (i = 0; i < nb_meters; i++)
//==================================================================================================
void OSD_PerfMeter::Init(const TCollection_AsciiString& theMeterName)
{
myMeterName = theMeterName;
if (!StopwatchStorage::Instance().HasStopwatch(myMeterName.ToCString()))
{
const t_TimeCounter* const ptc = &MeterTable[i];
if (ptc && ptc->nb_enter)
{
int n =
sprintf(string,
" Perf meter results : enters seconds microsec/enter\n");
if (n < length)
{
memcpy(buffer, string, n);
buffer += n;
length -= n;
}
break;
}
StopwatchStorage::Instance().CreateStopwatch(myMeterName.ToCString());
}
}
while (i < nb_meters)
//==================================================================================================
void OSD_PerfMeter::Start() const
{
Stopwatch* aStopwatch = StopwatchStorage::Instance().GetStopwatch(myMeterName.ToCString());
if (aStopwatch != nullptr)
{
t_TimeCounter* const ptc = &MeterTable[i++];
if (ptc && ptc->nb_enter)
{
const double secs = ptc->cumul_time;
int n = 0;
if (ptc->start_time)
n = sprintf(string, "Warning : meter %42s has not been stopped\n", ptc->name);
n += sprintf(string + n,
"%-42s : %7d %8.2f %10.2f\n",
ptc->name,
ptc->nb_enter,
secs,
(secs > 0. ? 1000000 * secs / ptc->nb_enter : 0.));
if (n < length)
{
memcpy(buffer, string, n);
buffer += n;
length -= n;
}
if (reset)
{
ptc->cumul_time = 0;
ptc->start_time = 0;
ptc->nb_enter = 0;
}
}
aStopwatch->Start();
}
*buffer = '\0';
}
/*======================================================================
Function : perf_close_meter
Purpose : Prints out a meter and resets it
Returns : none
======================================================================*/
void perf_close_meter(const char* const MeterName)
{
perf_close_imeter(find_meter(MeterName));
}
//==================================================================================================
/*======================================================================
Function : perf_close_imeter
Purpose : Prints out a meter and resets it
Returns : none
======================================================================*/
void perf_close_imeter(const int iMeter)
void OSD_PerfMeter::Stop() const
{
if (iMeter >= 0 && iMeter < nb_meters && MeterTable[iMeter].nb_enter)
Stopwatch* aStopwatch = StopwatchStorage::Instance().GetStopwatch(myMeterName.ToCString());
if (aStopwatch != nullptr)
{
t_TimeCounter* const ptc = &MeterTable[iMeter];
if (ptc->start_time)
printf(" ===> Warning : meter %s has not been stopped\n", ptc->name);
printf(" ===> [%s] : %d enters, %9.3f seconds\n", ptc->name, ptc->nb_enter, ptc->cumul_time);
ptc->cumul_time = 0;
ptc->start_time = 0;
ptc->nb_enter = 0;
aStopwatch->Stop();
}
}
/*======================================================================
Function : perf_destroy_all_meters
Purpose : Deletes all meters and frees memory
Returns : none
======================================================================*/
void perf_destroy_all_meters(void)
//==================================================================================================
double OSD_PerfMeter::Elapsed() const
{
int i;
for (i = 0; i < nb_meters; i++)
free(MeterTable[i].name);
nb_meters = 0;
Stopwatch* aStopwatch = StopwatchStorage::Instance().GetStopwatch(myMeterName.ToCString());
return aStopwatch ? aStopwatch->Elapsed() : 0.0;
}
/* agv - non portable: #pragma fini (perf_print_and_destroy)
using atexit instead (see _perf_init_meter below) */
//==================================================================================================
void perf_print_and_destroy(void)
void OSD_PerfMeter::Kill() const
{
perf_print_all_meters(0);
perf_destroy_all_meters();
StopwatchStorage::Instance().KillStopwatch(myMeterName.ToCString());
}
/*======================================================================
Function : _perf_init_meter
Purpose : Creates new counter (if it is absent) identified by
MeterName and resets its cumulative value
Returns : index of meter if OK, -1 if alloc problem
Remarks : For internal use in this module
======================================================================*/
static int _perf_init_meter(const char* const MeterName, const int doFind)
{
static int hasbeencalled = 0;
int ic = -1;
if (doFind)
ic = find_meter(MeterName);
//==================================================================================================
if (ic == -1)
TCollection_AsciiString OSD_PerfMeter::Print() const
{
Stopwatch* aStopwatch = StopwatchStorage::Instance().GetStopwatch(myMeterName.ToCString());
if (aStopwatch != nullptr)
{
if (nb_meters >= MAX_METERS)
return 0;
ic = nb_meters;
MeterTable[ic].name = strdup(MeterName);
if (!MeterTable[ic].name)
return -1;
nb_meters++;
const std::string anOutput = StopwatchStorage::Instance().Print(myMeterName.ToCString());
return anOutput.c_str();
}
MeterTable[ic].cumul_time = 0;
MeterTable[ic].start_time = 0;
MeterTable[ic].nb_enter = 0;
if (hasbeencalled == 0)
{
atexit(perf_print_and_destroy);
hasbeencalled = ~0;
}
return ic;
return "";
}
/*======================================================================
Function : find_meter
Purpose : Finds the meter MeterName in the MeterTable
Returns : Index of meter object, -1 if not found
Remarks : For internal use in this module
======================================================================*/
static int find_meter(const char* const MeterName)
//==================================================================================================
TCollection_AsciiString OSD_PerfMeter::PrintALL()
{
int i;
for (i = 0; i < nb_meters; i++)
if (!strcmp(MeterTable[i].name, MeterName))
return i;
return -1;
const std::string anOutput = StopwatchStorage::Instance().PrintAll();
return anOutput.c_str();
}
//==================================================================================================
void OSD_PerfMeter::ResetALL()
{
StopwatchStorage::Instance().Clear();
}

View File

@ -1,182 +0,0 @@
/*
Copyright (c) 1999-2014 OPEN CASCADE SAS
This file is part of Open CASCADE Technology software library.
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License version 2.1 as published
by the Free Software Foundation, with special exception defined in the file
OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
distribution for complete text of the license and disclaimer of any warranty.
Alternatively, this file may be used under the terms of Open CASCADE
commercial license or contractual agreement.
*/
#ifndef _OSD_PERFMETER_H
#define _OSD_PERFMETER_H
/**
* Macros for convenient and fast usage of meters.
* Define PERF_ENABLE_METERS to make them available.
*/
#ifdef PERF_ENABLE_METERS
/**
* @def PERF_START_METER(theMeterName)
* Forces meter MeterName to begin to count by remembering the current data of timer.
* Creates new meter if there is no such meter.
*/
#define PERF_START_METER(_m_name) \
{ \
static int __iMeter = -1; \
if (__iMeter >= 0) \
perf_start_imeter(__iMeter); \
else \
__iMeter = perf_start_meter(_m_name); \
}
/**
* @def PERF_STOP_METER(theMeterName)
* Forces meter MeterName to stop and cumulate the time elapsed since the start.
*/
#define PERF_STOP_METER(_m_name) \
{ \
static int __iMeter = -1; \
if (__iMeter >= 0) \
perf_stop_imeter(__iMeter); \
else \
__iMeter = perf_stop_meter(_m_name); \
}
/**
* @def PERF_TICK_METER(theMeterName)
* Increments the counter of meter MeterName without changing its state with respect to
* measurement of time. Creates new meter if there is no such meter. It is useful to count the
* number of enters to a part of code without wasting a time to measure CPU time.
*/
#define PERF_TICK_METER(_m_name) \
{ \
static int __iMeter = -1; \
if (__iMeter >= 0) \
perf_tick_imeter(__iMeter); \
else \
__iMeter = perf_tick_meter(_m_name); \
}
/**
* @def PERF_CLOSE_METER(theMeterName)
* Prints out and resets the given meter.
*/
#define PERF_CLOSE_METER(_m_name) perf_close_meter(_m_name);
/**
* @def PERF_PRINT_ALL
* Prints all existing meters which have been entered at least once and resets them.
*/
#define PERF_PRINT_ALL() \
{ \
perf_print_all_meters(1); \
}
#else
#define PERF_TICK_METER(_m_name)
#define PERF_START_METER(_m_name)
#define PERF_STOP_METER(_m_name)
#define PERF_CLOSE_METER(_m_name)
#define PERF_PRINT_ALL()
#endif
/**
* Creates new counter (if it is absent) identified by theMeterName and resets its cumulative value
* @return meter global identifier if OK, -1 if alloc problem
*/
Standard_EXPORTEXTERNC int perf_init_meter(const char* const theMeterName);
/**
* Forces meter theMeterName to begin to count by remembering the current data of timer.
* Creates new meter if there is no such meter.
* @return meter global identifier if OK, -1 if no such meter and cannot create a new one
*/
Standard_EXPORTEXTERNC int perf_start_meter(const char* const theMeterName);
/**
* Forces meter with number theMeterId to begin count by remembering the current data of timer.
* @return meter global identifier if OK, -1 if no such meter
*/
Standard_EXPORTEXTERNC int perf_start_imeter(const int theMeterId);
/**
* Forces meter theMeterName to stop and cumulate the time elapsed since the start.
* @return meter global identifier if OK, -1 if no such meter or it is has not been started
*/
Standard_EXPORTEXTERNC int perf_stop_meter(const char* const theMeterName);
/**
* Forces meter with number theMeterId to stop and cumulate the time elapsed since the start.
* @return meter global identifier if OK, -1 if no such meter or it is has not been started
*/
Standard_EXPORTEXTERNC int perf_stop_imeter(const int theMeterId);
/**
* Increments the counter of meter theMeterName without changing its state with respect to
* measurement of time. Creates new meter if there is no such meter.
* @return meter global identifier if OK, -1 if no such meter and cannot create a new one
*/
Standard_EXPORTEXTERNC int perf_tick_meter(const char* const theMeterName);
/**
* Increments the counter of meter theMeterId without changing its state with respect to measurement
* of time.
* @return meter global identifier if OK, -1 if no such meter
*/
Standard_EXPORTEXTERNC int perf_tick_imeter(const int theMeterId);
/**
* Tells the time cumulated by meter theMeterName and the number of enters to this meter.
* @param theNbEnter [OUT] number of enters if the pointer != NULL
* @param theSeconds [OUT] seconds if the pointer != NULL
* @return meter global identifier if OK, -1 if no such meter
*/
Standard_EXPORTEXTERNC int perf_get_meter(const char* const theMeterName,
int* theNbEnter,
double* theSeconds);
/**
* Prints on stdout the cumulated time and the number of enters for the specified meter.
*/
Standard_EXPORTEXTERNC void perf_close_meter(const char* const theMeterName);
/**
* Prints on stdout the cumulated time and the number of enters for the specified meter.
*/
Standard_EXPORTEXTERNC void perf_close_imeter(const int theMeterId);
/**
* Prints on stdout the cumulated time and the number of enters for each alive meter which have the
* number of enters > 0. Resets all meters if reset is non-null.
*/
Standard_EXPORTEXTERNC void perf_print_all_meters(int reset);
/**
* Prints to supplied string buffer the cumulated time and the number of enters
* for each alive meter with the number of enters > 0.
* If buffer length is not sufficient, data of some meters may be lost.
* It is recommended to reserve 256 bytes per meter, 25600 bytes should fit all.
* Resets all meters.
*/
Standard_EXPORTEXTERNC void perf_sprint_all_meters(char* buffer, int length, int reset);
/**
* Deletes all meters and frees memory.
*/
Standard_EXPORTEXTERNC void perf_destroy_all_meters(void);
/**
* ATTENTION!!!
* This func calls perf_print_all_meters() and perf_destroy_all_meters()
* and is called automatically at the end of a program via system call atexit().
*/
Standard_EXPORTEXTERNC void perf_print_and_destroy(void);
#endif

View File

@ -16,7 +16,8 @@
#ifndef OSD_PerfMeter_HeaderFile
#define OSD_PerfMeter_HeaderFile
#include <OSD_PerfMeter.h>
#include <Standard_Macro.hxx>
#include <TCollection_AsciiString.hxx>
//! This class enables measuring the CPU time between two points of code execution, regardless of
//! the scope of these points of code. A meter is identified by its name (string). So multiple
@ -24,57 +25,53 @@
//! on stdout upon finish of the program. For details see OSD_PerfMeter.h
class OSD_PerfMeter
{
public:
//! Constructs a void meter (to further call Init and Start)
OSD_PerfMeter()
: myIMeter(-1)
{
}
//! Constructs a void meter (to further call Init and Start).
Standard_EXPORT OSD_PerfMeter() = default;
//! Constructs and starts (if autoStart is true) the named meter
OSD_PerfMeter(const char* theMeter, const bool theToAutoStart = true)
: myIMeter(perf_get_meter(theMeter, 0, 0))
{
if (myIMeter < 0)
myIMeter = perf_init_meter(theMeter);
if (theToAutoStart)
Start();
}
//! Constructs and starts (if autoStart is true) the named meter.
//! @param theMeterName Name of the meter. If the meter with such name was already created,
//! and hasn't been killed, it will be used.
//! @param theToAutoStart If true, the meter will be started immediately after creation.
//! Otherwise, the user should call Start() method to start the meter.
//! Note that if meter already exists, theToAutoStart == true will reset it.
Standard_EXPORT OSD_PerfMeter(const TCollection_AsciiString& theMeterName,
const bool theToAutoStart = true);
//! Prepares the named meter
void Init(const char* theMeter)
{
myIMeter = perf_get_meter(theMeter, 0, 0);
if (myIMeter < 0)
myIMeter = perf_init_meter(theMeter);
}
//! Destructs this meter handler. Note that the meter itself is not destructed
//! and will be printed on stdout upon finish of the program. The meter with the name
//! Specified in the constructor can still be used in other places of the code.
Standard_EXPORT ~OSD_PerfMeter();
//! Starts the meter
void Start() const { perf_start_imeter(myIMeter); }
//! Prepares the named meter. If the meter with such name was already created,
//! it will be used. Otherwise, a new meter will be created.
Standard_EXPORT void Init(const TCollection_AsciiString& theMeterName);
//! Stops the meter
void Stop() const { perf_stop_imeter(myIMeter); }
//! Starts the meter. If the meter was already started, it will be reset.
//! Note that the meter with the name specified in the constructor can still be used
//! in other places of the code.
Standard_EXPORT void Start() const;
//! Increments the counter w/o time measurement
void Tick() const { perf_tick_imeter(myIMeter); }
//! Stops the meter.
Standard_EXPORT void Stop() const;
//! Outputs the meter data and resets it to initial state
void Flush() const { perf_close_imeter(myIMeter); }
//! Returns the elapsed time in seconds since the meter was started.
Standard_EXPORT double Elapsed() const;
//! Assures stopping upon destruction
~OSD_PerfMeter()
{
if (myIMeter >= 0)
Stop();
}
//! Outputs the meter data and resets it to initial state.
Standard_EXPORT void Kill() const;
//! Prints the data of this meter.
Standard_EXPORT TCollection_AsciiString Print() const;
//! Prints the data of all meters with non-zero elapsed time.
Standard_EXPORT static TCollection_AsciiString PrintALL();
//! Resets all meters.
Standard_EXPORT static void ResetALL();
private:
OSD_PerfMeter(const OSD_PerfMeter&);
OSD_PerfMeter& operator=(const OSD_PerfMeter&);
protected:
int myIMeter;
TCollection_AsciiString myMeterName;
};
#endif // OSD_PerfMeter_HeaderFile

View File

@ -1,11 +0,0 @@
puts "============"
puts "CR23237"
puts "==========="
puts ""
################################################
# Bug in OSD_PerfMeter
################################################
pload QAcommands
OCC23237