#!/usr/bin/env python3
"""
Utilities for displaying reports generated by the Intel VTune profiler.
"""
# Imports
import numpy as np
import pandas as pd
from gcpy.util import verify_variable_type
# Constants
DELIMITER = "\t"
LINES_PER_SCREEN = 30
[docs]
def vtune_read_hotspots_csv(
filename,
delimiter=DELIMITER
):
"""
Reads a hotspot report (in CSV format) generated by Intel VTune.
Parameters
----------
filename : str
Hotspots report in CSV format.
delimiter : str, optional
Text separator.
Default value: "\\t" (tab)
Returns
-------
report : pandas.DataFrame
DataFrame with hotspot information.
"""
verify_variable_type(filename, str)
report = pd.read_csv(
filename,
delimiter=delimiter,
skipinitialspace=True,
engine="c",
dtype=str,
)
if "CPU Time" in report.columns:
report = report.rename(columns={"CPU Time": "CPU Time [s]"})
return report
[docs]
def vtune_how_is_report_grouped(
report
):
"""
Determines how a VTune hotspot report is grouped.
Parameters
----------
report : pandas.DataFrame
Hotspot report data.
Returns
-------
result : str
Returns 'by_line' or 'by_function'.
"""
if "Source Line" in report.columns:
return "by_line"
if "Function" in report.columns:
return "by_function"
raise ValueError("Could not determine how report is grouped!")
[docs]
def vtune_ask_user_to_continue_or_quit(
header,
linecount,
lines_per_screen,
):
"""
Ask user if they wish to display more lines of VTune information
to the screen, or if they wish to quit.
Parameters
----------
header : str
Header line for hotspot report.
linecount : int
Index of the line being displayed.
lines_per_screen : int
Pause after showing these many lines.
Returns
-------
result : bool
True if user wishes to quit.
"""
if linecount % lines_per_screen == 0:
result = input(
"\nPress ENTER to continue, or Q/q then ENTER to quit >>> "
)
# User wishes to quit
if "Q" in result or "q" in result:
return True
# User wishes to continue
print("")
print(header)
return False
# Continue by default
return False
[docs]
def vtune_list_all_hotspots_by_line(
report,
lines_per_screen=LINES_PER_SCREEN
):
"""
Lists hotspots from an Intel VTune hotspot report
that has been grouped by source code line.
Parameters
----------
report : pandas.DataFrame
Hotspot report from Intel VTune.
lines_per_screen : int, optional
Pause after showing these many lines.
Default value: LINES_PER_SCREEN
"""
verify_variable_type(report, pd.DataFrame)
# Crop the report to necessary columns
report = report[["Source File", "Source Line", "CPU Time [s]"]]
# Print column headers
col = list(report.columns)
header = f"Rank {col[0]:<30} {col[1]:>12} {col[2]:>20}"
print(header)
# Return each row of the DataFrame as a tuple
for row in report.itertuples():
# Print each line
linecount = row[0] + 1
cpu = float(row[3])
display = f"{linecount:<8} {row[1]:<30} {row[2]:>12} {cpu:>20.6f}"
print(display)
# After a certain number of lines, ask user if they want to
# continue or quit. If quit, then break out of this loop
# Ask user to continue/quit. If returns true, exit
if vtune_ask_user_to_continue_or_quit(
header,
linecount,
lines_per_screen
):
break
[docs]
def vtune_list_all_hotspots_by_function(
report,
lines_per_screen=LINES_PER_SCREEN
):
"""
Lists hotspots from an Intel VTune hotspot report
that has been grouped by function.
Parameters
----------
report : pandas.DataFrame
Hotspot information data.
lines_per_screen : int, optional
Pause after showing these many lines.
Default value: LINES_PER_SCREEN
"""
verify_variable_type(report, pd.DataFrame)
# Crop the data to necessary columns
report = report[["Function", "CPU Time [s]"]]
# Print column headers
col = list(report.columns)
header = f"Rank {col[0]:<60} {col[1]:>20}"
print(header)
# Return each row of the DataFrame as a tuple
for row in report.itertuples():
# Print each line
linecount = row[0] + 1
display = f"{linecount:<8} {row[1]:<60} {float(row[2]):>20.6f}"
print(display)
# After a certain number of lines, ask user if they want to
# continue or quit. If quit, then break out of this loop
# Ask user to continue/quit. If returns true, exit
if vtune_ask_user_to_continue_or_quit(
header,
linecount,
lines_per_screen
):
break
[docs]
def vtune_list_all_hotspots(
filename,
delimiter=DELIMITER,
lines_per_screen=LINES_PER_SCREEN
):
"""
Reads a hotspots report (in CSV format) generated by the Intel VTune
profiler, and calls the proper function to display the results.
Parameters
----------
filename : str
File containing the hotspot report.
delimiter : str, optional
Text separator.
Default value: "\\t" (tab)
lines_per_screen : int, optional
Pause after showing these many lines.
Default value: LINES_PER_SCREEN
"""
verify_variable_type(filename, str)
# Read the date into a DataFrame
report= vtune_read_hotspots_csv(
filename,
delimiter=delimiter
)
# Filename contains hotspot output by source code line
if "by_line" in vtune_how_is_report_grouped(report):
vtune_list_all_hotspots_by_line(
report,
lines_per_screen=lines_per_screen
)
return
# Filename contains hotspot output by functions
if "by_function" in vtune_how_is_report_grouped(report):
vtune_list_all_hotspots_by_function(
report,
lines_per_screen=lines_per_screen
)
return
# Throw an error
msg = "Report is grouped neither by function nor by source line!"
raise ValueError(msg)
[docs]
def vtune_get_timing_info(
ref_time,
dev_time
):
"""
Computes timing information for a hotspot from two reports
and returns a string for display.
Parameters
----------
ref_time : str
CPU Time [s] from the hotspot report for Ref.
dev_time : str
CPU Time [s] from the hotspot report for Dev.
Returns
-------
time_str : str
String with timing information to display.
"""
ref_time = float(ref_time)
dev_time = float(dev_time)
abs_diff = dev_time - ref_time
pct_diff = (abs_diff / ref_time) * 100.0
time_str = f"{ref_time:>12.5f} {dev_time:>12.5f} "
time_str += f"{abs_diff:>12.5f} {pct_diff:>8.2f}"
return time_str
[docs]
def vtune_find_hotspot(
report,
column,
hotspot_name
):
"""
Searches for a hotspot by name in a DataFrame column,
Returns the relevant row of the DataFrame if found.
Parameters
----------
report : pandas.DataFrame
Hotspot report from Intel VTune.
column : str
Column to search.
hotspot_name : str
Name of the hotspot to look for.
Returns
-------
result : pandas.DataFrame
Modified DataFrame object.
"""
verify_variable_type(report, pd.DataFrame)
verify_variable_type(column, str)
verify_variable_type(hotspot_name, str)
index = report[column] == hotspot_name
if not np.any(index):
msg = f"Could not find {hotspot_name} in the '{column}' Series!"
raise ValueError(msg)
return report[index]
[docs]
def vtune_compare_a_hotspot_by_line(
ref_report,
ref_label,
dev_report,
dev_label,
hotspot_name,
ref_line_number=None,
dev_line_number=None,
):
"""
Compares a given hotspot in two different reports (grouped by
source code line), and prints timing information.
Parameters
----------
ref_report : pandas.DataFrame
Hotspot report from the Ref model.
ref_label : str
Label for the Ref model.
dev_report : pandas.DataFrame
Hotspot report from the Dev model.
dev_label : str
Label for the Dev model.
hotspot_name : str
Name of the hotspot to search for.
ref_line_number : str or int or None, optional
Line number where hotspot occurs in Ref.
Default value: None
dev_line_number : str or int or None, optional
Line number where hotspot occurs in Dev.
Default value: None
"""
verify_variable_type(ref_report, pd.DataFrame)
verify_variable_type(ref_label, str)
verify_variable_type(dev_report, pd.DataFrame)
verify_variable_type(dev_label, str)
verify_variable_type(hotspot_name, str)
def get_hotspot(report, hotspot_name, line_number):
"""
Returns info about a hotspot from a report (grouped by function).
Parameters
----------
report : pandas.DataFrame
Hotspot report from Intel VTune.
hotspot_name : str
Name of the hotspot to look up.
line_number : str or int
Line number where hotspot occurs.
Returns
-------
values : list
[Rank, Hotspot Name, Line #, CPU Time].
"""
# Error check
if line_number is None:
raise ValueError("Line number was not specified!")
# Convert line number to string (for safety's sake)
line_number = str(line_number)
# Return the hotspot as a DataFrame with one row
report = report[["Source File", "Source Line", "CPU Time [s]"]]
report = vtune_find_hotspot(report, "Source File", hotspot_name)
report = vtune_find_hotspot(report, "Source Line", line_number)
# Return as list: [Rank, Hotspot Name, Source Line, CPU Time]
values = report.iloc[0].tolist()
return [report.index[0], values[0], values[1], values[2]]
# Return hotspot info as Rank, Name, Line, CPU Time
ref_hotspot = get_hotspot(ref_report, hotspot_name, ref_line_number)
dev_hotspot = get_hotspot(dev_report, hotspot_name, dev_line_number)
# Compute timing info and create a string for display
time_str = vtune_get_timing_info(ref_hotspot[3], dev_hotspot[3])
# Print results
print(f"\n{'Hotspot':<25} {ref_label[0:12]:>12} ", end="")
print(f"{dev_label[0:12]:>12} {'Abs Diff':>12} {'% Diff':>8}")
print(f"{ref_hotspot[1][0:25]:<25} ", end="")
print(time_str)
[docs]
def vtune_compare_a_hotspot_by_function(
ref_report,
ref_label,
dev_report,
dev_label,
hotspot_name,
):
"""
Compares a given hotspot in two different reports (grouped by
source code line), and prints timing information.
Parameters
----------
ref_report : pandas.DataFrame
Hotspot report from the Ref model.
ref_label : str
Label for the Ref model.
dev_report : pandas.DataFrame
Hotspot report from the Dev model.
dev_label : str
Label for the Dev model.
hotspot_name : str
Name of the hotspot to search for.
"""
verify_variable_type(ref_report, pd.DataFrame)
verify_variable_type(ref_label, str)
verify_variable_type(dev_report, pd.DataFrame)
verify_variable_type(dev_label, str)
verify_variable_type(hotspot_name, str)
def get_hotspot(report, hotspot_name):
"""
Returns info about a hotspot from a report (grouped by function).
Parameters
----------
report : pandas.DataFrame
Hotspot report from Intel VTune.
hotspot_name : str
Name of the hotspot to look up.
Returns
-------
values : list
[Rank, Hotspot Name, CPU Time].
"""
# Return the hotspot as a DataFrame with one row
report = report[["Function", "CPU Time [s]"]]
report = vtune_find_hotspot(report, "Function", hotspot_name)
# Return as list: [Rank, Hotspot Name, CPU Time]
values = report.iloc[0].tolist()
return [report.index[0], values[0], values[1]]
# Return hotspot info as Rank, Name, Line, CPU Time
ref_hotspot = get_hotspot(ref_report, hotspot_name)
dev_hotspot = get_hotspot(dev_report, hotspot_name)
# Compute timing info and create a string for display
time_str = vtune_get_timing_info(ref_hotspot[2], dev_hotspot[2])
# Print results
print(f"\n{'Hotspot':<25} {ref_label[0:12]:>12} ", end="")
print(f"{dev_label[0:12]:>12} {'Abs Diff':>12} {'% Diff':>8}")
print(f"{ref_hotspot[1][0:25]:<25} ", end="")
print(time_str)
[docs]
def vtune_compare_a_hotspot(
ref_file,
ref_label,
dev_file,
dev_label,
hotspot_name,
delimiter=DELIMITER,
ref_line_number=None,
dev_line_number=None,
):
"""
Compares a given hotspot in two different reports (grouped by
source code line), and prints timing information.
Parameters
----------
ref_file : str
Hotspot report from the Ref model.
ref_label : str
Label for the Ref model.
dev_file : str
Hotspot report from the Dev model.
dev_label : str
Label for the Dev model.
hotspot_name : str
Name of the hotspot to search for.
delimiter : str, optional
Text separator.
Default value: "\\t" (tab)
ref_line_number : str or int or None, optional
Line number where hotspot occurs in Ref.
Default value: None
dev_line_number : str or int or None, optional
Line number where hotspot occurs in Dev.
Default value: None
"""
verify_variable_type(ref_file, str)
verify_variable_type(ref_label, str)
verify_variable_type(dev_file, str)
verify_variable_type(dev_label, str)
verify_variable_type(hotspot_name, str)
# Read Ref data and determine how it is grouped
ref_report = vtune_read_hotspots_csv(ref_file, delimiter=delimiter)
ref_grouped = vtune_how_is_report_grouped(ref_report)
# Read Dev data and determine how it is grouped
dev_report = vtune_read_hotspots_csv(dev_file, delimiter=delimiter)
dev_grouped = vtune_how_is_report_grouped(dev_report)
# Filename contains hotspot output by source code line
if "by_line" in ref_grouped and "by_line" in dev_grouped:
vtune_compare_a_hotspot_by_line(
ref_report,
ref_label,
dev_report,
dev_label,
hotspot_name,
ref_line_number=ref_line_number,
dev_line_number=dev_line_number,
)
return
# Filename contains hotspot output by functions
if "by_function" in ref_grouped and "by_function" in dev_grouped:
vtune_compare_a_hotspot_by_function(
ref_report,
ref_label,
dev_report,
dev_label,
hotspot_name,
)
return
# Throw an error
msg = "Report is grouped neither by function nor by source line!"
raise ValueError(msg)