Source code for yardstick.benchmark.scenarios.compute.cpuload

##############################################################################
# Copyright (c) 2015 Ericsson AB and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################

"""Processor statistics and system load."""

import logging
import time
import re
import yardstick.ssh as ssh

from yardstick.benchmark.scenarios import base


LOG = logging.getLogger(__name__)


[docs]class CPULoad(base.Scenario): """Collect processor statistics and system load. This scenario reads system load averages and CPU usage statistics on a Linux host. CPU usage statistics are read using the utility 'mpstat'. If 'mpstat' is not installed on the host usage statistics are instead read directly from '/proc/stat'. Load averages are read from the file '/proc/loadavg' on the Linux host. Parameters interval - Time interval to measure CPU usage. A value of 0 indicates that processors statistics are to be reported for the time since system startup (boot) type: [int] unit: seconds default: 0 """ __scenario_type__ = "CPUload" MPSTAT_FIELD_SIZE = 10 def __init__(self, scenario_cfg, context_cfg): """Scenario construction.""" self.scenario_cfg = scenario_cfg self.context_cfg = context_cfg self.setup_done = False self.has_mpstat = False
[docs] def setup(self): """Scenario setup.""" host = self.context_cfg['host'] user = host.get('user', 'ubuntu') ip = host.get('ip', None) key_filename = host.get('key_filename', '~/.ssh/id_rsa') LOG.info("user:%s, host:%s", user, ip) self.client = ssh.SSH(user, ip, key_filename=key_filename) self.client.wait(timeout=600) # Check if mpstat prog is installed status, _, _ = self.client.execute("mpstat -V >/dev/null 2>&1") if status != 0: LOG.info("MPSTAT is NOT installed") self.has_mpstat = False else: LOG.info("MPSTAT is installed") self.has_mpstat = True if 'options' in self.scenario_cfg: self.interval = self.scenario_cfg['options'].get("interval", 0) else: self.interval = 0 self.setup_done = True
def _execute_command(self, cmd): """Execute a command on server.""" LOG.info("Executing: %s" % cmd) status, stdout, stderr = self.client.execute(cmd) if status != 0: raise RuntimeError("Failed executing command: ", cmd, stderr) return stdout def _get_loadavg(self): """Get system load.""" return {'loadavg': self._execute_command("cat /proc/loadavg").split()} def _get_cpu_usage_mpstat(self): """Get processor usage using mpstat.""" if self.interval > 0: cmd = "mpstat -P ON %s 1" % self.interval else: cmd = "mpstat -P ON" result = self._execute_command(cmd) fields = [] mpstat = {} time_marker = re.compile("^([0-9]+):([0-9]+):([0-9]+)$") ampm_marker = re.compile("(AM|PM)$") # Parse CPU stats for row in result.split('\n'): line = row.split() if line and re.match(time_marker, line[0]): if re.match(ampm_marker, line[1]): del line[:2] else: del line[:1] if line[0] == 'CPU': # header fields fields = line[1:] if len(fields) != CPULoad.MPSTAT_FIELD_SIZE: raise RuntimeError("mpstat: unexpected field size", fields) else: # value fields cpu = 'cpu' if line[0] == 'all' else 'cpu' + line[0] values = line[1:] if values and len(values) == len(fields): mpstat[cpu] = dict(zip(fields, values)) else: raise RuntimeError("mpstat: parse error", fields, line) return {'mpstat': mpstat} def _get_cpu_usage(self): """Get processor usage from /proc/stat.""" fields = ['%usr', '%nice', '%sys', '%idle', '%iowait', '%irq', '%soft', '%steal', '%guest', '%gnice'] cmd = "grep '^cpu[0-9 ].' /proc/stat" if self.interval > 0: previous = self._execute_command(cmd).splitlines() time.sleep(self.interval) current = self._execute_command(cmd).splitlines() else: current = self._execute_command(cmd).splitlines() previous = current mpstat = {} for (prev, cur) in zip(previous, current): # Split string to list tokens cur_list = cur.split() prev_list = prev.split() cpu = cur_list[0] cur_stats = map(int, cur_list[1:]) if self.interval > 0: prev_stats = map(int, prev_list[1:]) else: prev_stats = [0] * len(cur_stats) # NB: Don't add 'guest' and 'gnice' as they # are already included in 'usr' and 'nice'. uptime_prev = sum(prev_stats[0:8]) uptime_cur = sum(cur_stats[0:8]) # Remove 'guest' and 'gnice' from 'usr' and 'nice' prev_stats[0] -= prev_stats[8] prev_stats[1] -= prev_stats[9] cur_stats[0] -= cur_stats[8] cur_stats[1] -= cur_stats[9] # number of samples (jiffies) in the interval samples = (uptime_cur - uptime_prev) or 1 def _percent(x, y): if x < y: return 0.0 else: return "%.2f" % (100.0 * (x - y) / samples) load = map(_percent, cur_stats, prev_stats) mpstat[cpu] = dict(zip(fields, load)) return {'mpstat': mpstat}
[docs] def run(self, result): """Read processor statistics.""" if not self.setup_done: self.setup() result.update(self._get_loadavg()) if self.has_mpstat: result.update(self._get_cpu_usage_mpstat()) else: result.update(self._get_cpu_usage()) # Note: No SLA as this scenario is only collecting statistics # def _test(): # """internal test function.""" # import pkg_resources # key_filename = pkg_resources.resource_filename('yardstick.resources', # 'files/yardstick_key') # ctx = { # 'host': { # 'ip': '172.16.0.175', # 'user': 'ubuntu', # 'key_filename': key_filename # } # } # logger = logging.getLogger('yardstick') # logger.setLevel(logging.DEBUG) # args = {} # result = {} # p = CPULoad(args, ctx) # p.run(result) # import json # print json.dumps(result) # if __name__ == '__main__': # _test()