From b4e9dc3ab96e699a38a71aa6bb46337a596312d5 Mon Sep 17 00:00:00 2001 From: John Morrissey Date: Fri, 12 Dec 2014 13:23:25 -0500 Subject: read in >1 byte chunks, and set a useful timeout on select() this way, we're not rolling this loop over nearly as much, while still preserving the overall timeout semantics --- paramiko/proxy.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/paramiko/proxy.py b/paramiko/proxy.py index 8959b244..25666be5 100644 --- a/paramiko/proxy.py +++ b/paramiko/proxy.py @@ -24,6 +24,7 @@ import signal from subprocess import Popen, PIPE from select import select import socket +import time from paramiko.ssh_exception import ProxyCommandFailure @@ -76,20 +77,24 @@ class ProxyCommand(object): :return: the length of the read content, as an `int` """ try: - start = datetime.now() + start = time.time() while len(self.buffer) < size: + select_timeout = None if self.timeout is not None: - elapsed = (datetime.now() - start).microseconds - timeout = self.timeout * 1000 * 1000 # to microseconds - if elapsed >= timeout: + elapsed = (time.time() - start) + if elapsed >= self.timeout: raise socket.timeout() - r, w, x = select([self.process.stdout], [], [], 0.0) + select_timeout = self.timeout - elapsed + + r, w, x = select( + [self.process.stdout], [], [], select_timeout) if r and r[0] == self.process.stdout: - b = os.read(self.process.stdout.fileno(), 1) + b = os.read( + self.process.stdout.fileno(), size - len(self.buffer)) # Store in class-level buffer for persistence across # timeouts; this makes us act more like a real socket # (where timeouts don't actually drop data.) - self.buffer.append(b) + self.buffer.extend(b) result = ''.join(self.buffer) self.buffer = [] return result -- cgit v1.2.3 From 741b4fbb9322a45282e86958c92b1b6706c07f8c Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Thu, 18 Dec 2014 13:53:24 -0800 Subject: Changelog re #413, closes #454 --- sites/www/changelog.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sites/www/changelog.rst b/sites/www/changelog.rst index 99c28fbd..66bbb806 100644 --- a/sites/www/changelog.rst +++ b/sites/www/changelog.rst @@ -2,6 +2,11 @@ Changelog ========= +* :bug:`413` (also :issue:`414`, :issue:`420`, :issue:`454`) Be significantly + smarter about polling & timing behavior when running proxy commands, to avoid + unnecessary (often 100%!) CPU usage. Major thanks to Jason Dunsmore for + report & initial patchset and to Chris Adams & John Morrissey for followup + improvements. * :bug:`428` Fix an issue in `~paramiko.file.BufferedFile` (primarily used in the SFTP modules) concerning incorrect behavior by `~paramiko.file.BufferedFile.readlines` on files whose size exceeds the -- cgit v1.2.3