0028478: Scope Names Are Swallowed in Message_ProgressSentry Constructors
authorabv <abv@opencascade.com>
Fri, 18 Aug 2017 12:05:34 +0000 (15:05 +0300)
committerbugmaster <bugmaster@opencascade.com>
Wed, 30 Aug 2017 10:52:33 +0000 (13:52 +0300)
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.

src/Draw/Draw_ProgressIndicator.cxx
src/Draw/Draw_ProgressIndicator.hxx
src/Message/Message_ProgressIndicator.hxx
src/Message/Message_ProgressSentry.hxx
src/OSD/OSD_Chronometer.cxx
src/QABugs/QABugs_11.cxx
src/XSDRAWSTLVRML/XSDRAWSTLVRML.cxx
tests/bugs/fclasses/bug28478 [new file with mode: 0644]
tests/perf/fclasses/progress [new file with mode: 0644]

index 2734d9951fdd4b599256a1e9a9e93a46fd764dee..0b55eb74efd32a0a9c70d1a87b2f94ebebc66aec 100644 (file)
@@ -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;"
index f176e5298f98686733ed6d5bc88248e2c7fab2e7..bfb6710e4dfa6de269478d01e773579d9bc7fc05 100644 (file)
@@ -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;
 };
 
index 369fed93b0f2be3396d368d83f1208f250d80171..a9d90e2b487a7a2e69ba73f44511b07939f50bba 100644 (file)
@@ -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
 {
 
index f8114d7bd2f727d36c38e32fc99daf47c1aa68a3..0e7a094a5dcbc3ae0502ac1b8a0ba49df43ad728 100644 (file)
@@ -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:
index 73738dffac8fe8b3bbdd2908d830ffec0a64ef55..699e9c2e11f4ca30b8841a71b23fc5b2320e3d94 100644 (file)
@@ -205,7 +205,7 @@ void OSD_Chronometer::Reset ()
 //=======================================================================
 void OSD_Chronometer::Restart ()
 {
-  Stopped = Standard_True;
+  Reset();
   Start();
 }
 
index 78b24ce41250d5f6e7d71afe303542ff9b20b1a8..f432ca06c00992765c780b7281ead02e02ac7bd5 100644 (file)
@@ -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;
 }
index 22197809fbbe9dec0e11dc1fe2ea75a7d48a892e..fe5fe0e138486c8673e7552908ca70932fd655e1 100644 (file)
@@ -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;
diff --git a/tests/bugs/fclasses/bug28478 b/tests/bugs/fclasses/bug28478
new file mode 100644 (file)
index 0000000..513f3f9
--- /dev/null
@@ -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 ""
+}
\ No newline at end of file
diff --git a/tests/perf/fclasses/progress b/tests/perf/fclasses/progress
new file mode 100644 (file)
index 0000000..1c8df5e
--- /dev/null
@@ -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"