1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-21 10:13:43 +03:00

0028478: Scope Names Are Swallowed in Message_ProgressSentry Constructors

Tests are added to control output and performance of progress indicator (bugs fclasses bug28478 and perf fclasses progress, respectively).

Implementation of class Draw_ProgressIndicator is improved to update indicator basing on achieved total progress (1% by default) instead of elapsed time since last update.

Method OSD_Chronometer::Restart() is fixed to actually reset the counter.

DRAW command readstl is improved to show progress indicator if configured (by command XProgress).

Description of class Message_ProgressIndicator is updated; code example is added in description of Message_ProgressSentry.
This commit is contained in:
abv 2017-08-18 15:05:34 +03:00 committed by bugmaster
parent 7d3225b51a
commit 6b55f8e398
9 changed files with 147 additions and 63 deletions

View File

@ -28,24 +28,24 @@ IMPLEMENT_STANDARD_RTTIEXT(Draw_ProgressIndicator,Message_ProgressIndicator)
//function : Draw_ProgressIndicator //function : Draw_ProgressIndicator
//purpose : //purpose :
//======================================================================= //=======================================================================
Draw_ProgressIndicator::Draw_ProgressIndicator(const Draw_Interpretor &di, Draw_ProgressIndicator::Draw_ProgressIndicator (const Draw_Interpretor &di, Standard_Real theUpdateThreshold)
const Standard_Integer updateTime) : : myTextMode ( DefaultTextMode() ),
myTextMode ( DefaultTextMode() ),
myGraphMode ( DefaultGraphMode() ), myGraphMode ( DefaultGraphMode() ),
myDraw ( (Standard_Address)&di ), myDraw ( (Standard_Address)&di ),
myShown ( Standard_False ), myShown ( Standard_False ),
myBreak ( Standard_False ), myBreak ( Standard_False ),
myUpdateTime ( updateTime ), myUpdateThreshold ( 0.01 * theUpdateThreshold ),
myLastUpdate ( 0 ), myStartTime ( 0 ) myLastPosition ( -1. ),
myStartTime ( 0 )
{ {
} }
//======================================================================= //=======================================================================
//function : Destroy //function : ~Draw_ProgressIndicator
//purpose : //purpose :
//======================================================================= //=======================================================================
void Draw_ProgressIndicator::Destroy() Draw_ProgressIndicator::~Draw_ProgressIndicator()
{ {
Reset(); Reset();
} }
@ -63,7 +63,8 @@ void Draw_ProgressIndicator::Reset()
myShown = Standard_False; myShown = Standard_False;
} }
myBreak = Standard_False; myBreak = Standard_False;
myLastUpdate = myStartTime = 0; myLastPosition = -1.;
myStartTime = 0;
} }
//======================================================================= //=======================================================================
@ -73,14 +74,22 @@ void Draw_ProgressIndicator::Reset()
Standard_Boolean Draw_ProgressIndicator::Show(const Standard_Boolean force) Standard_Boolean Draw_ProgressIndicator::Show(const Standard_Boolean force)
{ {
if ( ! myGraphMode && ! myTextMode ) return Standard_False; if ( ! myGraphMode && ! myTextMode )
return Standard_False;
// remember time of the first call to Show as process start time
if ( ! myStartTime )
{
time_t aTimeT; time_t aTimeT;
time ( &aTimeT ); time ( &aTimeT );
Standard_Size aTime = (Standard_Size)aTimeT; myStartTime = (Standard_Size)aTimeT;
if ( ! myStartTime ) myStartTime = aTime; }
if ( ! force && myUpdateTime >0 && aTime < myLastUpdate + myUpdateTime && GetPosition() < 1. )
// unless show is forced, show updated state only if at least 1% progress has been reached since the last update
Standard_Real aPosition = GetPosition();
if ( ! force && aPosition < 1. && Abs (aPosition - myLastPosition) < myUpdateThreshold)
return Standard_False; // return if update interval has not elapsed return Standard_False; // return if update interval has not elapsed
myLastUpdate = aTime; myLastPosition = aPosition;
// Prepare textual progress info // Prepare textual progress info
char text[2048]; char text[2048];
@ -100,14 +109,18 @@ Standard_Boolean Draw_ProgressIndicator::Show(const Standard_Boolean force)
scale.BaseToLocal ( locPos ), scale.GetMax() ); scale.BaseToLocal ( locPos ), scale.GetMax() );
} }
// Show graphic progress bar
if ( myGraphMode ) {
// In addition, write elapsed/estimated/remaining time // In addition, write elapsed/estimated/remaining time
if ( GetPosition() > 0.01 ) { if ( GetPosition() > 0.01 ) {
time_t aTimeT;
time ( &aTimeT );
Standard_Size aTime = (Standard_Size)aTimeT;
n += Sprintf ( &text[n], "\nElapsed/estimated time: %ld/%.0f sec", n += Sprintf ( &text[n], "\nElapsed/estimated time: %ld/%.0f sec",
(long)(aTime - myStartTime), ( aTime - myStartTime ) / GetPosition() ); (long)(aTime - myStartTime), ( aTime - myStartTime ) / GetPosition() );
} }
// Show graphic progress bar
if ( myGraphMode ) {
if ( ! myShown ) { if ( ! myShown ) {
char command[1024]; char command[1024];
Sprintf ( command, "toplevel .xprogress -height 100 -width 410;" Sprintf ( command, "toplevel .xprogress -height 100 -width 410;"

View File

@ -33,18 +33,15 @@ class Draw_ProgressIndicator : public Message_ProgressIndicator
public: public:
//! Creates a progress indicator and remembers pointer to //! Creates a progress indicator and remembers pointer to Draw_Interpretor
//! Draw_Interpretor //!
//! The updateTime, if given, defines time interval between //! @param theUpdateThreshold defines minimal progress (in percents) between
//! updates of the indicator (in seconds) //! updates of the indicator (non-forced updates of the progress bar will be
Standard_EXPORT Draw_ProgressIndicator(const Draw_Interpretor& di, const Standard_Integer updateTime = 0); //! disabled until that progress is reached since last update).
Standard_EXPORT Draw_ProgressIndicator(const Draw_Interpretor& di, Standard_Real theUpdateThreshold = 1.);
//! Destructor; calls Reset() //! Destructor; calls Reset()
Standard_EXPORT void Destroy(); Standard_EXPORT ~Draw_ProgressIndicator();
~Draw_ProgressIndicator()
{
Destroy();
}
//! Sets text output mode (on/off) //! Sets text output mode (on/off)
Standard_EXPORT void SetTextMode (const Standard_Boolean theTextMode); Standard_EXPORT void SetTextMode (const Standard_Boolean theTextMode);
@ -85,8 +82,8 @@ private:
Standard_Address myDraw; Standard_Address myDraw;
Standard_Boolean myShown; Standard_Boolean myShown;
Standard_Boolean myBreak; Standard_Boolean myBreak;
Standard_Integer myUpdateTime; Standard_Real myUpdateThreshold;
Standard_Size myLastUpdate; Standard_Real myLastPosition;
Standard_Size myStartTime; Standard_Size myStartTime;
}; };

View File

@ -33,50 +33,45 @@ class Message_ProgressIndicator;
DEFINE_STANDARD_HANDLE(Message_ProgressIndicator, Standard_Transient) DEFINE_STANDARD_HANDLE(Message_ProgressIndicator, Standard_Transient)
//! Defines abstract interface from program to the "user". //! Defines abstract interface from program to the "user".
//! That includes progress indication and user break mechanisms //! This includes progress indication and user break mechanisms.
//! //!
//! The interface to progress indicator represents it as a scale //! The process that uses the progress indicator interacts with it as
//! for each range and step can be defined by the program that uses it. //! with a scale whose range and step can be configured according to
//! the nature of the process.
//! The scale can be made "infinite", which means it will grow //! The scale can be made "infinite", which means it will grow
//! non-linearly, end of scale will be approached asymptotically at //! non-linearly, and end of scale will be approached asymptotically at
//! infinite number of steps. In that case value of scale range //! infinite number of steps. In that case the range defines
//! gives a number of steps corresponding to position at 1/2 of scale. //! a number of steps corresponding to position at 1/2 of scale.
//! The current position can be either set directly (in a range from //! The current position can be either set directly (in a range from
//! current position to maximum scale value), or incremented step //! current position to maximum scale value), or incremented step
//! by step. //! by step.
//! //!
//! Progress indication mechanism is adapted for convenient //! Progress indication mechanism is adapted for convenient
//! usage in hiererchical processes that require indication of //! usage in hiererchical processes that require indication of
//! progress at several (sub)levels of the process. //! progress at several levels of the process nesting.
//! For that purpose, it is possible to create restricted sub-scope of //! For that purpose, it is possible to create restricted sub-scope of
//! indication by specifying part of a current scale that is to be //! indication by specifying part of a current scale to be
//! used by the subprocess. //! used by the subprocess.
//! When subprocess works with progress indicator in the restricted //! When subprocess works with progress indicator in the restricted
//! scope, it has the same interface to a scale, while actually it //! scope, it has the same interface to a scale, while actually it
//! deals only with part of the whole scale. //! deals only with part of the whole scale.
//! //!
//! The recommended way to implement progress indication in the algorithm
//! is to use class Message_ProgressSentry that provides iterator-like
//! interface for incrementing progress and opening nested scopes.
//!
//! NOTE: //! NOTE:
//! Currently there is no support for concurrent progress //! Currently there is no support for concurrent progress
//! indicator that could be useful in multithreaded applications. //! indicator that could be useful in multithreaded applications.
//! The main reason for this is that such implementation would be
//! too complex regarding forecasted lack of real need for such
//! support.
//! To support this it would require that ProgressScale keep its
//! own position and take care of incrementing main ProgressIndicator
//! in destructor. This would also require having cross-references
//! between nested instances of ProgressScale, ie. potential
//! problems with memory management.
//! In case of need of concurrent progress indicator two things can
//! be suggested: either creation of single spane with summary number
//! of steps, or usage of infinite scale.
//! //!
//! The user break is implemented as virtual function that might //! The user break is implemented as virtual function that should
//! return True in case if break signal from the user is obtained. //! return True in case if break signal from the user is received.
//! //!
//! The derived classes should take care of visualisation of the //! The derived class should take care of visualisation of the
//! progress indicator (e.g. show total position at the graphical bar, //! progress indicator (e.g. show total position at the graphical bar,
//! and/or print all scopes in text mode), and for implementation //! print scopes in text mode, or else), and for implementation
//! of user break mechanism (if defined). //! of user break mechanism (if necessary).
class Message_ProgressIndicator : public Standard_Transient class Message_ProgressIndicator : public Standard_Transient
{ {

View File

@ -37,6 +37,25 @@ class TCollection_HAsciiString;
//! check for user break //! check for user break
//! - Automatic scope closing in destructor //! - Automatic scope closing in destructor
//! - Safe for NULL ProgressIndicator (just does nothing) //! - Safe for NULL ProgressIndicator (just does nothing)
//!
//! Example of usage in nested process:
//!
//! @code{.cpp}
//! Handle(Draw_ProgressIndicator) aProgress = ...;
//!
//! // Outer cycle
//! Message_ProgressSentry anOuter (aProgress, "Outer", 0, nbOuter, 1);
//! for (int i = 0; i < nbOuter && anOuter.More(); i++, anOuter.Next())
//! {
//! // Inner cycle
//! Message_ProgressSentry anInner (aProgress, "Inner", 0, nbInner, 1);
//! for (int j = 0; j < nbInner && anInner.More(); j++, anInner.Next())
//! {
//! // Cycle body
//! }
//! }
//! @endcode
class Message_ProgressSentry class Message_ProgressSentry
{ {
public: public:

View File

@ -205,7 +205,7 @@ void OSD_Chronometer::Reset ()
//======================================================================= //=======================================================================
void OSD_Chronometer::Restart () void OSD_Chronometer::Restart ()
{ {
Stopped = Standard_True; Reset();
Start(); Start();
} }

View File

@ -4791,6 +4791,30 @@ Standard_Integer CR23403 (Draw_Interpretor& di, Standard_Integer argc, const cha
return 0; return 0;
} }
Standard_Integer OCC28478 (Draw_Interpretor& di, Standard_Integer argc, const char ** argv)
{
Standard_Integer nbOuter = (argc > 1 ? Draw::Atoi(argv[1]) : 3);
Standard_Integer nbInner = (argc > 2 ? Draw::Atoi(argv[2]) : 2);
// test behavior of progress indicator when using nested scopes with names set by Sentry objects
Handle(Draw_ProgressIndicator) aProgress = new Draw_ProgressIndicator (di, 1);
aProgress->SetTextMode (Standard_True);
// Outer cycle
Message_ProgressSentry anOuter (aProgress, "Outer", 0, nbOuter, 1);
for (int i = 0; i < nbOuter && anOuter.More(); i++, anOuter.Next())
{
// Inner cycle
Message_ProgressSentry anInner (aProgress, "Inner", 0, nbInner, 1);
for (int j = 0; j < nbInner && anInner.More(); j++, anInner.Next())
{
// Cycle body
}
}
return 0;
}
void QABugs::Commands_11(Draw_Interpretor& theCommands) { void QABugs::Commands_11(Draw_Interpretor& theCommands) {
const char *group = "QABugs"; const char *group = "QABugs";
@ -4896,5 +4920,6 @@ void QABugs::Commands_11(Draw_Interpretor& theCommands) {
theCommands.Add("OCC22558", "OCC22558 x_vec y_vec z_vec x_dir y_dir z_dit x_pnt y_pnt z_pnt", __FILE__, OCC22558, group); theCommands.Add("OCC22558", "OCC22558 x_vec y_vec z_vec x_dir y_dir z_dit x_pnt y_pnt z_pnt", __FILE__, OCC22558, group);
theCommands.Add("CR23403", "CR23403 string", __FILE__, CR23403, group); theCommands.Add("CR23403", "CR23403 string", __FILE__, CR23403, group);
theCommands.Add("OCC23429", "OCC23429 res shape tool [appr]", __FILE__, OCC23429, group); theCommands.Add("OCC23429", "OCC23429 res shape tool [appr]", __FILE__, OCC23429, group);
theCommands.Add("OCC28478", "OCC28478 [nb_outer=3 [nb_inner=2]: test progress indicator on nested cycles", __FILE__, OCC28478, group);
return; return;
} }

View File

@ -116,7 +116,8 @@ static Standard_Integer readstl(Draw_Interpretor& theDI,
strcmp("triangulation", theArgv[3]) == 0) strcmp("triangulation", theArgv[3]) == 0)
{ {
// Read STL file to the triangulation. // Read STL file to the triangulation.
Handle(Poly_Triangulation) aTriangulation = RWStl::ReadFile (theArgv[2]); Handle(Draw_ProgressIndicator) aProgress = new Draw_ProgressIndicator (theDI, 1);
Handle(Poly_Triangulation) aTriangulation = RWStl::ReadFile (theArgv[2], aProgress);
TopoDS_Face aFace; TopoDS_Face aFace;
BRep_Builder aB; BRep_Builder aB;

View File

@ -0,0 +1,24 @@
puts "# ============"
puts "# 0028478: Scope Names Are Swallowed in Message_ProgressSentry Constructors"
puts "# ============"
puts ""
puts "# Test output of progress indicator in text mode"
pload QAcommands
set out [OCC28478 3 2]
set expected {
{Progress: 0% Outer: 1 / 3}
{Progress: 17% Outer: 1 / 3 Inner: 1 / 2}
{Progress: 33% Outer: 1 / 3 Inner: 2 / 2}
{Progress: 50% Outer: 2 / 3 Inner: 1 / 2}
{Progress: 67% Outer: 2 / 3 Inner: 2 / 2}
{Progress: 83% Outer: 3 / 3 Inner: 1 / 2}
{Progress: 100% Outer: 3 / 3 Inner: 2 / 2}
}
if { [string compare [string trim $out] [join $expected "\n"]] } {
puts "Error: output (see above) does not match expected one:"
puts "[join $expected "\n"]"
puts ""
}

View File

@ -0,0 +1,10 @@
puts "# ========"
puts "# Measure performance of progress indicator on many empty cycles"
puts "# ========"
puts ""
pload QAcommands
chrono s restart
OCC28478 10000 10000
chrono s counter "100 M cycles of progress indicator"