def inspect_vnics(self, instance, duration): """Inspect the vNIC statistics for an instance. :param instance: the target instance :param duration: the last 'n' seconds, over which the value should be inspected. The PowerVM implementation does not make use of the duration field. :return: for each vNIC, the number of bytes & packets received and transmitted """ # Get the current and previous sample. Delta is performed between # these two. uuid = self._puuid(instance) cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid) # If the cur_metric is none, then the instance can not be found in the # sample and an error should be raised. if cur_metric is None: raise virt_inspector.InstanceNotFoundException( _('VM %s not found in PowerVM Metrics Sample.') % instance.name) # If there isn't network information, this is because the Virtual # I/O Metrics were turned off. Have to pass through this method. if cur_metric.network is None: return # Get the network interfaces. A 'cna' is a Client VM's Network Adapter client_cnas = self._get_cnas(uuid) for metric_cna in cur_metric.network.cnas: # Get the mac, but if it isn't found, then move to the next. Might # have been removed since the last sample. mac = self.mac_for_metric_cna(metric_cna, client_cnas) if mac is None: continue # The name will be the location code. MAC is identified from # above. Others appear libvirt specific. # # PowerVM doesn't specify drops by receive vs. transmit. Since we # have the client adapter, we assume all are receive drops. # There are no error metrics available. yield virt_inspector.InterfaceStats( name=metric_cna.physical_location, mac=mac, fref=None, parameters=None, rx_bytes=metric_cna.received_bytes, rx_packets=metric_cna.received_packets, rx_drop=metric_cna.dropped_packets, rx_errors=0, tx_bytes=metric_cna.sent_bytes, tx_packets=metric_cna.sent_packets, tx_drop=0, tx_errors=0)
def inspect_vnics(self, instance): """Inspect the vNIC statistics for an instance. :param instance: the target instance :return: for each vNIC, the number of bytes & packets received and transmitted """ # Get the current and previous sample. Delta is performed between # these two. uuid = self._puuid(instance) cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid) # If the cur_metric is none, then the instance can not be found in the # sample and an error should be raised. if cur_metric is None: raise virt_inspector.InstanceNotFoundException( _('VM %s not found in PowerVM Metrics Sample.') % instance.name) # If there isn't network information, this is because the Virtual # I/O Metrics were turned off. Have to pass through this method. if cur_metric.network is None: return # Get the network interfaces. A 'cna' is a Client VM's Network Adapter client_cnas = self._get_cnas(uuid) for metric_cna in cur_metric.network.cnas: # Get the mac, but if it isn't found, then move to the next. Might # have been removed since the last sample. mac = self.mac_for_metric_cna(metric_cna, client_cnas) if mac is None: continue # The name will be the location code. MAC is identified from # above. Others appear libvirt specific. interface = virt_inspector.Interface( name=metric_cna.physical_location, mac=mac, fref=None, parameters=None) stats = virt_inspector.InterfaceStats( rx_bytes=metric_cna.received_bytes, rx_packets=metric_cna.received_packets, tx_bytes=metric_cna.sent_bytes, tx_packets=metric_cna.sent_packets) # Yield the stats up to the invoker yield (interface, stats)
def inspect_disks(self, instance, duration): """Inspect the disk statistics for an instance. The response is a generator of the values. :param instance: the target instance :param duration: the last 'n' seconds, over which the value should be inspected. The PowerVM implementation does not make use of the duration field. :return disk: The Disk indicating the device for the storage device. :return stats: The DiskStats indicating the read/write data to the device. """ # Get the current and previous sample. Delta is performed between # these two. uuid = self._puuid(instance) cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid) # If the cur_metric is none, then the instance can not be found in the # sample and an error should be raised. if cur_metric is None: raise virt_inspector.InstanceNotFoundException( _('VM %s not found in PowerVM Metrics Sample.') % instance.name) # If there isn't storage information, this is because the Virtual # I/O Metrics were turned off. Have to pass through this method. if cur_metric.storage is None: LOG.debug("Current storage metric was unavailable from the API " "instance %s." % instance.name) return # Bundle together the SCSI and virtual FC adapters adpts = cur_metric.storage.virt_adpts + cur_metric.storage.vfc_adpts # Loop through all the storage adapters for adpt in adpts: # PowerVM only shows the connection (SCSI or FC). Name after # the connection name yield virt_inspector.DiskStats(device=adpt.name, read_requests=adpt.num_reads, read_bytes=adpt.read_bytes, write_requests=adpt.num_writes, write_bytes=adpt.write_bytes, errors=0, wr_total_times=0, rd_total_times=0)
def _get_host_uuid(self, adpt): """Returns the Host system's UUID for pypowervm. The pypowervm API needs a UUID of the server that it is managing. This method returns the UUID of that host. :param adpt: The pypowervm adapter. :return: The UUID of the host system. """ hosts = pvm_ms.System.wrap(adpt.read(pvm_ms.System.schema_type)) if len(hosts) != 1: raise Exception(_("Expected exactly one host; found %d."), len(hosts)) LOG.debug("Host UUID: %s" % hosts[0].uuid) return hosts[0].uuid
def _get_host_uuid(self, adpt): """Returns the Host systems UUID for pypowervm. The pypowervm API needs a UUID of the server that it is managing. This method returns the UUID of that host. :param adpt: The pypowervm adapter. :return: The UUID of the host system. """ hosts = pvm_ms.System.wrap(adpt.read(pvm_ms.System.schema_type)) if len(hosts) != 1: raise Exception(_("Expected exactly one host; found %d."), len(hosts)) LOG.debug("Host UUID: %s" % hosts[0].uuid) return hosts[0].uuid
def inspect_disks(self, instance): """Inspect the disk statistics for an instance. The response is a generator of the values. :param instance: the target instance :return disk: The Disk indicating the device for the storage device. :return stats: The DiskStats indicating the read/write data to the device. """ # Get the current and previous sample. Delta is performed between # these two. uuid = self._puuid(instance) cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid) # If the cur_metric is none, then the instance can not be found in the # sample and an error should be raised. if cur_metric is None: raise virt_inspector.InstanceNotFoundException( _('VM %s not found in PowerVM Metrics Sample.') % instance.name) # If there isn't storage information, this is because the Virtual # I/O Metrics were turned off. Have to pass through this method. if cur_metric.storage is None: LOG.debug("Current storage metric was unavailable from the API " "instance %s." % instance.name) return # Bundle together the SCSI and virtual FC adapters adpts = cur_metric.storage.virt_adpts + cur_metric.storage.vfc_adpts # Loop through all the storage adapters for adpt in adpts: # PowerVM only shows the connection (SCSI or FC). Name after # the connection name disk = virt_inspector.Disk(device=adpt.name) stats = virt_inspector.DiskStats( read_requests=adpt.num_reads, read_bytes=adpt.read_bytes, write_requests=adpt.num_writes, write_bytes=adpt.write_bytes, errors=0) yield (disk, stats)
def inspect_cpus(self, instance): """Inspect the CPU statistics for an instance. :param instance: the target instance :return: the number of CPUs and cumulative CPU time """ uuid = self._puuid(instance) cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid) # If the current metric is none, then the instance can not be found in # the sample set. An error should be raised. if cur_metric is None: raise virt_inspector.InstanceNotFoundException( _('VM %s not found in PowerVM Metrics Sample.') % instance.name) cpu_time = (cur_metric.processor.util_cap_proc_cycles + cur_metric.processor.util_uncap_proc_cycles) return virt_inspector.CPUStats(number=cur_metric.processor.virt_procs, time=cpu_time)
def inspect_instance(self, instance, duration): """Inspect the statistics for an instance. :param instance: the target instance :param duration: the last 'n' seconds, over which the value should be inspected. The PowerVM implementation does not make use of the duration field. :return: the instance statistics """ uuid = self._puuid(instance) cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid) # If the current metric is none, then the instance can not be found in # the sample set. An error should be raised. if cur_metric is None: raise virt_inspector.InstanceNotFoundException( _('VM %s not found in PowerVM Metrics Sample.') % instance.name) cpu_time = (cur_metric.processor.util_cap_proc_cycles + cur_metric.processor.util_uncap_proc_cycles) cpu_num = cur_metric.processor.virt_procs # The duration is ignored. There is precedent for this in other # inspectors if the platform doesn't support duration. # # Given the nature of PowerVM to collect samples over coarse periods # of time, it does not lend well to duration based collection. # Therefore this works by gathering the latest utilization from the # samples and ignores the duration. # Get the current and previous sample. Delta is performed between # these two. prev_date, prev_metric = self.vm_metrics.get_previous_metric(uuid) # Get the current data. cur_util_cap = cur_metric.processor.util_cap_proc_cycles cur_util_uncap = cur_metric.processor.util_uncap_proc_cycles cur_idle = cur_metric.processor.idle_proc_cycles cur_donated = cur_metric.processor.donated_proc_cycles cur_entitled = cur_metric.processor.entitled_proc_cycles # Get the previous sample data if prev_metric is None: # If there is no previous sample, that is either a new VM or is # a live migrated system. A live migrated system will pull all # of its metrics with it. The issue with this is it could have # CPU cycles for months of run time. So we can't really determine # the CPU utilization within the last X seconds...because to THIS # host it's new (only in the cur_metric). So we error out, the # inspector will use a debug message in the log. LOG.warning( 'Unable to derive CPU Utilization for VM %s. It is ' 'either a new VM or was recently migrated. It will be ' 'collected in the next inspection cycle.', instance.name) return virt_inspector.InstanceStats(cpu_time=cpu_time, cpu_number=cpu_num) # Gather the previous metrics prev_util_cap = prev_metric.processor.util_cap_proc_cycles prev_util_uncap = prev_metric.processor.util_uncap_proc_cycles prev_idle = prev_metric.processor.idle_proc_cycles prev_donated = prev_metric.processor.donated_proc_cycles prev_entitled = prev_metric.processor.entitled_proc_cycles # Utilization can be driven by multiple factors on PowerVM. # PowerVM has 'entitled' cycles. These are cycles that, if the VM # needs them, they get them no matter what. # # In terms of how those cycles are returned from the API: # util_cap_proc_cycles - How many cycles from the guaranteed # capacity were used. # util_uncap_proc_cycles - How many cycles were used that were # taken from spare (which is either unused processors cycles # or donated cycles from other VMs). # idle_proc_cycles - How many cycles (as reported by the OS to the # hypervisor) were reported as idle. # donated_proc_cycles - Cycles that were not needed by this VM that # were given to another VM in need of cycles. # # # So the final utilization equation is: # (util cap + util uncap - idle - donated) / entitled # # It is important to note that idle and donated proc cycles are # included in the 'util_cap_proc_cycles'. That is why they are # subtracted out. # # The interesting aspect of this is that the CPU Utilization can go # dramatically above 100% if there are free processors or if the # other workloads are in a lull. util_cap = cur_util_cap - prev_util_cap util_uncap = cur_util_uncap - prev_util_uncap idle = cur_idle - prev_idle donated = cur_donated - prev_donated entitled = cur_entitled - prev_entitled # If the entitled is zero, that generally means that the VM has not # been started yet (everything else would be zero as well). So to # avoid a divide by zero error, just return 0% in that case. util = (float(util_cap + util_uncap - idle - donated) / float(entitled) if entitled else 0.0) # Utilization is reported as percents. Therefore, multiply by 100.0 # to get a readable percentage based format. return virt_inspector.InstanceStats(cpu_util=util * 100.0, cpu_time=cpu_time, cpu_number=cpu_num)
def inspect_disk_iops(self, instance, duration): """Inspect the Disk Input/Output operations per second for an instance. The response is a generator of the values. :param instance: the target instance :param duration: the last 'n' seconds, over which the value should be inspected. The PowerVM implementation does not make use of the duration field. :return disk: The Disk indicating the device for the storage device. :return stats: The DiskIOPSStats indicating the I/O operations per second for the device. """ # Get the current and previous sample. Delta is performed between # these two. uuid = self._puuid(instance) cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid) prev_date, prev_metric = self.vm_metrics.get_previous_metric(uuid) # If the cur_metric is none, then the instance can not be found in the # sample and an error should be raised. if cur_metric is None: raise virt_inspector.InstanceNotFoundException( _('VM %s not found in PowerVM Metrics Sample.') % instance.name) # If there isn't storage information, this may be because the Virtual # I/O Metrics were turned off. If the previous metric is unavailable, # also have to pass through this method. if (cur_metric.storage is None or prev_metric is None or prev_metric.storage is None): LOG.debug("Current storage metric was unavailable from the API " "instance %s." % instance.name) return # Need to determine the time delta between the samples. This is # usually 30 seconds from the API, but the metrics will be specific. # However, if there is no previous sample, then we have to estimate. # Therefore, we estimate 15 seconds - half of the standard 30 seconds. date_delta = ((cur_date - prev_date) if prev_date is not None else datetime.timedelta(seconds=15)) # Bundle together the SCSI and virtual FC adapters cur_adpts = (cur_metric.storage.virt_adpts + cur_metric.storage.vfc_adpts) prev_adpts = (prev_metric.storage.virt_adpts + prev_metric.storage.vfc_adpts) def find_prev(cur_adpt): for prev_adpt in prev_adpts: if prev_adpt.name == cur_adpt.name: return prev_adpt return None # Loop through all the storage adapters for cur_adpt in cur_adpts: # IOPs is the read/write counts of the current - prev divided by # second difference between the two, rounded to the integer. :-) cur_ops = cur_adpt.num_reads + cur_adpt.num_writes # The previous adapter may be None. This simply indicates that the # adapter was added between the previous sample and this one. It # does not indicate a live migrate scenario like noted above, as # the VM itself hasn't moved. prev_adpt = find_prev(cur_adpt) prev_ops = ((prev_adpt.num_reads + prev_adpt.num_writes) if prev_adpt else 0) iops = (cur_ops - prev_ops) // date_delta.seconds # PowerVM only shows the connection (SCSI or FC). Name after # the connection name yield virt_inspector.DiskIOPSStats(device=cur_adpt.name, iops_count=iops)
def inspect_vnic_rates(self, instance, duration): """Inspect the vNIC rate statistics for an instance. :param instance: the target instance :param duration: the last 'n' seconds, over which the value should be inspected The PowerVM implementation does not make use of the duration field. :return: for each vNIC, the rate of bytes & packets received and transmitted """ # Get the current and previous sample. Delta is performed between # these two. uuid = self._puuid(instance) cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid) prev_date, prev_metric = self.vm_metrics.get_previous_metric(uuid) # If the current is none, then the instance can not be found in the # sample and an error should be raised. if cur_metric is None: raise virt_inspector.InstanceNotFoundException( _('VM %s not found in PowerVM Metrics Sample.') % instance.name) # If there isn't network information, this is because the Virtual # I/O Metrics were turned off. Have to pass through this method. if (cur_metric.network is None or prev_metric is None or prev_metric.network is None): return # Get the network interfaces. A 'cna' is a Client VM's Network Adapter client_cnas = self._get_cnas(uuid) def find_prev_net(metric_cna): """Finds the metric vNIC from the previous sample's vNICs.""" # If no previous, return None if prev_metric is None or prev_metric.network is None: return None for prev_cna in prev_metric.network.cnas: if prev_cna.physical_location == metric_cna.physical_location: return prev_cna # Couldn't find a previous. Maybe the interface was recently # added to the instance? Return None return None # Need to determine the time delta between the samples. This is # usually 30 seconds from the API, but the metrics will be specific. date_delta_num = float((cur_date - prev_date).seconds) for metric_cna in cur_metric.network.cnas: # Get the mac, but if it isn't found, then move to the next. Might # have been removed since the last sample. mac = self.mac_for_metric_cna(metric_cna, client_cnas) if mac is None: continue # Note that here, the previous may be none. That simply indicates # that the adapter was dynamically added to the VM before the # previous collection. Not the migration scenario above. # In this case, we can default the base to 0. prev = find_prev_net(metric_cna) rx_bytes_diff = (metric_cna.received_bytes - (0 if prev is None else prev.received_bytes)) tx_bytes_diff = (metric_cna.sent_bytes - (0 if prev is None else prev.sent_bytes)) # Stats are the difference in the bytes, divided by the difference # in time between the two samples. rx_rate = float(rx_bytes_diff) / float(date_delta_num) tx_rate = float(tx_bytes_diff) / float(date_delta_num) # The name will be the location code. MAC is identified from # above. Others appear libvirt specific. yield virt_inspector.InterfaceRateStats( name=metric_cna.physical_location, mac=mac, fref=None, parameters=None, rx_bytes_rate=rx_rate, tx_bytes_rate=tx_rate)
def inspect_disk_iops(self, instance): """Inspect the Disk Input/Output operations per second for an instance. The response is a generator of the values. :param instance: the target instance :return disk: The Disk indicating the device for the storage device. :return stats: The DiskIOPSStats indicating the I/O operations per second for the device. """ # Get the current and previous sample. Delta is performed between # these two. uuid = self._puuid(instance) cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid) prev_date, prev_metric = self.vm_metrics.get_previous_metric(uuid) # If the cur_metric is none, then the instance can not be found in the # sample and an error should be raised. if cur_metric is None: raise virt_inspector.InstanceNotFoundException( _('VM %s not found in PowerVM Metrics Sample.') % instance.name) # If there isn't storage information, this may be because the Virtual # I/O Metrics were turned off. If the previous metric is unavailable, # also have to pass through this method. if (cur_metric.storage is None or prev_metric is None or prev_metric.storage is None): LOG.debug("Current storage metric was unavailable from the API " "instance %s." % instance.name) return # Need to determine the time delta between the samples. This is # usually 30 seconds from the API, but the metrics will be specific. # However, if there is no previous sample, then we have to estimate. # Therefore, we estimate 15 seconds - half of the standard 30 seconds. date_delta = ((cur_date - prev_date) if prev_date is not None else datetime.timedelta(seconds=15)) # Bundle together the SCSI and virtual FC adapters cur_adpts = (cur_metric.storage.virt_adpts + cur_metric.storage.vfc_adpts) prev_adpts = (prev_metric.storage.virt_adpts + prev_metric.storage.vfc_adpts) def find_prev(cur_adpt): for prev_adpt in prev_adpts: if prev_adpt.name == cur_adpt.name: return prev_adpt return None # Loop through all the storage adapters for cur_adpt in cur_adpts: # IOPs is the read/write counts of the current - prev divided by # second difference between the two, rounded to the integer. :-) cur_ops = cur_adpt.num_reads + cur_adpt.num_writes # The previous adapter may be None. This simply indicates that the # adapter was added between the previous sample and this one. It # does not indicate a live migrate scenario like noted above, as # the VM itself hasn't moved. prev_adpt = find_prev(cur_adpt) prev_ops = ((prev_adpt.num_reads + prev_adpt.num_writes) if prev_adpt else 0) iops = (cur_ops - prev_ops) // date_delta.seconds # PowerVM only shows the connection (SCSI or FC). Name after # the connection name disk = virt_inspector.Disk(device=cur_adpt.name) stats = virt_inspector.DiskIOPSStats(iops_count=iops) yield (disk, stats)
def inspect_vnic_rates(self, instance, duration=None): """Inspect the vNIC rate statistics for an instance. :param instance: the target instance :param duration: the last 'n' seconds, over which the value should be inspected The PowerVM implementation does not make use of the duration field. :return: for each vNIC, the rate of bytes & packets received and transmitted """ # Get the current and previous sample. Delta is performed between # these two. uuid = self._puuid(instance) cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid) prev_date, prev_metric = self.vm_metrics.get_previous_metric(uuid) # If the current is none, then the instance can not be found in the # sample and an error should be raised. if cur_metric is None: raise virt_inspector.InstanceNotFoundException( _('VM %s not found in PowerVM Metrics Sample.') % instance.name) # If there isn't network information, this is because the Virtual # I/O Metrics were turned off. Have to pass through this method. if (cur_metric.network is None or prev_metric is None or prev_metric.network is None): return # Get the network interfaces. A 'cna' is a Client VM's Network Adapter client_cnas = self._get_cnas(uuid) def find_prev_net(metric_cna): """Finds the metric vNIC from the previous sample's vNICs.""" # If no previous, return None if prev_metric is None or prev_metric.network is None: return None for prev_cna in prev_metric.network.cnas: if prev_cna.physical_location == metric_cna.physical_location: return prev_cna # Couldn't find a previous. Maybe the interface was recently # added to the instance? Return None return None # Need to determine the time delta between the samples. This is # usually 30 seconds from the API, but the metrics will be specific. date_delta_num = float((cur_date - prev_date).seconds) for metric_cna in cur_metric.network.cnas: # Get the mac, but if it isn't found, then move to the next. Might # have been removed since the last sample. mac = self.mac_for_metric_cna(metric_cna, client_cnas) if mac is None: continue # The name will be the location code. MAC is identified from # above. Others appear libvirt specific. interface = virt_inspector.Interface( name=metric_cna.physical_location, mac=mac, fref=None, parameters=None) # Note that here, the previous may be none. That simply indicates # that the adapter was dynamically added to the VM before the # previous collection. Not the migration scenario above. # In this case, we can default the base to 0. prev = find_prev_net(metric_cna) rx_bytes_diff = (metric_cna.received_bytes - (0 if prev is None else prev.received_bytes)) tx_bytes_diff = (metric_cna.sent_bytes - (0 if prev is None else prev.sent_bytes)) # Stats are the difference in the bytes, divided by the difference # in time between the two samples. rx_rate = float(rx_bytes_diff) / float(date_delta_num) tx_rate = float(tx_bytes_diff) / float(date_delta_num) stats = virt_inspector.InterfaceRateStats(rx_rate, tx_rate) # Yield the results back to the invoker. yield (interface, stats)
def inspect_cpu_util(self, instance, duration=None): """Inspect the CPU Utilization (%) for an instance. :param instance: the target instance :param duration: the last 'n' seconds, over which the value should be inspected. The PowerVM implementation does not make use of the duration field. :return: the percentage of CPU utilization """ # The duration is ignored. There is precedent for this in other # inspectors if the platform doesn't support duration. # # Given the nature of PowerVM to collect samples over coarse periods # of time, it does not lend well to duration based collection. # Therefore this works by gathering the latest utilization from the # samples and ignores the duration. # Get the current and previous sample. Delta is performed between # these two. uuid = self._puuid(instance) cur_date, cur_metric = self.vm_metrics.get_latest_metric(uuid) prev_date, prev_metric = self.vm_metrics.get_previous_metric(uuid) # If the current is none, then the instance can not be found in the # sample and an error should be raised. if cur_metric is None: raise virt_inspector.InstanceNotFoundException( _('VM %s not found in PowerVM Metrics Sample.') % instance.name) # Get the current data. cur_util_cap = cur_metric.processor.util_cap_proc_cycles cur_util_uncap = cur_metric.processor.util_uncap_proc_cycles cur_idle = cur_metric.processor.idle_proc_cycles cur_donated = cur_metric.processor.donated_proc_cycles cur_entitled = cur_metric.processor.entitled_proc_cycles # Get the previous sample data if prev_metric is None: # If there is no previous sample, that is either a new VM or is # a live migrated system. A live migrated system will pull all # of its metrics with it. The issue with this is it could have # CPU cycles for months of run time. So we can't really determine # the CPU utilization within the last X seconds...because to THIS # host its new (only in the cur_metric). So we error out, the # inspector will use a debug message in the log. LOG.warn(_LW("Unable to derive CPU Utilization for VM %s. It is " "either a new VM or was recently migrated. It will " "be collected in the next inspection cycle."), instance.name) message = (_("Unable to derive CPU Utilization for VM %s.") % instance.name) raise virt_inspector.InstanceNotFoundException(message) # Gather the previous metrics prev_util_cap = prev_metric.processor.util_cap_proc_cycles prev_util_uncap = prev_metric.processor.util_uncap_proc_cycles prev_idle = prev_metric.processor.idle_proc_cycles prev_donated = prev_metric.processor.donated_proc_cycles prev_entitled = prev_metric.processor.entitled_proc_cycles # Utilization can be driven by multiple factors on PowerVM. # PowerVM has 'entitled' cycles. These are cycles that, if the VM # needs them, they get them no matter what. # # In terms of how those cycles are returned from the API: # util_cap_proc_cycles - How many cycles from the guaranteed # capacity were used. # util_uncap_proc_cycles - How many cycles were used that were # taken from spare (which is either unused processors cycles # or donated cycles from other VMs). # idle_proc_cycles - How many cycles (as reported by the OS to the # hypervisor) were reported as idle. # donated_proc_cycles - Cycles that were not needed by this VM that # were given to another VM in need of cycles. # # # So the final utilization equation is: # (util cap + util uncap - idle - donated) / entitled # # It is important to note that idle and donated proc cycles are # included in the 'util_cap_proc_cycles'. That is why they are # subtracted out. # # The interesting aspect of this is that the CPU Utilization can go # dramatically above 100% if there are free processors or if the # other workloads are in a lull. util_cap = cur_util_cap - prev_util_cap util_uncap = cur_util_uncap - prev_util_uncap idle = cur_idle - prev_idle donated = cur_donated - prev_donated entitled = cur_entitled - prev_entitled # If the entitled is zero, that generally means that the VM has not # been started yet (everything else would be zero as well). So to # avoid a divide by zero error, just return 0% in that case. if entitled == 0: return virt_inspector.CPUUtilStats(util=0.0) util = float(util_cap + util_uncap - idle - donated) / float(entitled) # Utilization is reported as percents. Therefore, multiply by 100.0 # to get a readable percentage based format. return virt_inspector.CPUUtilStats(util=util * 100.0)