-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactoring: rx-buffers-increase util has separated library and test …
…now.
- Loading branch information
1 parent
26db44a
commit f2a083c
Showing
6 changed files
with
117 additions
and
110 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
from os import system, path | ||
from subprocess import Popen, PIPE | ||
|
||
|
||
class RxBuffersIncreaser(object): | ||
|
||
""" | ||
0. Check if buffers already been setted up in ifcfg-ethX | ||
1. Determines what size of buffers available | ||
2. Evaluate one that fits for our purposes | ||
3. Apply it | ||
""" | ||
|
||
def __init__(self, dev=None, upper_bound=2048): | ||
self.dev = dev | ||
self.upper_bound = upper_bound | ||
self.current = 0 | ||
self.maximum = 0 | ||
self.prefered = None | ||
self.manual_tuned = False | ||
|
||
def __str__(self): | ||
attrs = ('dev', 'upper_bound', 'current', 'maximum', 'prefered') | ||
return str(dict((attr, self.__getattribute__(attr)) for attr in attrs)) | ||
|
||
def investigate(self): | ||
""" get maximum and current rx ring buffers values via ethtool """ | ||
def extract_value(s): | ||
return int(s.strip('RX:\t\n')) | ||
|
||
ns = '/etc/sysconfig/network-scripts/' | ||
with open(path.join(ns, 'ifcfg-' + self.dev)) as config: | ||
if any(line for line in config.xreadlines() if 'ETHTOOL_OPTS' in line): | ||
print "{0}'s RX ring buffer already manually tuned.".format(self.dev) | ||
exit(0) | ||
process = Popen(['ethtool', '-i', self.dev], stdout=PIPE, stderr=PIPE) | ||
_, _ = process.communicate() | ||
# silent fail if called for vlan/bridge/etc | ||
if process.returncode != 0: | ||
exit(0) | ||
process = Popen(['ethtool', '-g', self.dev], stdout=PIPE, stderr=PIPE) | ||
ethtool_buffers, _ = process.communicate() | ||
if process.returncode != 0: | ||
exit(1) | ||
ethtool_buffers = ethtool_buffers.split('\n') | ||
self.maximum = extract_value(ethtool_buffers[2]) | ||
self.current = extract_value(ethtool_buffers[7]) | ||
|
||
def determine(self, current=None, maximum=None): | ||
""" evaluate most fitting RX ring buffer's fize """ | ||
if not current: | ||
current = self.current | ||
if not maximum: | ||
maximum = self.maximum | ||
if current > self.upper_bound: | ||
return current | ||
if maximum < self.upper_bound: | ||
return maximum | ||
return max(current, min(self.upper_bound, maximum / 2)) | ||
|
||
def apply(self): | ||
""" doing all the job, applying new buffer's size if required """ | ||
self.investigate() | ||
self.prefered = self.determine() | ||
if self.prefered == self.current: | ||
print "{0}'s RX ring buffer already has fine size.".format(self.dev) | ||
return | ||
assert self.prefered, "Can't eval prefered RX ring buffer size." | ||
command = 'ethtool -G {0} rx {1}'.format(self.dev, self.prefered) | ||
print 'run:', command | ||
system(command) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,7 +14,7 @@ def read(*paths): | |
|
||
setuptools.setup( | ||
name='netutils-linux', | ||
version='1.1.4', | ||
version='1.1.5', | ||
author='Oleg Strizhechenko', | ||
author_email='[email protected]', | ||
license='MIT', | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#!/usr/bin/env python | ||
|
||
import unittest | ||
from netutils_linux.rx_buffers import RxBuffersIncreaser | ||
|
||
|
||
class RxBuffersIncreaserTest(unittest.TestCase): | ||
""" | ||
Just in-memory test of evaluation rx-buffer's size. | ||
No device's settings changed. | ||
""" | ||
|
||
def setUp(self): | ||
self.rxbi = RxBuffersIncreaser(upper_bound=2048) | ||
|
||
def test_4096(self): | ||
self.assertEqual(self.rxbi.determine(256, 4096), 2048) | ||
self.assertEqual(self.rxbi.determine(512, 4096), 2048) | ||
self.assertEqual(self.rxbi.determine(2048, 4096), 2048) | ||
self.assertEqual(self.rxbi.determine(3072, 4096), 3072) | ||
self.assertEqual(self.rxbi.determine(4096, 4096), 4096) | ||
|
||
def test_511(self): | ||
self.assertEqual(self.rxbi.determine(200, 511), 511) | ||
self.assertEqual(self.rxbi.determine(511, 511), 511) | ||
self.assertEqual(self.rxbi.determine(400, 511), 511) | ||
|
||
def test_8096(self): | ||
self.assertEqual(self.rxbi.determine(200, 8096), 2048) | ||
self.assertEqual(self.rxbi.determine(2048, 8096), 2048) | ||
self.assertEqual(self.rxbi.determine(3000, 8096), 3000) | ||
self.assertEqual(self.rxbi.determine(8096, 8096), 8096) | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
#!/usr/bin/env python | ||
|
||
import unittest | ||
from netutils_linux.softnet_stat import SoftnetStat | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,116 +1,17 @@ | ||
#!/usr/bin/env python | ||
|
||
""" | ||
rx-buffers-increase utils, that finds and sets compromise-value | ||
between avoiding dropped/missing pkts and keeping a latency low. | ||
Finds and sets compromise-value between avoiding | ||
dropped/missing pkts and keeping a latency low. | ||
""" | ||
|
||
import sys | ||
from os import getenv, system, path | ||
from unittest import TestCase | ||
from unittest import main as test_main | ||
from subprocess import Popen, PIPE | ||
from os import getenv | ||
from netutils_linux.rx_buffers import RxBuffersIncreaser | ||
|
||
__author__ = 'Oleg Strizhechenko <[email protected]>' | ||
|
||
|
||
class RxBuffersIncreaser(object): | ||
|
||
""" | ||
0. Check if buffers already been setted up in ifcfg-ethX | ||
1. Determines what size of buffers available | ||
2. Evaluate one that fits for our purposes | ||
3. Apply it | ||
""" | ||
|
||
def __init__(self, dev=None, upper_bound=2048): | ||
self.dev = dev | ||
self.upper_bound = upper_bound | ||
self.current = 0 | ||
self.maximum = 0 | ||
self.prefered = None | ||
self.manual_tuned = False | ||
|
||
def __str__(self): | ||
attrs = ('dev', 'upper_bound', 'current', 'maximum', 'prefered') | ||
return str(dict((attr, self.__getattribute__(attr)) for attr in attrs)) | ||
|
||
def investigate(self): | ||
""" get maximum and current rx ring buffers values via ethtool """ | ||
def extract_value(s): | ||
return int(s.strip('RX:\t\n')) | ||
|
||
ns = '/etc/sysconfig/network-scripts/' | ||
with open(path.join(ns, 'ifcfg-' + self.dev)) as config: | ||
if any(line for line in config.xreadlines() if 'ETHTOOL_OPTS' in line): | ||
print "{0}'s RX ring buffer already manually tuned.".format(self.dev) | ||
exit(0) | ||
process = Popen(['ethtool', '-i', self.dev], stdout=PIPE, stderr=PIPE) | ||
_, _ = process.communicate() | ||
# silent fail if called for vlan/bridge/etc | ||
if process.returncode != 0: | ||
exit(0) | ||
process = Popen(['ethtool', '-g', self.dev], stdout=PIPE, stderr=PIPE) | ||
ethtool_buffers, _ = process.communicate() | ||
if process.returncode != 0: | ||
exit(1) | ||
ethtool_buffers = ethtool_buffers.split('\n') | ||
self.maximum = extract_value(ethtool_buffers[2]) | ||
self.current = extract_value(ethtool_buffers[7]) | ||
|
||
def determine(self, current=None, maximum=None): | ||
""" evaluate most fitting RX ring buffer's fize """ | ||
if not current: | ||
current = self.current | ||
if not maximum: | ||
maximum = self.maximum | ||
if current > self.upper_bound: | ||
return current | ||
if maximum < self.upper_bound: | ||
return maximum | ||
return max(current, min(self.upper_bound, maximum / 2)) | ||
|
||
def apply(self): | ||
""" doing all the job, applying new buffer's size if required """ | ||
self.investigate() | ||
self.prefered = self.determine() | ||
if self.prefered == self.current: | ||
print "{0}'s RX ring buffer already has fine size.".format(self.dev) | ||
return | ||
assert self.prefered, "Can't eval prefered RX ring buffer size." | ||
command = 'ethtool -G {0} rx {1}'.format(self.dev, self.prefered) | ||
print 'run:', command | ||
system(command) | ||
|
||
|
||
class RxBuffersIncreaserTest(TestCase): | ||
""" | ||
Just in-memory test of evaluation rx-buffer's size. | ||
No device's settings changed. | ||
""" | ||
|
||
def setUp(self): | ||
self.rxbi = RxBuffersIncreaser(upper_bound=2048) | ||
|
||
def test_4096(self): | ||
self.assertEqual(self.rxbi.determine(256, 4096), 2048) | ||
self.assertEqual(self.rxbi.determine(512, 4096), 2048) | ||
self.assertEqual(self.rxbi.determine(2048, 4096), 2048) | ||
self.assertEqual(self.rxbi.determine(3072, 4096), 3072) | ||
self.assertEqual(self.rxbi.determine(4096, 4096), 4096) | ||
|
||
def test_511(self): | ||
self.assertEqual(self.rxbi.determine(200, 511), 511) | ||
self.assertEqual(self.rxbi.determine(511, 511), 511) | ||
self.assertEqual(self.rxbi.determine(400, 511), 511) | ||
|
||
def test_8096(self): | ||
self.assertEqual(self.rxbi.determine(200, 8096), 2048) | ||
self.assertEqual(self.rxbi.determine(2048, 8096), 2048) | ||
self.assertEqual(self.rxbi.determine(3000, 8096), 3000) | ||
self.assertEqual(self.rxbi.determine(8096, 8096), 8096) | ||
|
||
|
||
def main(): | ||
""" Tune NIC's buffers if given in args """ | ||
upper_bound = int(getenv('RX_UPPER_BOUND', '2048')) | ||
|
@@ -119,7 +20,4 @@ def main(): | |
|
||
|
||
if __name__ == '__main__': | ||
if len(sys.argv) == 1: | ||
test_main() | ||
else: | ||
main() | ||
main() |