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

0031763: Foundation Classes - reporting of progress within parallel algorithms

Classes Message_ProgressRange and Message_ProgressScope are improved to store start point of the range.
Method Message_ProgressScope::Value() is improved to compute the value in the current scope from the actual current value of the global progress.
Description of Message_ProgressScope class is improved.

Off-topic:
- method Message_ProgressScope::Relieve() is renamed to Close() for semantic consistency
- article in Upgrade Guide is revised and corrected
This commit is contained in:
abv 2020-09-13 19:48:30 +03:00 committed by bugmaster
parent 88610dfc0e
commit 7a3e8aad74
7 changed files with 188 additions and 100 deletions

View File

@ -1935,26 +1935,38 @@ Offset direction, which used in class Adaptor2d_OffsetCurve for evaluating value
Adaptor2d_OffsetCurve aOC(BaseCurve, Offset) --> Adaptor2d_OffsetCurve aOC(BaseCurve, -Offset) Adaptor2d_OffsetCurve aOC(BaseCurve, Offset) --> Adaptor2d_OffsetCurve aOC(BaseCurve, -Offset)
subsection upgrade_750_ProgressIndicator Change of Message_ProgressIndicator @subsection upgrade_750_ProgressIndicator Change of progress indication API
The progress indication mechanism has been revised to eliminate its weak points in previous design (leading to ambiguity and unprotected from an error-prone behavior). The progress indication mechanism has been revised to eliminate its weak points in
Redesign also allows using progress indicator in multi-threaded algorithms in more straight-forward way with minimal overhead. previous design (leading to implementation mistakes).
Note, however, that multi-threaded algorithm should pre-allocate per-thread progress scopes in advance to ensure thread-safety - check new classes API for details. Redesign also allows using progress indicator in multi-threaded algorithms
in more straight-forward way with minimal overhead.
Note however, that multi-threaded algorithm should pre-allocate per-task
progress ranges in advance to ensure thread-safety -
see examples in documentation of class Message_ProgressScope for details.
Classes Message_ProgressSentry and Message_ProgressScale have been removed. Classes Message_ProgressSentry and Message_ProgressScale have been removed.
New classes Message_ProgressScope and Messge_ProgressRange replace them and should be used as main API classes to organize progress indication in the algorithms. New classes Message_ProgressScope and Message_ProgressRange should be used as main
Instances of the class Message_ProgressRange are used to pass the progress capability to nested levels of the algorithm API classes to organize progress indication in the algorithms.
and an instance of the class Message_ProgressScope is to be created (preferably as local variable) to manage progress at each level of the algorithm. Instances of the class Message_ProgressRange are used to pass the progress capability to
nested levels of the algorithm, and an instance of the class Message_ProgressScope is to
be created (preferably as local variable) to manage progress at each level of the algorithm.
The instance of Message_ProgressIndicator is not passed anymore to sub-algorithms. The instance of Message_ProgressIndicator is not passed anymore to sub-algorithms.
See documentation of the class Message_ProgressScope for more details and examples. See documentation of the class Message_ProgressScope for more details and examples.
Methods to deal with progress scopes and to advance progress are removed from class Message_ProgressIndicator; now it only provides interface to the application-level progress indicator. Methods to deal with progress scopes and to advance progress are removed from class
Virtual method Message_ProgressIndicator::Show() has changed its signature and should be updated accordingly in descendants of Message_ProgressIndicator. Message_ProgressIndicator; now it only provides interface to the application-level progress indicator.
The scope passed as argument to this method can be used to obtain information on context of the current process (instead of calling method GetScope() in previous implementation). Virtual method Message_ProgressIndicator::Show() has changed its signature and should be
Methods Show(), UserBreak(), and Reset() are made protected in class Message_ProgressIndicator; method More() of Message_ProgressScope should be used to know if the cancel event has come. updated accordingly in descendants of Message_ProgressIndicator.
See documentation of the class Message_ProgressIndicator for more details and implementation of Draw_ProgressIndicator for an example. The scope passed as argument to this method can be used to obtain information on context
of the current process (instead of calling method GetScope() in previous implementation).
Methods Show(), UserBreak(), and Reset() are made protected in class Message_ProgressIndicator;
methods More() or UserBreak() of classes Message_ProgressScope or Message_ProgressRange should
be used to know if the cancel event has come.
See documentation of the class Message_ProgressIndicator for more details and implementation
of Draw_ProgressIndicator for an example.
Lets take a look onto typical algorithm using an old API: Let's take a look onto typical algorithm using an old API:
@code @code
class MyAlgo class MyAlgo
{ {
@ -1967,7 +1979,10 @@ public:
{ {
Message_ProgressSentry aPSentry1 (theProgress, "Stage 1", 0, 153, 1); Message_ProgressSentry aPSentry1 (theProgress, "Stage 1", 0, 153, 1);
for (int anIter = 0; anIter < 153; ++anIter, aPSentry1.Next()) for (int anIter = 0; anIter < 153; ++anIter, aPSentry1.Next())
{ if (!aPSentry1.More()) { return false; } } {
if (!aPSentry1.More()) { return false; }
// do some job here...
}
} }
aPSentry.Next(); aPSentry.Next();
{ {
@ -1982,9 +1997,9 @@ private:
//! Nested sub-algorithm taking Progress Indicator. //! Nested sub-algorithm taking Progress Indicator.
bool perform2 (const Handle(Message_ProgressIndicator)& theProgress) bool perform2 (const Handle(Message_ProgressIndicator)& theProgress)
{ {
Message_ProgressSentry aPSentry2 (theProgress, "Stage 2", 0, 561, 1); Message_ProgressSentry aPSentry2 (theProgress, "Stage 2", 0, 100, 1);
for (int anIter = 0; anIter < 561 && aPSentry2.More(); ++anIter, aPSentry2.Next()) {} for (int anIter = 0; anIter < 100 && aPSentry2.More(); ++anIter, aPSentry2.Next()) {}
return aPSentry2.More(); return !aPSentry2.UserBreak();
} }
}; };
@ -1995,19 +2010,25 @@ anAlgo.Perform ("FileName", aProgress);
@endcode @endcode
The following guidance can be used to update such code: The following guidance can be used to update such code:
- Replace `const Handle(Message_ProgressIndicator)&` with `const Message_ProgressRange&`. - Replace `const Handle(Message_ProgressIndicator)&` with `const Message_ProgressRange&`
in arguments of the methods that support progress indication.
Message_ProgressIndicator object should be now created only at place where application starts algorithms. Message_ProgressIndicator object should be now created only at place where application starts algorithms.
- Replace `Message_ProgressSentry` with `Message_ProgressScope`. - Replace `Message_ProgressSentry` with `Message_ProgressScope`.
Take note that Message_ProgressScope has smaller number of arguments (no "minimal value"). Take note that Message_ProgressScope has less arguments (no "minimal value").
In other aspects, Message_ProgressScope mimics an iterator-style interface (with methods More() and Next()) In other aspects, Message_ProgressScope mimics an iterator-style interface
close to the old Message_ProgressSentry (pay attention to extra functionality of Message_ProgressScope::Next() method below). (with methods More() and Next()) close to the old Message_ProgressSentry (pay attention
- Each Message_ProgressScope should take the next Range to fill in. to extra functionality of Message_ProgressScope::Next() method below).
Within old API, Message_ProgressSentry received the root Progress Indicator object and implicitly split it into ranges using error-prone logic. Note that method Message_ProgressScope::Close() is equivalent of the method
Message_ProgressScope in new API takes Message_ProgressRange, which should be created from the Range of the parent Scope using value returned by Message_ProgressScope::Next() method. Relieve() of Message_ProgressSentry in previous version.
Don't use the same Range passed to the algorithm for all sub-Scopes like it was possible in old API. Class Message_ProgressSentry is still defined (marked as deprecated) providing
- Check user abortion state using Message_ProgressScope::UserBreak() method; API more close to old one, and can be still used to reduce porting efforts.
Message_ProgressRange is a temporary object with the only purpose to create a new Message_ProgressScope, - Each Message_ProgressScope should take the next Range object to work with.
and Message_ProgressIndicator should be never passed directly to algorithms. Within old API, Message_ProgressSentry received the root Progress Indicator
object which mantained the sequence of ranges internally.
Message_ProgressScope in new API takes Message_ProgressRange, which should be
returned by Message_ProgressScope::Next() method of the parent scope.
Do not use the same Range passed to the algorithm for all sub-Scopes like
it was possible in old API; each range object may be used only once.
Take a look onto ported code and compare with code above to see differences: Take a look onto ported code and compare with code above to see differences:
@ -2023,7 +2044,10 @@ public:
{ {
Message_ProgressScope aPSentry1 (aPSentry.Next(), "Stage 1", 153); Message_ProgressScope aPSentry1 (aPSentry.Next(), "Stage 1", 153);
for (int anIter = 0; anIter < 153; ++anIter, aPSentry1.Next()) for (int anIter = 0; anIter < 153; ++anIter, aPSentry1.Next())
{ if (!aPSentry1.More()) { return false; }; } {
if (!aPSentry1.More()) { return false; };
// do some job here...
}
} }
{ {
perform2 (aPSentry.Next()); perform2 (aPSentry.Next());
@ -2035,9 +2059,9 @@ public:
//! Nested sub-algorithm taking Progress sub-Range. //! Nested sub-algorithm taking Progress sub-Range.
bool perform2 (const Message_ProgressRange& theProgress) bool perform2 (const Message_ProgressRange& theProgress)
{ {
Message_ProgressScope aPSentry2 (theProgress, "Stage 2", 561); Message_ProgressScope aPSentry2 (theProgress, "Stage 2", 100);
for (int anIter = 0; anIter < 561 && aPSentry2.More(); ++anIter, aPSentry2.Next()) {} for (int anIter = 0; anIter < 100 && aPSentry2.More(); ++anIter, aPSentry2.Next()) {}
return aPSentry2.More(); return !aPSentry2.UserBreak();
} }
}; };

View File

@ -202,7 +202,7 @@ Standard_Boolean Draw_ProgressIndicator::UserBreak()
{ {
OSD::ControlBreak(); OSD::ControlBreak();
} }
catch (OSD_Exception_CTRL_BREAK) catch (const OSD_Exception_CTRL_BREAK&)
{ {
myBreak = Standard_True; myBreak = Standard_True;
} }

View File

@ -99,12 +99,12 @@ protected:
//! Show() should return as soon as possible to reduce thread contention //! Show() should return as soon as possible to reduce thread contention
//! in multithreaded algorithms. //! in multithreaded algorithms.
//! //!
//! It is recommended to update (redraw, output etc.) only if progress advanced //! It is recommended to update (redraw, output etc.) only if progress is
//! by at least 1% from previous update. //! advanced by at least 1% from previous update.
//! //!
//! Flag isForce is intended for forcing update in case if it is //! Flag isForce is intended for forcing update in case if it is required
//! optimized; all calls to it from inside the core mechanism are //! at particular step of the algorithm; all calls to it from inside the core
//! done with this flag equal to False. //! mechanism (Message_Progress... classes) are done with this flag equal to False.
//! //!
//! The parameter theScope is the current scope being advanced; //! The parameter theScope is the current scope being advanced;
//! it can be used to show the names and ranges of the on-going scope and //! it can be used to show the names and ranges of the on-going scope and
@ -120,7 +120,7 @@ public:
//!@name Auxiliary methods //!@name Auxiliary methods
//! Returns total progress position ranged from 0 to 1. //! Returns total progress position ranged from 0 to 1.
//! Should not be called concurrently while the progress is advancing //! Should not be called concurrently while the progress is advancing,
//! except from implementation of method Show(). //! except from implementation of method Show().
Standard_Real GetPosition() const Standard_Real GetPosition() const
{ {

View File

@ -32,21 +32,22 @@ class Message_ProgressScope;
//! A range object can be copied, the responsibility for progress advancement is //! A range object can be copied, the responsibility for progress advancement is
//! then taken by the copy. //! then taken by the copy.
//! The same range object may be used (either copied or used to create scope) only once. //! The same range object may be used (either copied or used to create scope) only once.
//! Any consequenct attempts to use range will give no result on the progress; //! Any consequent attempts to use range will give no result on the progress;
//! in debug mode, an assert message will be generated. //! in debug mode, an assert message will be generated.
//! //!
//! @sa Message_ProgressScope for more details //! @sa Message_ProgressScope for more details
class Message_ProgressRange class Message_ProgressRange
{ {
public: public:
//! Constructor of the range //! Constructor of the empty range
Message_ProgressRange() Message_ProgressRange()
: myParentScope (0), myDelta (0), myWasUsed (false) : myParentScope (0), myStart(0.), myDelta (0.), myWasUsed (false)
{} {}
//! Copy constructor disarms the source. //! Copy constructor disarms the source
Message_ProgressRange (const Message_ProgressRange& theOther) Message_ProgressRange (const Message_ProgressRange& theOther)
: myParentScope (theOther.myParentScope), : myParentScope (theOther.myParentScope),
myStart (theOther.myStart),
myDelta (theOther.myDelta), myDelta (theOther.myDelta),
myWasUsed (theOther.myWasUsed) myWasUsed (theOther.myWasUsed)
{ {
@ -54,10 +55,11 @@ public:
theOther.myWasUsed = true; theOther.myWasUsed = true;
} }
//! Copy assignment disarms the source. //! Copy assignment disarms the source
Message_ProgressRange& operator=(const Message_ProgressRange& theOther) Message_ProgressRange& operator=(const Message_ProgressRange& theOther)
{ {
myParentScope = theOther.myParentScope; myParentScope = theOther.myParentScope;
myStart = theOther.myStart;
myDelta = theOther.myDelta; myDelta = theOther.myDelta;
myWasUsed = theOther.myWasUsed; myWasUsed = theOther.myWasUsed;
theOther.myWasUsed = true; theOther.myWasUsed = true;
@ -87,15 +89,19 @@ public:
private: private:
//! Constructor is private //! Constructor is private
Message_ProgressRange (const Message_ProgressScope& theParent, Standard_Real theDelta) Message_ProgressRange (const Message_ProgressScope& theParent,
Standard_Real theStart, Standard_Real theDelta)
: myParentScope (&theParent), : myParentScope (&theParent),
myStart (theStart),
myDelta (theDelta), myDelta (theDelta),
myWasUsed (false) myWasUsed (false)
{} {}
private: private:
const Message_ProgressScope* myParentScope; //!< Pointer to parent scope const Message_ProgressScope* myParentScope; //!< Pointer to parent scope
Standard_Real myDelta; //!< Step of incrementation Standard_Real myStart; //!< Start point on the global scale
Standard_Real myDelta; //!< Step of incrementation on the global scale
mutable Standard_Boolean myWasUsed; //!< Flag indicating that this range mutable Standard_Boolean myWasUsed; //!< Flag indicating that this range
//! was used to create a new scope //! was used to create a new scope

View File

@ -38,25 +38,44 @@ class Message_ProgressIndicator;
//! //!
//! The position on the local scale may be advanced using the method Next(), //! The position on the local scale may be advanced using the method Next(),
//! which allows iteration-like advancement. This method can take argument to //! which allows iteration-like advancement. This method can take argument to
//! advance on the needed value. And, this method returns ProgressRange object //! advance by the specified value (with default step equal to 1).
//! that takes responsibility of making the specified step at its destruction. //! This method returns Message_ProgressRange object that takes responsibility
//! The ProgressRange can be used to create a new progress sub-scope. //! of making the specified step, either directly at its destruction or by
//! delegating this task to another sub-scope created from that range object.
//! //!
//! It is important that sub-scope must have life time less than //! It is important that sub-scope must have life time less than
//! the life time of its parent scope that provided the range. //! the life time of its parent scope that provided the range.
//! The usage pattern is to create scope objects as local variables in the
//! functions that do the job, and pass range objects returned by Next() to
//! the functions of the lower level, to allow them creating their own scopes.
//! //!
//! The scope has a name that can be used in visualization of the progress. //! The scope has a name that can be used in visualization of the progress.
//! It can be null. Note that the string is not copied, just pointer is stored. //! It can be null. Note that when C string literal is used as a name, then its
//! So, the pointer must point to the string with life time //! value is not copied, just pointer is stored. In other variants (char pointer
//! greater than that of the scope object. //! or a string class) the string is copied, which is additional overhead.
//! //!
//! In multithreaded programs, for each task running concurrently it is recommended //! The same instance of the progress scope! must not be used concurrently from different threads.
//! to create a separate progress scope. The same instance of the progress scope //! For the algorithm running its tasks in parallel threads, a common scope is
//! must not be used concurrently from different threads. //! created before the parallel execution, and the range objects produced by method
//! Next() are used to initialise the data pertinent to each task.
//! Then the progress is advanced within each task using its own range object.
//! See example below.
//!
//! Note that while a range of the scope is specified using Standard_Real
//! (double) parameter, it is expected to be a positive integer value.
//! If the range is not an integer, method Next() shall be called with
//! explicit step argument, and the rounded value returned by method Value()
//! may be not coherent with the step and range.
//!
//! A scope can be created with option "infinite". This is useful when
//! the number of steps is not known by the time of the scope creation.
//! In this case the progress will be advanced logarithmically, approaching
//! the end of the scope at infinite number of steps. The parameter Max
//! for infinite scope indicates number of steps corresponding to mid-range.
//! //!
//! A progress scope created with empty constructor is not connected to any //! A progress scope created with empty constructor is not connected to any
//! progress indicator, and passing the range created on it to any algorithm //! progress indicator, and passing the range created on it to any algorithm
//! allows it executing safely without progress indication. //! allows it executing safely without actual progress indication.
//! //!
//! Example of preparation of progress indicator: //! Example of preparation of progress indicator:
//! //!
@ -132,12 +151,11 @@ class Message_ProgressIndicator;
//! { //! {
//! void operator() (Task& theTask) const //! void operator() (Task& theTask) const
//! { //! {
//! // Note: it is essential that this method is executed only once //! // Note: it is essential that this method is executed only once for the same Task object
//! // for the same Task object //! Message_ProgressScope aPS (theTask.Range, NULL, theTask.Data.NbItems);
//! Message_ProgressScope aPS (theTask.Range, "Processing task", 1); //! for (Standard_Integer i = 0; i < theTask.Data.NbSteps && aPS.More(); i++)
//! if (aPS.More())
//! { //! {
//! // ... process data //! do_job (theTask.Data.Item[i], aPS.Next());
//! } //! }
//! } //! }
//! }; //! };
@ -153,6 +171,24 @@ class Message_ProgressIndicator;
//! OSD_Parallel::ForEach (aTasks.begin(), aTasks.end(), Functor()); //! OSD_Parallel::ForEach (aTasks.begin(), aTasks.end(), Functor());
//! } //! }
//! @endcode //! @endcode
//!
//! For lightweight algorithms that do not need advancing the progress
//! within individual tasks the code can be simplified to avoid inner scopes:
//!
//! @code
//! struct Functor
//! {
//! void operator() (Task& theTask) const
//! {
//! if (theTask.Range.More())
//! {
//! do_job (theTask.Data);
//! // advance the progress
//! theTask.Range.Close();
//! }
//! }
//! };
//! @endcode
class Message_ProgressScope class Message_ProgressScope
{ {
public: public:
@ -165,7 +201,10 @@ public: //! @name Preparation methods
: myProgress (0), : myProgress (0),
myParent (0), myParent (0),
myName (0), myName (0),
myPortion (1.), myMax (1.), myValue (0.), myStart (0.),
myPortion (1.),
myMax (1.),
myValue (0.),
myIsActive (false), myIsActive (false),
myIsOwnName (false), myIsOwnName (false),
myIsInfinite (false) myIsInfinite (false)
@ -302,12 +341,16 @@ public: //! @name Auxiliary methods to use in ProgressIndicator
} }
//! Returns the current value of progress in this scope. //! Returns the current value of progress in this scope.
//! If this scope is being advanced by sub-scoping, that value is //!
//! computed by mapping current global progress into this scope range. //! The value is computed by mapping current global progress into
Standard_Real Value() const //! this scope range; the result is rounded up to integer.
{ //! Note that if MaxValue() is not an integer, Value() can be
return myIsActive ? myValue : myMax; //! greater than MaxValue() due to that rounding.
} //!
//! This method should not be called concurrently while the progress
//! is advancing, except from implementation of method Show() in
//! descendant of Message_ProgressIndicator.
Standard_Real Value() const;
//! Returns the infinite flag //! Returns the infinite flag
Standard_Boolean IsInfinite() const Standard_Boolean IsInfinite() const
@ -326,7 +369,7 @@ public: //! @name Destruction, allocation
//! Destructor - closes the scope and adds its scale to the total progress //! Destructor - closes the scope and adds its scale to the total progress
~Message_ProgressScope() ~Message_ProgressScope()
{ {
Relieve(); Close();
if (myIsOwnName) if (myIsOwnName)
{ {
Standard::Free (myName); Standard::Free (myName);
@ -335,9 +378,9 @@ public: //! @name Destruction, allocation
} }
} }
//! Closes the scope and adds its scale to the total progress. //! Closes the scope and advances the progress to its end.
//! Relieved scope should not be used. //! Closed scope should not be used.
void Relieve(); void Close();
DEFINE_STANDARD_ALLOC DEFINE_STANDARD_ALLOC
@ -347,12 +390,10 @@ private: //! @name Internal methods
//! Called only by Message_ProgressIndicator constructor. //! Called only by Message_ProgressIndicator constructor.
Message_ProgressScope (Message_ProgressIndicator* theProgress); Message_ProgressScope (Message_ProgressIndicator* theProgress);
//! Convert value from this scale to global one //! Convert value from this scope to global scale, but disregarding
//! start position of the scope, in the range [0, myPortion]
Standard_Real localToGlobal(const Standard_Real theVal) const; Standard_Real localToGlobal(const Standard_Real theVal) const;
//! Convert value from global scale to this one
Standard_Real globalToLocal(const Standard_Real theVal) const;
private: private:
//! Copy constructor is prohibited //! Copy constructor is prohibited
Message_ProgressScope (const Message_ProgressScope& theOther); Message_ProgressScope (const Message_ProgressScope& theOther);
@ -366,7 +407,9 @@ private:
const Message_ProgressScope* myParent; //!< Pointer to parent scope const Message_ProgressScope* myParent; //!< Pointer to parent scope
Standard_CString myName; //!< Name of the operation being done in this scope, or null Standard_CString myName; //!< Name of the operation being done in this scope, or null
Standard_Real myPortion; //!< The portion of the global scale covered by this scope (from 0 to 1) Standard_Real myStart; //!< Start position on the global scale [0, 1]
Standard_Real myPortion; //!< The portion of the global scale covered by this scope [0, 1]
Standard_Real myMax; //!< Maximal value of progress in this scope Standard_Real myMax; //!< Maximal value of progress in this scope
Standard_Real myValue; //!< Current position advanced within this scope [0, Max] Standard_Real myValue; //!< Current position advanced within this scope [0, Max]
@ -389,6 +432,7 @@ inline Message_ProgressScope::Message_ProgressScope (Message_ProgressIndicator*
: myProgress(theProgress), : myProgress(theProgress),
myParent(0), myParent(0),
myName(0), myName(0),
myStart(0.),
myPortion(1.), myPortion(1.),
myMax(1.), myMax(1.),
myValue(0.), myValue(0.),
@ -409,6 +453,7 @@ inline Message_ProgressScope::Message_ProgressScope (const Message_ProgressRange
: myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL), : myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL),
myParent (theRange.myParentScope), myParent (theRange.myParentScope),
myName (NULL), myName (NULL),
myStart (theRange.myStart),
myPortion (theRange.myDelta), myPortion (theRange.myDelta),
myMax (Max (1.e-6, theMax)), // protection against zero range myMax (Max (1.e-6, theMax)), // protection against zero range
myValue (0.), myValue (0.),
@ -433,6 +478,7 @@ Message_ProgressScope::Message_ProgressScope (const Message_ProgressRange& theRa
: myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL), : myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL),
myParent (theRange.myParentScope), myParent (theRange.myParentScope),
myName (theName), myName (theName),
myStart (theRange.myStart),
myPortion (theRange.myDelta), myPortion (theRange.myDelta),
myMax (Max (1.e-6, theMax)), // protection against zero range myMax (Max (1.e-6, theMax)), // protection against zero range
myValue (0.), myValue (0.),
@ -455,6 +501,7 @@ inline Message_ProgressScope::Message_ProgressScope (const Message_ProgressRange
: myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL), : myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL),
myParent (theRange.myParentScope), myParent (theRange.myParentScope),
myName (NULL), myName (NULL),
myStart (theRange.myStart),
myPortion (theRange.myDelta), myPortion (theRange.myDelta),
myMax (Max (1.e-6, theMax)), // protection against zero range myMax (Max (1.e-6, theMax)), // protection against zero range
myValue (0.), myValue (0.),
@ -467,10 +514,10 @@ inline Message_ProgressScope::Message_ProgressScope (const Message_ProgressRange
} }
//======================================================================= //=======================================================================
//function : Relieve //function : Close
//purpose : //purpose :
//======================================================================= //=======================================================================
inline void Message_ProgressScope::Relieve() inline void Message_ProgressScope::Close()
{ {
if (!myIsActive) if (!myIsActive)
{ {
@ -506,17 +553,14 @@ inline Standard_Boolean Message_ProgressScope::UserBreak() const
//======================================================================= //=======================================================================
inline Message_ProgressRange Message_ProgressScope::Next (Standard_Real theStep) inline Message_ProgressRange Message_ProgressScope::Next (Standard_Real theStep)
{ {
if (myIsActive) if (myIsActive && theStep > 0.)
{ {
if (theStep > 0.) Standard_Real aCurr = localToGlobal(myValue);
{ Standard_Real aNext = localToGlobal(myValue += theStep);
Standard_Real aCurr = localToGlobal (myValue);
Standard_Real aNext = localToGlobal (myValue += theStep);
Standard_Real aDelta = aNext - aCurr; Standard_Real aDelta = aNext - aCurr;
if (aDelta > 0.) if (aDelta > 0.)
{ {
return Message_ProgressRange (*this, aDelta); return Message_ProgressRange(*this, myStart + aCurr, aDelta);
}
} }
} }
return Message_ProgressRange(); return Message_ProgressRange();
@ -557,23 +601,34 @@ inline Standard_Real Message_ProgressScope::localToGlobal (const Standard_Real t
} }
//======================================================================= //=======================================================================
//function : globalToLocal //function : Value
//purpose : //purpose :
//======================================================================= //=======================================================================
inline Standard_Real Message_ProgressScope::globalToLocal (const Standard_Real theVal) const inline Standard_Real Message_ProgressScope::Value () const
{ {
if (!myIsActive)
{
return myIsInfinite ? Precision::Infinite() : myMax;
}
// get current progress on the global scale counted
// from the start of this scope
Standard_Real aVal = myProgress->GetPosition() - myStart;
// if progress has not reached yet the start of this scope, return 0
if (aVal <= 0.)
return 0.;
// if at end of the scope (or behind), report the maximum // if at end of the scope (or behind), report the maximum
Standard_Real aDist = myPortion - theVal; Standard_Real aDist = myPortion - aVal;
if (aDist <= Precision::Confusion()) if (aDist <= Precision::Confusion())
return myIsInfinite ? Precision::Infinite() : myMax; return myIsInfinite ? Precision::Infinite() : myMax;
if (!myIsInfinite) // map the value to the range of this scope [0, Max],
return myMax * theVal / myPortion; // rounding up to integer, with small correction applied
// to avoid rounding errors
// Standard_Real x = log (theVal / aDist); // exponent return std::ceil (myMax * aVal / (myIsInfinite ? aDist : myPortion) - Precision::Confusion());
Standard_Real x = theVal / aDist; // hyperbola
return x * myMax;
} }
#endif // _Message_ProgressScope_HeaderFile #endif // _Message_ProgressScope_HeaderFile

View File

@ -38,6 +38,9 @@ public:
} }
} }
//! Method Relieve() was replaced by Close() in Message_ProgressScope
void Relieve () { Close(); }
private: private:
//! Message_ProgressRange should be passed to constructor instead of Message_ProgressIndicator. //! Message_ProgressRange should be passed to constructor instead of Message_ProgressIndicator.
Message_ProgressSentry (const Handle(Message_ProgressIndicator)& theProgress, Message_ProgressSentry (const Handle(Message_ProgressIndicator)& theProgress,

View File

@ -4843,12 +4843,12 @@ namespace
{ {
void operator()(Task& theTask) const void operator()(Task& theTask) const
{ {
Message_ProgressScope aPS(theTask.Range, NULL, 1); if (theTask.Range.More())
if (aPS.More())
{ {
if (theTask.Mat1.RowNumber() > 1) if (theTask.Mat1.RowNumber() > 1)
theTask.Mat3 = theTask.Mat1 * theTask.Mat2; theTask.Mat3 = theTask.Mat1 * theTask.Mat2;
} }
theTask.Range.Close();
} }
}; };
} }