diff options
-rw-r--r-- | ansible/install_collectd.yml | 1 | ||||
-rwxr-xr-x | ansible/roles/download_pmu_tools/files/event_download_local.py | 100 | ||||
-rw-r--r-- | ansible/roles/download_pmu_tools/tasks/main.yml | 4 | ||||
-rw-r--r-- | etc/yardstick/nodes/pod.yaml.collectd.sample | 8 | ||||
-rw-r--r-- | tests/unit/network_services/nfvi/test_resource.py | 13 | ||||
-rw-r--r-- | yardstick/network_services/nfvi/collectd.conf | 18 | ||||
-rw-r--r-- | yardstick/network_services/nfvi/resource.py | 35 |
7 files changed, 119 insertions, 60 deletions
diff --git a/ansible/install_collectd.yml b/ansible/install_collectd.yml index 0824c1525..16021b77b 100644 --- a/ansible/install_collectd.yml +++ b/ansible/install_collectd.yml @@ -15,6 +15,7 @@ - hosts: all vars: clone_dir: /tmp/yardstick-clone + environment: "{{ proxy_env|default({}) }}" roles: # build shared DPDK for collectd only, required DPDK downloaded already diff --git a/ansible/roles/download_pmu_tools/files/event_download_local.py b/ansible/roles/download_pmu_tools/files/event_download_local.py index 882fc5046..8eda2cd0d 100755 --- a/ansible/roles/download_pmu_tools/files/event_download_local.py +++ b/ansible/roles/download_pmu_tools/files/event_download_local.py @@ -16,35 +16,46 @@ # event_download.py download for current cpu # event_download.py -a download all # event_download.py cpustr... Download for specific CPU +from __future__ import absolute_import +from __future__ import print_function import sys + import re -from urllib2 import urlopen, URLError import os import string from fnmatch import fnmatch from shutil import copyfile +try: + from urllib2 import URLError +except ImportError: + # python 3 + from urllib.error import URLError + + urlpath = 'https://download.01.org/perfmon' -localpath = 'download.01.org/perfmon' +localpath = 'pmu_local_mirror/download.01.org/perfmon' mapfile = 'mapfile.csv' modelpath = localpath + "/" + mapfile -NSB_JSON = '/opt/nsb_bin/pmu_event.json' +NSB_JSON = os.environ.get("PMU_EVENTS_PATH", "/tmp/pmu_event.json") + def get_cpustr(): - f = open('/proc/cpuinfo', 'r') - cpu = [None, None, None] - for j in f: - n = j.split() - if n[0] == 'vendor_id': - cpu[0] = n[2] - elif n[0] == 'model' and n[1] == ':': - cpu[2] = int(n[2]) - elif n[0] == 'cpu' and n[1] == 'family': - cpu[1] = int(n[3]) - if all(cpu): - break + with open('/proc/cpuinfo', 'r') as f: + cpu = [None, None, None] + for j in f: + n = j.split() + if n[0] == 'vendor_id': + cpu[0] = n[2] + elif n[0] == 'model' and n[1] == ':': + cpu[2] = int(n[2]) + elif n[0] == 'cpu' and n[1] == 'family': + cpu[1] = int(n[3]) + if all(cpu): + break return "%s-%d-%X" % (cpu[0], cpu[1], cpu[2]) + def sanitize(s, a): o = "" for j in s: @@ -52,13 +63,14 @@ def sanitize(s, a): o += j return o + def getdir(): try: d = os.getenv("XDG_CACHE_HOME") xd = d if not d: home = os.getenv("HOME") - d = "%s/.cache" % (home) + d = "%s/.cache" % home d += "/pmu-events" if not os.path.isdir(d): # try to handle the sudo case @@ -73,11 +85,13 @@ def getdir(): except OSError: raise Exception('Cannot access ' + d) + NUM_TRIES = 3 + def getfile(url, dir, fn): tries = 0 - print "Downloading", url, "to", fn + print("Downloading", url, "to", fn) while True: try: f = open(url) @@ -86,15 +100,17 @@ def getfile(url, dir, fn): tries += 1 if tries >= NUM_TRIES: raise - print "retrying download" + print("retrying download") continue break - o = open(os.path.join(dir, fn), "w") - o.write(data) - o.close() + with open(os.path.join(dir, fn), "w") as o: + o.write(data) f.close() + allowed_chars = string.ascii_letters + '_-.' + string.digits + + def download(match, key=None, link=True): found = 0 dir = getdir() @@ -105,14 +121,14 @@ def download(match, key=None, link=True): n = j.rstrip().split(",") if len(n) < 4: if len(n) > 0: - print "Cannot parse", n + print("Cannot parse", n) continue cpu, version, name, type = n if not fnmatch(cpu, match) or (key is not None and type not in key) or type.startswith("EventType"): continue cpu = sanitize(cpu, allowed_chars) url = localpath + name - fn = "%s-%s.json" % (cpu, sanitize(type, allowed_chars)) + fn = "%s-%s.json" % (cpu, sanitize(type, allowed_chars)) try: os.remove(os.path.join(dir, fn)) except OSError: @@ -128,34 +144,37 @@ def download(match, key=None, link=True): try: os.symlink(fn, os.path.join(dir, lname)) except OSError as e: - print >>sys.stderr, "Cannot link %s to %s:" % (name, lname), e + print("Cannot link %s to %s:" % (name, lname), e, file=sys.stderr) found += 1 models.close() getfile(localpath + "/readme.txt", dir, "readme.txt") except URLError as e: - print >>sys.stderr, "Cannot access event server:", e - print >>sys.stderr, "If you need a proxy to access the internet please set it with:" - print >>sys.stderr, "\texport https_proxy=http://proxyname..." - print >>sys.stderr, "If you are not connected to the internet please run this on a connected system:" - print >>sys.stderr, "\tevent_download.py '%s'" % (match) - print >>sys.stderr, "and then copy ~/.cache/pmu-events to the system under test" - print >>sys.stderr, "To get events for all possible CPUs use:" - print >>sys.stderr, "\tevent_download.py -a" + print("Cannot access event server:", e, file=sys.stderr) + print("If you need a proxy to access the internet please set it with:", file=sys.stderr) + print("\texport https_proxy=http://proxyname...", file=sys.stderr) + print("If you are not connected to the internet please run this on a connected system:", file=sys.stderr) + print("\tevent_download.py '%s'" % match, file=sys.stderr) + print("and then copy ~/.cache/pmu-events to the system under test", file=sys.stderr) + print("To get events for all possible CPUs use:", file=sys.stderr) + print("\tevent_download.py -a", file=sys.stderr) except OSError as e: - print >>sys.stderr, "Cannot write events file:", e + print("Cannot write events file:", e, file=sys.stderr) return found + def download_current(link=False): """Download JSON event list for current cpu. Returns >0 when a event list is found""" return download(get_cpustr(), link=link) + def eventlist_name(name=None, key="core"): if not name: name = get_cpustr() cache = getdir() return "%s/%s-%s.json" % (cache, name, key) + if __name__ == '__main__': # only import argparse when actually called from command line # this makes ocperf work on older python versions without it. @@ -164,18 +183,19 @@ if __name__ == '__main__': p.add_argument('--all', '-a', help='Download all available event files', action='store_true') p.add_argument('--verbose', '-v', help='Be verbose', action='store_true') p.add_argument('--mine', help='Print name of current CPU', action='store_true') - p.add_argument('--link', help='Create links with the original event file name', action='store_true', default=True) + p.add_argument('--link', help='Create links with the original event file name', + action='store_true', default=True) p.add_argument('cpus', help='CPU identifiers to download', nargs='*') args = p.parse_args() cpustr = get_cpustr() if args.verbose or args.mine: - print "My CPU", cpustr + print("My CPU", cpustr) if args.mine: sys.exit(0) d = getdir() if args.all: - found = download('*', link=args.link) + found = download('*', link=args.link) elif len(args.cpus) == 0: found = download_current(link=args.link) else: @@ -184,10 +204,10 @@ if __name__ == '__main__': found += download(j, link=args.link) if found == 0: - print >>sys.stderr, "Nothing found" + print("Nothing found", file=sys.stderr) el = eventlist_name() if os.path.exists(el): - print "my event list", el - copyfile(el,NSB_JSON) - print "File copied to ", NSB_JSON + print("my event list", el) + copyfile(el, NSB_JSON) + print("File copied to ", NSB_JSON) diff --git a/ansible/roles/download_pmu_tools/tasks/main.yml b/ansible/roles/download_pmu_tools/tasks/main.yml index e78cc72d6..3ef412217 100644 --- a/ansible/roles/download_pmu_tools/tasks/main.yml +++ b/ansible/roles/download_pmu_tools/tasks/main.yml @@ -29,13 +29,13 @@ pmu_tools_path: "{{ pmu_tools_dest }}" - name: Create perfmon local mirror - command: "wget -mkEpnp {{ perfmon_url }} -P {{ pmu_tools_dest }}" + command: "wget -mkEpnp {{ perfmon_url }} -P {{ INSTALL_BIN_PATH }}/pmu_local_mirror" ignore_errors: yes - name: Copy local event download file copy: src: event_download_local.py - dest: "{{ pmu_tools_dest }}" + dest: "{{ INSTALL_BIN_PATH }}/event_download_local.py" owner: root group: root mode: 0755 diff --git a/etc/yardstick/nodes/pod.yaml.collectd.sample b/etc/yardstick/nodes/pod.yaml.collectd.sample index 6ebf9e295..aae677ce6 100644 --- a/etc/yardstick/nodes/pod.yaml.collectd.sample +++ b/etc/yardstick/nodes/pod.yaml.collectd.sample @@ -21,5 +21,9 @@ nodes: password: r00t collectd: interval: 5 - plugins: - ovs_stats: {} +# plugins: +# intel_rdt: {} +# virt: {} +# ovs_stats: +# ovs_socket_path: /var/run/openvswitch/db.sock +# intel_pmu: {} diff --git a/tests/unit/network_services/nfvi/test_resource.py b/tests/unit/network_services/nfvi/test_resource.py index 799cc202b..f3244fdbd 100644 --- a/tests/unit/network_services/nfvi/test_resource.py +++ b/tests/unit/network_services/nfvi/test_resource.py @@ -134,6 +134,14 @@ class TestResourceProfile(unittest.TestCase): self.assertIsNone( self.resource_profile._prepare_collectd_conf("/opt/nsb_bin")) + def test__setup_intel_pmu(self): + self.assertIsNone( + self.resource_profile._setup_intel_pmu(self.ssh_mock, "/opt/nsb_bin")) + + def test__setup_ovs_stats(self): + self.assertIsNone( + self.resource_profile._setup_ovs_stats(self.ssh_mock)) + @mock.patch("yardstick.network_services.nfvi.resource.open") @mock.patch("yardstick.network_services.nfvi.resource.os") def test__provide_config_file(self, mock_open, mock_os): @@ -187,7 +195,6 @@ class TestResourceProfile(unittest.TestCase): res = self.resource_profile.parse_collectd_result({}) expected_result = {'cpu': {}, 'dpdkstat': {}, 'hugepages': {}, 'memory': {}, 'ovs_stats': {}, 'timestamp': '', - 'intel_pmu': {}, 'virt': {}} self.assertDictEqual(res, expected_result) @@ -200,7 +207,6 @@ class TestResourceProfile(unittest.TestCase): res = self.resource_profile.parse_collectd_result(metric) expected_result = {'cpu': {1: {'ipc': '1234'}}, 'dpdkstat': {}, 'hugepages': {}, 'memory': {}, 'ovs_stats': {}, 'timestamp': '', - 'intel_pmu': {}, 'virt': {}} self.assertDictEqual(res, expected_result) @@ -209,7 +215,6 @@ class TestResourceProfile(unittest.TestCase): res = self.resource_profile.parse_collectd_result(metric) expected_result = {'cpu': {}, 'dpdkstat': {}, 'hugepages': {}, 'memory': {'bw': '101'}, 'ovs_stats': {}, 'timestamp': '', - 'intel_pmu': {}, 'virt': {}} self.assertDictEqual(res, expected_result) @@ -220,7 +225,6 @@ class TestResourceProfile(unittest.TestCase): res = self.resource_profile.parse_collectd_result(metric) expected_result = {'cpu': {}, 'dpdkstat': {}, 'hugepages': {'free': '101'}, 'memory': {}, 'ovs_stats': {}, 'timestamp': '', - 'intel_pmu': {}, 'virt': {}} self.assertDictEqual(res, expected_result) @@ -237,7 +241,6 @@ class TestResourceProfile(unittest.TestCase): res = self.resource_profile.parse_collectd_result(metric) expected_result = {'cpu': {}, 'dpdkstat': {'tx': '101'}, 'hugepages': {}, 'memory': {}, 'ovs_stats': {'tx': '101'}, 'timestamp': '', - 'intel_pmu': {}, 'virt': {'memory': '101'}} self.assertDictEqual(res, expected_result) diff --git a/yardstick/network_services/nfvi/collectd.conf b/yardstick/network_services/nfvi/collectd.conf index e6a1f0d8c..b166fe7fd 100644 --- a/yardstick/network_services/nfvi/collectd.conf +++ b/yardstick/network_services/nfvi/collectd.conf @@ -24,10 +24,17 @@ Interval {{ interval }} ############################################################################## #LoadPlugin syslog -{% for plugin in loadplugins %} +{% for plugin in loadplugins if plugin != "ovs_stats" %} LoadPlugin {{ plugin }} {% endfor %} +{% if "ovs_stats" in plugins %} +<LoadPlugin ovs_stats> + Interval 1 +</LoadPlugin> +{% endif %} + + ############################################################################## # Plugin configuration # #----------------------------------------------------------------------------# @@ -82,12 +89,11 @@ LoadPlugin {{ plugin }} {% endif %} {% if "intel_pmu" in plugins %} -<Plugin intel_pmu> +<Plugin "intel_pmu"> ReportHardwareCacheEvents true ReportKernelPMUEvents true ReportSoftwareEvents true - EventList "/opt/nsb_bin/pmu_event.json" - HardwareEvents "L2_RQSTS.CODE_RD_HIT,L2_RQSTS.CODE_RD_MISS" "L2_RQSTS.ALL_CODE_RD" + EventList "{{ plugins['intel_pmu']['pmu_event_path'] }}" </Plugin> {% endif %} @@ -110,6 +116,8 @@ LoadPlugin {{ plugin }} {% if "virt" in plugins %} <Plugin "virt"> # monitor all domains + RefreshInterval 60 + ExtraStats "cpu_util disk disk_err domain_state fs_info job_stats_background pcpu perf vcpupin" </Plugin> {% endif %} @@ -117,7 +125,7 @@ LoadPlugin {{ plugin }} <Plugin "ovs_stats"> Port "6640" Address "127.0.0.1" - Socket "/usr/local/var/run/openvswitch/db.sock" + Socket "{{ plugins['ovs_stats']['ovs_socket_path'] }}" # don't specify bridges, monitor all bridges </Plugin> {% endif %} diff --git a/yardstick/network_services/nfvi/resource.py b/yardstick/network_services/nfvi/resource.py index fef44e207..dea754d8b 100644 --- a/yardstick/network_services/nfvi/resource.py +++ b/yardstick/network_services/nfvi/resource.py @@ -34,7 +34,7 @@ from yardstick import ssh from yardstick.common.task_template import finalize_for_yaml from yardstick.common.utils import validate_non_string_sequence from yardstick.network_services.nfvi.collectd import AmqpConsumer -from yardstick.network_services.utils import get_nsb_option + LOG = logging.getLogger(__name__) @@ -53,6 +53,7 @@ class ResourceProfile(object): AMPQ_PORT = 5672 DEFAULT_INTERVAL = 25 DEFAULT_TIMEOUT = 3600 + OVS_SOCKET_PATH = "/usr/local/var/run/openvswitch/db.sock" def __init__(self, mgmt, port_names=None, cores=None, plugins=None, interval=None, timeout=None): @@ -154,7 +155,6 @@ class ResourceProfile(object): "dpdkstat": {}, "virt": {}, "ovs_stats": {}, - "intel_pmu": {}, } testcase = "" @@ -233,10 +233,32 @@ class ResourceProfile(object): } self._provide_config_file(config_file_path, self.COLLECTD_CONF, kwargs) + def _setup_intel_pmu(self, connection, bin_path): + pmu_event_path = os.path.join(bin_path, "pmu_event.json") + try: + self.plugins["intel_pmu"]["pmu_event_path"] = pmu_event_path + except KeyError: + # if intel_pmu is not a dict, force it into a dict + self.plugins["intel_pmu"] = {"pmu_event_path": pmu_event_path} + LOG.debug("Downloading event list for pmu_stats plugin") + cmd = 'cd {0}; PMU_EVENTS_PATH={1} python event_download_local.py'.format( + bin_path, pmu_event_path) + cmd = "sudo bash -c '{}'".format(cmd) + connection.execute(cmd) + + def _setup_ovs_stats(self, connection): + try: + socket_path = self.plugins["ovs_stats"].get("ovs_socket_path", self.OVS_SOCKET_PATH) + except KeyError: + # ovs_stats is not a dict + socket_path = self.OVS_SOCKET_PATH + status = connection.execute("test -S {}".format(socket_path))[0] + if status != 0: + LOG.error("cannot find OVS socket %s", socket_path) + def _start_collectd(self, connection, bin_path): LOG.debug("Starting collectd to collect NFVi stats") connection.execute('sudo pkill -x -9 collectd') - bin_path = get_nsb_option("bin_path") collectd_path = os.path.join(bin_path, "collectd", "sbin", "collectd") config_file_path = os.path.join(bin_path, "collectd", "etc") exit_status = connection.execute("which %s > /dev/null 2>&1" % collectd_path)[0] @@ -251,9 +273,10 @@ class ResourceProfile(object): # collectd_installer, http_proxy, https_proxy)) return if "intel_pmu" in self.plugins: - LOG.debug("Downloading event list for pmu_stats plugin") - cmd = 'sudo bash -c \'cd /opt/tempT/pmu-tools/; python event_download_local.py\'' - connection.execute(cmd) + self._setup_intel_pmu(connection, bin_path) + if "ovs_stats" in self.plugins: + self._setup_ovs_stats(connection) + LOG.debug("Starting collectd to collect NFVi stats") # ensure collectd.conf.d exists to avoid error/warning connection.execute("sudo mkdir -p /etc/collectd/collectd.conf.d") |