Repository: pfnet/pytorch-pfn-extras

Issue:
ProgressBar extension doesn't show correct `iters/sec` in ppe==0.5.0
The `ProgressBar` extension shows `iters/sec` as well as the progress bar, but I noticed that in ppe==0.5.0 it becomes always `inf iters/sec`.

### ppe==0.5.0

Minimum reproduction code:
```python
# progress.py (based on https://git.io/JzHP3)
import pytorch_pfn_extras as ppe
import time

print("PPE =", ppe.__version__)

max_epochs = 3
iters_per_epoch = 20
manager = ppe.training.ExtensionsManager({}, {}, max_epochs, iters_per_epoch=iters_per_epoch)
manager.extend(ppe.training.extensions.ProgressBar(training_length=None, update_interval=1, bar_length=40))

for epoch in range(max_epochs):
    for _ in range(iters_per_epoch):
        with manager.run_iteration():
            pass
        time.sleep(0.1)
```

Result:
```
$ python progress.py
PPE = 0.5.0
     total [####################....................] 51.67%
this epoch [######################..................] 55.00%
        31 iter, 1 epoch / 3 epochs
       inf iters/sec. Estimated time to finish: 0:00:00.
```

### ppe==0.4.5 (expected behavior)
It shows a correct iters/sec.
```
$ python progress.py
PPE = 0.4.5
     total [#################.......................] 43.33%
this epoch [############............................] 30.00%
        26 iter, 1 epoch / 3 epochs
    10.825 iters/sec. Estimated time to finish: 0:00:03.140780.
```


Discussion:
It seems that the change introduced in [`update_speed`](https://github.com/asi1024/pytorch-pfn-extras/blob/bb58bb88f20fb35016e6c70e0cb40d098c5d322b/pytorch_pfn_extras/training/extensions/util.py#L79-L94) by #242 has something to do with it.
If I revert https://github.com/pfnet/pytorch-pfn-extras/commit/bb58bb88f20fb35016e6c70e0cb40d098c5d322b based on `v0.5.0`, it shows correct `iters/sec`.

Thanks, confirmed the issue reproduce. Could you take a look @asi1024 ?

Resolving patch:
diff --git a/pytorch_pfn_extras/training/extensions/util.py b/pytorch_pfn_extras/training/extensions/util.py
--- a/pytorch_pfn_extras/training/extensions/util.py
+++ b/pytorch_pfn_extras/training/extensions/util.py
@@ -1,8 +1,8 @@
+import collections
 import os
 import sys
-import queue
 import time
-from typing import NamedTuple, Optional, Sequence, TextIO, Tuple, TYPE_CHECKING
+from typing import Deque, Optional, Sequence, TextIO, Tuple, TYPE_CHECKING
 
 if TYPE_CHECKING:
     from pytorch_pfn_extras.training.manager import _BaseExtensionsManager
@@ -64,17 +64,12 @@ def erase_console(x: int, y: int, mode: int = 0) -> None:
             os.system('cls')
 
 
-class _QueUnit(NamedTuple):
-    iteration: int
-    epoch_detail: float
-    time: float
-
-
 class ProgressBar:
 
     def __init__(self, out: Optional[TextIO] = None) -> None:
         self._out = sys.stdout if out is None else out
-        self._recent_timing: 'queue.Queue[_QueUnit]' = queue.Queue(maxsize=100)
+        self._recent_timing: Deque[Tuple[int, float, float]] = collections.deque(
+            [], maxlen=100)
 
     def update_speed(
             self,
@@ -82,12 +77,12 @@ def update_speed(
             epoch_detail: float
     ) -> Tuple[float, float]:
         now = time.time()
-        self._recent_timing.put(_QueUnit(iteration, epoch_detail, now))
-        old = self._recent_timing.get()
-        span = now - old.time
+        self._recent_timing.append((iteration, epoch_detail, now))
+        old_t, old_e, old_sec = self._recent_timing[0]
+        span = now - old_sec
         if span != 0:
-            speed_t = (iteration - old.iteration) / span
-            speed_e = (epoch_detail - old.epoch_detail) / span
+            speed_t = (iteration - old_t) / span
+            speed_e = (epoch_detail - old_e) / span
         else:
             speed_t = float('inf')
             speed_e = float('inf')


Test patch:
diff --git a/tests/pytorch_pfn_extras_tests/training_tests/extensions_tests/test_progress_bar.py b/tests/pytorch_pfn_extras_tests/training_tests/extensions_tests/test_progress_bar.py
--- a/tests/pytorch_pfn_extras_tests/training_tests/extensions_tests/test_progress_bar.py
+++ b/tests/pytorch_pfn_extras_tests/training_tests/extensions_tests/test_progress_bar.py
@@ -1,4 +1,6 @@
 import io
+import re
+import time
 
 import pytorch_pfn_extras as ppe
 
@@ -21,8 +23,12 @@ def test_run():
     for epoch in range(max_epochs):
         for _ in range(iters_per_epoch):
             with manager.run_iteration():
+                time.sleep(0.1)
                 if manager.iteration < 2:
                     continue
-                status = '{} iter, {} epoch / {} epochs'.format(
-                    manager.iteration, epoch, max_epochs)
-                assert status in out.getvalue()
+                status = out.getvalue()
+                assert '{} iter, {} epoch / {} epochs'.format(
+                    manager.iteration, epoch, max_epochs) in status
+                iters_per_sec = float(
+                    re.findall(r'([0-9]+\.[0-9]*) iters/sec', status)[-1])
+                assert 8 <= iters_per_sec <= 12