Add the --use_interface_counters option.

This commit is contained in:
Marco Paganini 2015-09-12 13:38:00 -07:00
parent 93951f1154
commit e31dd2700a
3 changed files with 75 additions and 6 deletions

View File

@ -97,6 +97,11 @@ Usage
--timeout TIMEOUT HTTP timeout in seconds. Default 10
--secure Use HTTPS instead of HTTP when communicating with
speedtest.net operated servers
--use_interface_counters USE_INTERFACE_COUNTERS
Use the kernel counters for the specified network
interface to calculate the total number of bytes
transmitted/received (Linux only).
--version Show the version number and exit
--version Show the version number and exit
Inconsistency

View File

@ -58,6 +58,15 @@ URL of the Speedtest Mini server
Source IP address to bind to
.RE
\fB\-\-use_interface_counters INTF\fR
.RS
With this option the program uses the kernel counters for interface
"intf" to calculate the number of bytes transferred. This option is
useful when running this program on a computer that is the gateway
to the Internet, as it will include the bandwidth used by every user
of the system and thus provide more accurate bandwidth figures.
.RE
\fB\-\-version\fR
.RS
Show the version number and exit

View File

@ -16,6 +16,7 @@
# under the License.
import os
import os.path
import re
import sys
import math
@ -233,6 +234,28 @@ def catch_request(request):
return None, e
def get_interface_counter(intf, counter):
"""Retrieve a specific interface counter for interface 'intf'.
This requires a mounted /sys filesystem and is linux specific.
Will raise IOError if the /sys file cannot be opened."""
sysfile = os.path.join('/sys/class/net', intf, 'statistics', counter)
fd = open(sysfile)
val = int(fd.readline().rstrip())
fd.close()
return val
def counter_diff(start, end):
"""Returns the difference between end and start, considering counter
wrap-arounds. Values are assumed to wrap at 64-bit boundaries."""
if end > start:
return end - start
else:
return ((2**64) - start) + end
class FileGetter(threading.Thread):
"""Thread class for retrieving a URL"""
@ -257,11 +280,14 @@ class FileGetter(threading.Thread):
pass
def downloadSpeed(files, quiet=False):
def downloadSpeed(files, quiet=False, net_interface=None):
"""Function to launch FileGetter threads and calculate download speeds"""
start = timeit.default_timer()
if net_interface:
start_bytes = get_interface_counter(net_interface, 'rx_bytes')
def producer(q, files):
for file in files:
thread = FileGetter(file, start)
@ -291,7 +317,17 @@ def downloadSpeed(files, quiet=False):
prod_thread.join(timeout=0.1)
while cons_thread.isAlive():
cons_thread.join(timeout=0.1)
return (sum(finished) / (timeit.default_timer() - start))
elapsed = timeit.default_timer() - start
# If 'net_interface' is set, calculate the total bytes received
# based on the interface counters. Otherwise, use the total
# number of bytes in 'finished'.
if net_interface:
end_bytes = get_interface_counter(net_interface, 'rx_bytes')
return counter_diff(start_bytes, end_bytes) / elapsed
else:
return sum(finished) / elapsed
class FilePutter(threading.Thread):
@ -322,11 +358,14 @@ class FilePutter(threading.Thread):
self.result = 0
def uploadSpeed(url, sizes, quiet=False):
def uploadSpeed(url, sizes, quiet=False, net_interface=None):
"""Function to launch FilePutter threads and calculate upload speeds"""
start = timeit.default_timer()
if net_interface:
start_bytes = get_interface_counter(net_interface, 'tx_bytes')
def producer(q, sizes):
for size in sizes:
thread = FilePutter(url, start, size)
@ -356,7 +395,17 @@ def uploadSpeed(url, sizes, quiet=False):
prod_thread.join(timeout=0.1)
while cons_thread.isAlive():
cons_thread.join(timeout=0.1)
return (sum(finished) / (timeit.default_timer() - start))
elapsed = timeit.default_timer() - start
# If 'net_interface' is set, calculate the total bytes transmitted
# based on the interface counters. Otherwise, use the total
# number of bytes in 'finished'.
if net_interface:
end_bytes = get_interface_counter(net_interface, 'tx_bytes')
return counter_diff(start_bytes, end_bytes) / elapsed
else:
return sum(finished) / elapsed
def getAttributesByTagName(dom, tagName):
@ -590,6 +639,11 @@ def speedtest():
parser.add_argument('--secure', action='store_true',
help='Use HTTPS instead of HTTP when communicating '
'with speedtest.net operated servers')
parser.add_argument('--use_interface_counters',
help='Use the kernel counters for the specified '
'network interface to calculate the total '
'number of bytes transmitted/received '
'(Linux only).')
parser.add_argument('--version', action='store_true',
help='Show the version number and exit')
@ -716,7 +770,7 @@ def speedtest():
(os.path.dirname(best['url']), size, size))
if not args.simple:
print_('Testing download speed', end='')
dlspeed = downloadSpeed(urls, args.simple)
dlspeed = downloadSpeed(urls, args.simple, args.use_interface_counters)
if not args.simple:
print_()
print_('Download: %0.2f M%s/s' %
@ -729,7 +783,8 @@ def speedtest():
sizes.append(size)
if not args.simple:
print_('Testing upload speed', end='')
ulspeed = uploadSpeed(best['url'], sizes, args.simple)
ulspeed = uploadSpeed(best['url'], sizes,
args.simple, args.use_interface_counters)
if not args.simple:
print_()
print_('Upload: %0.2f M%s/s' %