def _parse_turbostat_line(heading, line): """Parse a single turbostat line.""" line_data = {} for key, value in zip_longest(heading.keys(), line): if value is not None and value != "-": if not heading[key]: if Trivial.is_int(value): heading[key] = int elif Trivial.is_float(value): heading[key] = float else: heading[key] = str line_data[key] = heading[key](value) return line_data
def set_intervals(self, intervals): """ Set intervals for statistics collectors. The 'intervals' argument should be a dictionary with statistics collector names as keys and the collection interval as the value. This method should be called prior to the 'configure()' method. By default the statistics collectors use intervals from the 'DEFAULT_STINFO' statistics description dictionary. Returns a dictionary of the same structure as 'interval', but with interval values that will actually be used for all the statistics collectors. """ # Convert intervals to strings and get rid of the trailing ".0" from the final string. for stname, interval in intervals.items(): if not Trivial.is_float(interval): raise Error( f"bad interval value '{interval}' for '{stname}' statistics" ) self.stinfo[stname]["interval"] = float(interval) actual = {} for stname, stinfo in self.stinfo.items(): if stinfo.get("interval"): actual[stname] = stinfo.get("interval") return actual
def _next(self): """ Generator which yields a dictionary corresponding to one snapshot of turbostat output at a time. """ cpus = {} table_started = False nontable = {} heading = totals = None tbl_regex = re.compile(self._cols_regex) for line in self._lines: # Ignore empty and 'jitter' lines like "turbostat: cpu65 jitter 2574 5881". if not line or line.startswith("turbostat: "): continue # Match the beginning of the turbostat table. if not table_started and not re.match(tbl_regex, line): _add_nontable_data(nontable, line) continue line = line.split() if Trivial.is_float(line[0]): # This is the continuation of the table we are currently parsing. It starts either # with a floating-point 'Time_Of_Day_Seconds' an integer 'Core' value. Each line # describes a single CPU. cpu_data = _parse_turbostat_line(heading, line) cpus[cpu_data["CPU"]] = cpu_data else: # This is the start of the new table. if cpus or table_started: if not cpus: # This is the the special case for single-CPU systems. Turbostat does not # print the totals because there is only one CPU and totals is the the same # as the CPU information. cpus[0] = totals yield _construct_the_result(totals, cpus, nontable) nontable = {} cpus = {} heading = {} for key in line: if "%" in key or "Watt" in key or key in {"Time_Of_Day_Seconds", "IPC"}: heading[key] = float elif key in ("Package", "Core", "CPU"): heading[key] = str else: heading[key] = None # The next line is total statistics across all CPUs, exept if there is only one # single CPU in the system. # False pylint warning, see issue: https://github.com/PyCQA/pylint/issues/1830 line = next(self._lines).split() # pylint: disable=stop-iteration-return # On systems with a single core turbostat does not include the "Core" colum. Similar # to single CPU systems - the CPU column is excluded. Make sure we always have them. for key in ("Core", "CPU"): if key not in heading: heading[key] = str line.append("0") totals = _parse_turbostat_line(heading, line) table_started = True yield _construct_the_result(totals, cpus, nontable)