Skip to content

Commit

Permalink
Made Broken Pipe Error more verbose (#3292)
Browse files Browse the repository at this point in the history
* Fix for #3225. Made Triangular `c` attribute be handled consistently with scipy.stats. Added test and updated example code.

* Added a more detailed error message for Broken pipes.

* Not a fix for #3140

* Fixed import of time. Trimmed the broken pipe exception handling. Added release notes.

* Moved maintenance message to release notes of pymc3.7
  • Loading branch information
lucianopaz authored and twiecki committed Dec 22, 2018
1 parent e67c476 commit 98fd63e
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 1 deletion.
1 change: 1 addition & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

### Maintenance

- Made `BrokenPipeError` for parallel sampling more verbose on Windows.
- Added the `broadcast_distribution_samples` function that helps broadcasting arrays of drawn samples, taking into account the requested `size` and the inferred distribution shape. This sometimes is needed by distributions that call several `rvs` separately within their `random` method, such as the `ZeroInflatedPoisson` (Fix issue #3310).
- The `Wald`, `Kumaraswamy`, `LogNormal`, `Pareto`, `Cauchy`, `HalfCauchy`, `Weibull` and `ExGaussian` distributions `random` method used a hidden `_random` function that was written with scalars in mind. This could potentially lead to artificial correlations between random draws. Added shape guards and broadcasting of the distribution samples to prevent this (Similar to issue #3310).

Expand Down
51 changes: 50 additions & 1 deletion pymc3/parallel_sampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from collections import namedtuple
import traceback
from pymc3.exceptions import SamplingError
import errno

import numpy as np

Expand All @@ -14,6 +15,34 @@
logger = logging.getLogger("pymc3")


def _get_broken_pipe_exception():
import sys
if sys.platform == 'win32':
return RuntimeError("The communication pipe between the main process "
"and its spawned children is broken.\n"
"In Windows OS, this usually means that the child "
"process raised an exception while it was being "
"spawned, before it was setup to communicate to "
"the main process.\n"
"The exceptions raised by the child process while "
"spawning cannot be caught or handled from the "
"main process, and when running from an IPython or "
"jupyter notebook interactive kernel, the child's "
"exception and traceback appears to be lost.\n"
"A known way to see the child's error, and try to "
"fix or handle it, is to run the problematic code "
"as a batch script from a system's Command Prompt. "
"The child's exception will be printed to the "
"Command Promt's stderr, and it should be visible "
"above this error and traceback.\n"
"Note that if running a jupyter notebook that was "
"invoked from a Command Prompt, the child's "
"exception should have been printed to the Command "
"Prompt on which the notebook is running.")
else:
return None


class ParallelSamplingError(Exception):
def __init__(self, message, chain, warnings=None):
super().__init__(message)
Expand Down Expand Up @@ -83,10 +112,19 @@ def run(self):
pass
except BaseException as e:
e = ExceptionWithTraceback(e, e.__traceback__)
# Send is not blocking so we have to force a wait for the abort
# message
self._msg_pipe.send(("error", None, e))
self._wait_for_abortion()
finally:
self._msg_pipe.close()

def _wait_for_abortion(self):
while True:
msg = self._recv_msg()
if msg[0] == "abort":
break

def _make_numpy_refs(self):
shape_dtypes = self._step_method.vars_shape_dtype
point = {}
Expand Down Expand Up @@ -200,7 +238,18 @@ def __init__(self, draws, tune, step_method, chain, seed, start):
seed,
)
# We fork right away, so that the main process can start tqdm threads
self._process.start()
try:
self._process.start()
except IOError as e:
# Something may have gone wrong during the fork / spawn
if e.errno == errno.EPIPE:
exc = _get_broken_pipe_exception()
if exc is not None:
# Sleep a little to give the child process time to flush
# all its error message
time.sleep(0.2)
raise exc
raise

@property
def shared_point_view(self):
Expand Down

0 comments on commit 98fd63e

Please sign in to comment.