Home » Console » Console_ProgressBar » Bug #9236
Patch to improve performance
Details
| Request #9236 | Patch to improve performance |
|---|---|
| Submitted | 2006-11-05 04:56 UTC |
| From | apinstein at mac dot com |
| Assigned | et |
| Status | Closed |
| Package | Console_ProgressBar |
| PHP Version | 5.1.6 |
| OS | n/a |
| Roadmaps | (Not assigned) |
Comments
[2006-11-05 04:56 UTC] apinstein at mac dot com
Description:
------------
Repeated calls to update() can affect performance,
particularly over a network, as ansi chars are transmitted
and rendered by the terminal.
On my Mac OS X G5 1.6GHz, the follow test results
demonstrate the issue:
Progressing... 10000/10000
[===============================>] 100.00% 00:30.06
[Remaining: 00:00.00]Done!
This is just a simple for loop going 10,000 times, and
updating the progress bar once each time through the loop.
It takes 30s to run! That is a cost of 0.003s/call to
update.
I have added a small bit of code that imposes a "minimum
update delay" so that the udpate function quietly exits if
the minimum delay hasn't been met.
Changing to a 1-second delay speed up the test by 30x:
Progressing... 9172/10000
[============================>---] 91.72% 00:01.01
[Remaining: 00:00.09]Done!
The main reason for implementing such a thing in progressbar
rather than having the client code call update() less often
is ease-of-use. Usually progressbar is used only for
interactive sessions, and thus most of the code related to
it is just for "debug" or interactive use. It is somewhat
annoying to have to write throttling code on the client for
this purpose. Client-side throttling is even further
complicated by the fact that the same script running on
different machines with different speeds should be throttled
differently. Moving the throttling to time-based within
progressbar reduces the need for the client to have to spend
any time coding around this small performance drain.
Also, if you accept the patch, you could also change default
value for "min_update_delay" to 0 which would cause no
backwards-compatibility issues.
Test script:
---------------
/* test script */
test(0);
test(1);
function test($minUpdateDelay)
{
$its = 10000;
$progress = new Console_ProgressBar("Progressing... %fraction% [%bar%] %percent% %elapsed% [Remaining: %estimate%]", "=>", "-", 100, $its, array('ansi_terminal' => true, 'min_update_delay' => $minUpdateDelay));
for ($i = 0; $i < $its; $i++) {
$progress->update($i);
}
$progress->update($i);
print "Done!\n";
}
/* patch to ProgressBar.php (0.40) */
--- ProgressBar.php.orig 2006-11-04 23:43:52.000000000 -0500
+++ ProgressBar.php 2006-11-04 23:43:57.000000000 -0500
@@ -73,6 +73,10 @@
*/
var $_start_time = null;
var $_rate_datapoints = array();
+ /**
+ * Update throttle
+ */
+ var $_lastUpdateTime = null;
// }}}
// constructor() {{{
@@ -187,6 +191,7 @@
'ansi_terminal' => false,
'ansi_clear' => false,
'num_datapoints' => 5,
+ 'min_update_delay' => 1,
);
$intopts = array();
foreach ($default_options as $key => $value) {
@@ -257,13 +262,17 @@
*/
function update($current)
{
+ // throttle updates
+ $tNow = $this->_fetchTime();
+ if ( ($tNow - $this->_lastUpdateTime) < $this->_options['min_update_delay']) return;
+ $this->_lastUpdateTime = $tNow;
$this->_addDatapoint($current);
if ($this->_first) {
if ($this->_options['ansi_terminal']) {
print "\x1b[s"; // save cursor position
}
$this->_first = false;
- $this->_start_time = $this->_fetchTime();
+ $this->_start_time = $tNow;
$this->display($current);
return;
}
[2006-12-01 16:29 UTC] apinstein at mac dot com
I just re-built my pear and realized that my patch doesn't
work against 0.4.0. I am re-submitting a valid patch.
--- ProgressBar.php.orig 2006-12-01 11:15:18.000000000
-0500
+++ ProgressBar.php 2006-12-01 11:27:08.000000000 -0500
@@ -52,6 +52,10 @@
* Options, like the precision used to display the
numbers
*/
var $_options = array();
+ /**
+ * Update throttle
+ */
+ var $_lastUpdateTime = null;
// }}}
// constructor() {{{
@@ -196,6 +200,10 @@
* ansi_terminal | false | If this option is
true, a better
* | | (faster) method
for erasing the bar is
* | | used.
+ * min_update_delay | 0.25 | Minimum time delay
in seconds (decimals ok)
+ * | | required to pass
before an update will be drawn.
+ * | | Improves
performance of things that progress
+ * | | hundreds+ times
per second.
* </pre>
*
* @param string The format string
@@ -217,6 +225,7 @@
'fraction_pad' => ' ',
'width_absolute' => true,
'ansi_terminal' => false,
+ 'min_update_delay' => 0.25,
);
foreach ($default_options as $key => $value) {
if (!isset($options[$key])) {
@@ -279,8 +288,13 @@
*/
function update($current)
{
+ // throttle updates
+ $tNow = microtime(true);
+ if ( ($tNow - $this->_lastUpdateTime) < $this-
>_options['min_update_delay']) return;
+ $this->_lastUpdateTime = $tNow;
if ($this->_first) {
$this->_first = false;
+ $this->_start_time = $tNow;
$this->display($current);
return;
}
[2007-01-23 03:49 UTC] apinstein at mac dot com
Hmm... I just tried using my own patch and it didn't work...
I re-did the patch and here's yet another patchfile...
--- /opt/local/lib/php/Console/ProgressBar.php.orig
2007-01-22 22:43:40.000000000 -0500
+++ /opt/local/lib/php/Console/ProgressBar.php 2007-01-22
22:47:50.000000000 -0500
@@ -64,6 +64,10 @@
* Options, like the precision used to display the
numbers
*/
var $_options = array();
+ /**
+ * Update throttle
+ */
+ var $_lastUpdateTime = null;
/**
* Length to erase
*/
@@ -164,6 +168,10 @@
* ansi_clear | false | If the bar should
be cleared everytime
* num_datapoints | 5 | How many
datapoints to use to create
* | | the estimated
remaining time
+ * min_update_delay | 0.25 | Minimum time delay
in seconds (decimals ok)
+ * | | required to pass
before an update will be drawn.
+ * | | Improves
performance of things that progress
+ * | | hundreds+ times
per second.
* </pre>
*
* @param string The format string
@@ -187,6 +195,7 @@
'ansi_terminal' => false,
'ansi_clear' => false,
'num_datapoints' => 5,
+ 'min_update_delay' => 0.25,
);
$intopts = array();
foreach ($default_options as $key => $value) {
@@ -257,12 +266,17 @@
*/
function update($current)
{
+ // throttle updates
+ $tNow = microtime(true);
+ if ( ($tNow - $this->_lastUpdateTime) < $this-
>_options['min_update_delay']) return;
+ $this->_lastUpdateTime = $tNow;
$this->_addDatapoint($current);
if ($this->_first) {
if ($this->_options['ansi_terminal']) {
print "\x1b[s"; // save cursor position
}
$this->_first = false;
+ $this->_start_time = $tNow;
$this->_start_time = $this->_fetchTime();
$this->display($current);
return;
[2007-01-30 23:16 UTC] apinstein at mac dot com
Just a quick update to my original patch...
In the update() function, change:
tNow = microtime(true);
to:
tNow = $this->_fetchTime();
That's all! Now it works in PHP4 and PHP5.