Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Cost Report] Add some UI fixes #1788

Merged
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions sky/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1694,24 +1694,42 @@ def cost_report(all: bool): # pylint: disable=redefined-builtin
- clusters that were terminated/stopped on the cloud console.
"""
cluster_records = core.cost_report()

nonreserved_cluster_records = []
reserved_clusters = dict()
for cluster_record in cluster_records:
cluster_name = cluster_record['name']
if cluster_name in backend_utils.SKY_RESERVED_CLUSTER_NAMES:
cluster_group_name = backend_utils.SKY_RESERVED_CLUSTER_NAMES[
cluster_name]
reserved_clusters[cluster_group_name] = cluster_record
# to display most recent entry for each reserved cluster
sumanthgenz marked this conversation as resolved.
Show resolved Hide resolved
if cluster_group_name not in reserved_clusters:
reserved_clusters[cluster_group_name] = cluster_record
else:
nonreserved_cluster_records.append(cluster_record)

status_utils.show_cost_report_table(nonreserved_cluster_records, all)
total_cost = status_utils.get_total_cost_of_displayed_records(
nonreserved_cluster_records, all)

status_utils.show_cost_report_table(nonreserved_cluster_records, all)
for cluster_group_name, cluster_record in reserved_clusters.items():
status_utils.show_cost_report_table(
[cluster_record], all, reserved_group_name=cluster_group_name)
total_cost += cluster_record['total_cost']

click.echo(f'\n{colorama.Style.BRIGHT}'
f'Total Cost: ${total_cost:.2f}{colorama.Style.RESET_ALL}')

if not all:
click.secho(
f'Showing the {status_utils.NUM_COST_REPORT_LINES} '
sumanthgenz marked this conversation as resolved.
Show resolved Hide resolved
'most recent clusters. '
'To see all clusters in history, '
'pass the --all flag.',
fg='yellow')

sumanthgenz marked this conversation as resolved.
Show resolved Hide resolved
click.secho(
'NOTE: This feature is experimental. '
'This feature is experimental. '
'Costs for clusters with auto{stop,down} '
'scheduled may not be accurate.',
fg='yellow')
Expand Down
2 changes: 2 additions & 0 deletions sky/global_user_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,8 @@ def _get_cluster_duration(cluster_hash: str) -> int:

for i, (start_time, end_time) in enumerate(usage_intervals):
# duration from latest start time to time of query
if start_time is None:
continue
if end_time is None:
assert i == len(usage_intervals) - 1, i
end_time = int(time.time())
Expand Down
33 changes: 32 additions & 1 deletion sky/utils/cli_utils/status_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from sky.utils import log_utils

_COMMAND_TRUNC_LENGTH = 25
NUM_COST_REPORT_LINES = 5

# A record in global_user_state's 'clusters' table.
_ClusterRecord = Dict[str, Any]
Expand Down Expand Up @@ -104,6 +105,20 @@ def show_status_table(cluster_records: List[_ClusterRecord],
return num_pending_autostop


def get_total_cost_of_displayed_records(
cluster_records: List[_ClusterCostReportRecord], display_all: bool):
"""Compute total cost of records to be displayed in cost report."""
cluster_records.sort(
key=lambda report: -_get_status_value_for_cost_report(report))

displayed_records = cluster_records[:NUM_COST_REPORT_LINES]
if display_all:
displayed_records = cluster_records

total_cost = sum(record['total_cost'] for record in displayed_records)
return total_cost


def show_cost_report_table(cluster_records: List[_ClusterCostReportRecord],
show_all: bool,
reserved_group_name: Optional[str] = None):
Expand Down Expand Up @@ -153,7 +168,15 @@ def show_cost_report_table(cluster_records: List[_ClusterCostReportRecord],
columns.append(status_column.name)
cluster_table = log_utils.create_table(columns)

for record in cluster_records:
num_lines_to_display = NUM_COST_REPORT_LINES
if show_all:
num_lines_to_display = len(cluster_records)

# prioritize showing non-terminated clusters in table
cluster_records.sort(
key=lambda report: -_get_status_value_for_cost_report(report))

for record in cluster_records[:num_lines_to_display]:
row = []
for status_column in status_columns:
if status_column.show_by_default or show_all:
Expand Down Expand Up @@ -340,6 +363,14 @@ def _is_pending_autostop(cluster_record: _ClusterRecord) -> bool:
# ---- 'sky cost-report' helper functions below ----


def _get_status_value_for_cost_report(
cluster_cost_report_record: _ClusterCostReportRecord) -> int:
status = cluster_cost_report_record['status']
if status is None:
return -1
return 1
Comment on lines +369 to +371
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we sorting a bunch of -1's and 1's? From the output, seems like we are sorting by launch-time?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We wanted to bubble up clusters that were active and un-terminated to the top since they are actively incurring cost. In addition, we also sort by launch time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we put this comment as comment before L172?



def _get_status_for_cost_report(
cluster_cost_report_record: _ClusterCostReportRecord) -> str:
status = cluster_cost_report_record['status']
Expand Down