mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-04-03 17:56:21 +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:
parent
7d3225b51a
commit
6b55f8e398
@ -28,24 +28,24 @@ IMPLEMENT_STANDARD_RTTIEXT(Draw_ProgressIndicator,Message_ProgressIndicator)
|
||||
//function : Draw_ProgressIndicator
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
Draw_ProgressIndicator::Draw_ProgressIndicator(const Draw_Interpretor &di,
|
||||
const Standard_Integer updateTime) :
|
||||
myTextMode ( DefaultTextMode() ),
|
||||
myGraphMode ( DefaultGraphMode() ),
|
||||
myDraw ( (Standard_Address)&di ),
|
||||
myShown ( Standard_False ),
|
||||
myBreak ( Standard_False ),
|
||||
myUpdateTime ( updateTime ),
|
||||
myLastUpdate ( 0 ), myStartTime ( 0 )
|
||||
Draw_ProgressIndicator::Draw_ProgressIndicator (const Draw_Interpretor &di, Standard_Real theUpdateThreshold)
|
||||
: myTextMode ( DefaultTextMode() ),
|
||||
myGraphMode ( DefaultGraphMode() ),
|
||||
myDraw ( (Standard_Address)&di ),
|
||||
myShown ( Standard_False ),
|
||||
myBreak ( Standard_False ),
|
||||
myUpdateThreshold ( 0.01 * theUpdateThreshold ),
|
||||
myLastPosition ( -1. ),
|
||||
myStartTime ( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : Destroy
|
||||
//function : ~Draw_ProgressIndicator
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
|
||||
void Draw_ProgressIndicator::Destroy()
|
||||
Draw_ProgressIndicator::~Draw_ProgressIndicator()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
@ -63,7 +63,8 @@ void Draw_ProgressIndicator::Reset()
|
||||
myShown = 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)
|
||||
{
|
||||
if ( ! myGraphMode && ! myTextMode ) return Standard_False;
|
||||
time_t aTimeT;
|
||||
time ( &aTimeT );
|
||||
Standard_Size aTime = (Standard_Size)aTimeT;
|
||||
if ( ! myStartTime ) myStartTime = aTime;
|
||||
if ( ! force && myUpdateTime >0 && aTime < myLastUpdate + myUpdateTime && GetPosition() < 1. )
|
||||
if ( ! myGraphMode && ! myTextMode )
|
||||
return Standard_False;
|
||||
|
||||
// remember time of the first call to Show as process start time
|
||||
if ( ! myStartTime )
|
||||
{
|
||||
time_t aTimeT;
|
||||
time ( &aTimeT );
|
||||
myStartTime = (Standard_Size)aTimeT;
|
||||
}
|
||||
|
||||
// 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
|
||||
myLastUpdate = aTime;
|
||||
myLastPosition = aPosition;
|
||||
|
||||
// Prepare textual progress info
|
||||
char text[2048];
|
||||
@ -100,14 +109,18 @@ Standard_Boolean Draw_ProgressIndicator::Show(const Standard_Boolean force)
|
||||
scale.BaseToLocal ( locPos ), scale.GetMax() );
|
||||
}
|
||||
|
||||
// In addition, write elapsed/estimated/remaining time
|
||||
if ( GetPosition() > 0.01 ) {
|
||||
n += Sprintf ( &text[n], "\nElapsed/estimated time: %ld/%.0f sec",
|
||||
(long)(aTime - myStartTime), ( aTime - myStartTime ) / GetPosition() );
|
||||
}
|
||||
|
||||
// Show graphic progress bar
|
||||
if ( myGraphMode ) {
|
||||
|
||||
// In addition, write elapsed/estimated/remaining time
|
||||
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",
|
||||
(long)(aTime - myStartTime), ( aTime - myStartTime ) / GetPosition() );
|
||||
}
|
||||
|
||||
if ( ! myShown ) {
|
||||
char command[1024];
|
||||
Sprintf ( command, "toplevel .xprogress -height 100 -width 410;"
|
||||
|
@ -33,18 +33,15 @@ class Draw_ProgressIndicator : public Message_ProgressIndicator
|
||||
public:
|
||||
|
||||
|
||||
//! Creates a progress indicator and remembers pointer to
|
||||
//! Draw_Interpretor
|
||||
//! The updateTime, if given, defines time interval between
|
||||
//! updates of the indicator (in seconds)
|
||||
Standard_EXPORT Draw_ProgressIndicator(const Draw_Interpretor& di, const Standard_Integer updateTime = 0);
|
||||
//! Creates a progress indicator and remembers pointer to Draw_Interpretor
|
||||
//!
|
||||
//! @param theUpdateThreshold defines minimal progress (in percents) between
|
||||
//! updates of the indicator (non-forced updates of the progress bar will be
|
||||
//! disabled until that progress is reached since last update).
|
||||
Standard_EXPORT Draw_ProgressIndicator(const Draw_Interpretor& di, Standard_Real theUpdateThreshold = 1.);
|
||||
|
||||
//! Destructor; calls Reset()
|
||||
Standard_EXPORT void Destroy();
|
||||
~Draw_ProgressIndicator()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
Standard_EXPORT ~Draw_ProgressIndicator();
|
||||
|
||||
//! Sets text output mode (on/off)
|
||||
Standard_EXPORT void SetTextMode (const Standard_Boolean theTextMode);
|
||||
@ -85,8 +82,8 @@ private:
|
||||
Standard_Address myDraw;
|
||||
Standard_Boolean myShown;
|
||||
Standard_Boolean myBreak;
|
||||
Standard_Integer myUpdateTime;
|
||||
Standard_Size myLastUpdate;
|
||||
Standard_Real myUpdateThreshold;
|
||||
Standard_Real myLastPosition;
|
||||
Standard_Size myStartTime;
|
||||
};
|
||||
|
||||
|
@ -33,50 +33,45 @@ class Message_ProgressIndicator;
|
||||
DEFINE_STANDARD_HANDLE(Message_ProgressIndicator, Standard_Transient)
|
||||
|
||||
//! 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
|
||||
//! for each range and step can be defined by the program that uses it.
|
||||
//! The process that uses the progress indicator interacts with it as
|
||||
//! 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
|
||||
//! non-linearly, end of scale will be approached asymptotically at
|
||||
//! infinite number of steps. In that case value of scale range
|
||||
//! gives a number of steps corresponding to position at 1/2 of scale.
|
||||
//! non-linearly, and end of scale will be approached asymptotically at
|
||||
//! infinite number of steps. In that case the range defines
|
||||
//! a number of steps corresponding to position at 1/2 of scale.
|
||||
//! The current position can be either set directly (in a range from
|
||||
//! current position to maximum scale value), or incremented step
|
||||
//! by step.
|
||||
//!
|
||||
//! Progress indication mechanism is adapted for convenient
|
||||
//! 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
|
||||
//! 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.
|
||||
//! When subprocess works with progress indicator in the restricted
|
||||
//! scope, it has the same interface to a scale, while actually it
|
||||
//! 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:
|
||||
//! Currently there is no support for concurrent progress
|
||||
//! 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
|
||||
//! return True in case if break signal from the user is obtained.
|
||||
//! The user break is implemented as virtual function that should
|
||||
//! 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,
|
||||
//! and/or print all scopes in text mode), and for implementation
|
||||
//! of user break mechanism (if defined).
|
||||
//! print scopes in text mode, or else), and for implementation
|
||||
//! of user break mechanism (if necessary).
|
||||
|
||||
class Message_ProgressIndicator : public Standard_Transient
|
||||
{
|
||||
|
||||
|
@ -37,6 +37,25 @@ class TCollection_HAsciiString;
|
||||
//! check for user break
|
||||
//! - Automatic scope closing in destructor
|
||||
//! - 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
|
||||
{
|
||||
public:
|
||||
|
@ -205,7 +205,7 @@ void OSD_Chronometer::Reset ()
|
||||
//=======================================================================
|
||||
void OSD_Chronometer::Restart ()
|
||||
{
|
||||
Stopped = Standard_True;
|
||||
Reset();
|
||||
Start();
|
||||
}
|
||||
|
||||
|
@ -4791,6 +4791,30 @@ Standard_Integer CR23403 (Draw_Interpretor& di, Standard_Integer argc, const cha
|
||||
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) {
|
||||
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("CR23403", "CR23403 string", __FILE__, CR23403, 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;
|
||||
}
|
||||
|
@ -116,7 +116,8 @@ static Standard_Integer readstl(Draw_Interpretor& theDI,
|
||||
strcmp("triangulation", theArgv[3]) == 0)
|
||||
{
|
||||
// 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;
|
||||
BRep_Builder aB;
|
||||
|
24
tests/bugs/fclasses/bug28478
Normal file
24
tests/bugs/fclasses/bug28478
Normal 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 ""
|
||||
}
|
10
tests/perf/fclasses/progress
Normal file
10
tests/perf/fclasses/progress
Normal 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"
|
Loading…
x
Reference in New Issue
Block a user