Skip to content

Commit ed04ba6

Browse files
authored
chore: show timeline and change load_times (#1161)
* show timeline, deperacate old load_times * fix bug
1 parent 970561a commit ed04ba6

File tree

2 files changed

+256
-64
lines changed

2 files changed

+256
-64
lines changed

rdagent/log/ui/ds_trace.py

Lines changed: 84 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
from rdagent.log.ui.utils import (
2020
curve_figure,
2121
get_sota_exp_stat,
22-
load_times,
22+
load_times_info,
23+
timeline_figure,
2324
trace_figure,
2425
)
2526
from rdagent.log.utils import (
@@ -170,9 +171,11 @@ def load_stdout(stdout_path: Path):
170171

171172
# UI windows
172173
def task_win(task):
173-
with st.container(border=True):
174-
st.markdown(f"**:violet[{task.name}]**")
174+
with st.expander(f"**:violet[{task.name}]**", expanded=False):
175175
st.markdown(task.description)
176+
if hasattr(task, "package_info"):
177+
st.markdown(f"**:blue[Package Info:]**")
178+
st.code(task.package_info)
176179
if hasattr(task, "architecture"): # model task
177180
st.markdown(
178181
f"""
@@ -185,14 +188,17 @@ def task_win(task):
185188

186189
def workspace_win(workspace, cmp_workspace=None, cmp_name="last code."):
187190
show_files = {k: v for k, v in workspace.file_dict.items() if "test" not in k}
188-
189191
if len(show_files) > 0:
190192
if cmp_workspace:
191193
diff = generate_diff_from_dict(cmp_workspace.file_dict, show_files, "main.py")
192194
with st.popover(f":violet[**Diff with {cmp_name}**]", use_container_width=True, icon="🔍"):
193195
st.code("".join(diff), language="diff", wrap_lines=True, line_numbers=True)
196+
197+
rtime = workspace.running_info.running_time
198+
time_str = timedelta_to_str(timedelta(seconds=rtime) if rtime else None) or "00:00:00"
199+
194200
with st.popover(
195-
f"Files in :blue[{replace_ep_path(workspace.workspace_path)}]", use_container_width=True, icon="📂"
201+
f"⏱️{time_str} 📂Files in :blue[{replace_ep_path(workspace.workspace_path)}]", use_container_width=True
196202
):
197203
code_tabs = st.tabs(show_files.keys())
198204
for ct, codename in zip(code_tabs, show_files.keys()):
@@ -276,7 +282,18 @@ def to_str_recursive(obj):
276282
system = d["obj"].get("system", None)
277283
user = d["obj"]["user"]
278284
resp = d["obj"]["resp"]
279-
with st.expander(f"**LLM**", icon="🤖", expanded=False):
285+
start_time = d["obj"].get("start", "")
286+
end_time = d["obj"].get("end", "")
287+
if start_time and end_time:
288+
start_str = start_time.strftime("%m-%d %H:%M:%S")
289+
end_str = end_time.strftime("%m-%d %H:%M:%S")
290+
duration = end_time - start_time
291+
time_info_str = (
292+
f"🕰️:blue[**{start_str} ~ {end_str}**] ⏳:violet[**{round(duration.total_seconds(), 2)}s**]"
293+
)
294+
else:
295+
time_info_str = ""
296+
with st.expander(f"**LLM** {time_info_str}", icon="🤖", expanded=False):
280297
t1, t2, t3, t4 = st.tabs(
281298
[":green[**Response**]", ":blue[**User**]", ":orange[**System**]", ":violet[**ChatBot**]"]
282299
)
@@ -367,13 +384,13 @@ def exp_gen_win(exp_gen_data, llm_data=None):
367384
st.header("Exp Gen", divider="blue", anchor="exp-gen")
368385
if state.show_llm_log and llm_data is not None:
369386
llm_log_win(llm_data["no_tag"])
370-
st.subheader("Hypothesis")
387+
st.subheader("💡 Hypothesis")
371388
hypothesis_win(exp_gen_data["no_tag"].hypothesis)
372389

373-
st.subheader("pending_tasks")
390+
st.subheader("📋 pending_tasks")
374391
for tasks in exp_gen_data["no_tag"].pending_tasks_list:
375392
task_win(tasks[0])
376-
st.subheader("Exp Workspace")
393+
st.subheader("📁 Exp Workspace")
377394
workspace_win(exp_gen_data["no_tag"].experiment_workspace)
378395

379396

@@ -573,21 +590,23 @@ def replace_ep_path(p: Path):
573590
def get_llm_call_stats(llm_data: dict) -> tuple[int, int]:
574591
total_llm_call = 0
575592
total_filter_call = 0
576-
total_call_seconds = 0
577-
filter_call_seconds = 0
593+
total_call_duration = timedelta()
594+
filter_call_duration = timedelta()
578595
filter_sys_prompt = T("rdagent.utils.prompts:filter_redundant_text.system").r()
579596
for li, loop_d in llm_data.items():
580597
for fn, loop_fn_d in loop_d.items():
581598
for k, v in loop_fn_d.items():
582599
for d in v:
583600
if "debug_llm" in d["tag"]:
584601
total_llm_call += 1
585-
total_call_seconds += d["obj"].get("duration", 0)
602+
total_call_duration += d["obj"].get("end", timedelta()) - d["obj"].get("start", timedelta())
586603
if "system" in d["obj"] and filter_sys_prompt == d["obj"]["system"]:
587604
total_filter_call += 1
588-
filter_call_seconds += d["obj"].get("duration", 0)
605+
filter_call_duration += d["obj"].get("end", timedelta()) - d["obj"].get(
606+
"start", timedelta()
607+
)
589608

590-
return total_llm_call, total_filter_call, total_call_seconds, filter_call_seconds
609+
return total_llm_call, total_filter_call, total_call_duration, filter_call_duration
591610

592611

593612
def get_timeout_stats(llm_data: dict):
@@ -638,13 +657,13 @@ def summarize_win():
638657
with info3.popover("RDLOOP", icon="⚙️"):
639658
st.write(state.data.get("settings", {}).get("RDLOOP_SETTINGS", "No settings found."))
640659

641-
llm_call, llm_filter_call, llm_call_seconds, llm_filter_call_seconds = get_llm_call_stats(state.llm_data)
642-
info4.metric("LLM Calls", llm_call, help=timedelta_to_str(timedelta(seconds=llm_call_seconds)))
660+
llm_call, llm_filter_call, llm_call_duration, filter_call_duration = get_llm_call_stats(state.llm_data)
661+
info4.metric("LLM Calls", llm_call, help=timedelta_to_str(llm_call_duration))
643662
info5.metric(
644663
"LLM Filter Calls",
645664
llm_filter_call,
646665
delta=-round(llm_filter_call / llm_call, 5),
647-
help=timedelta_to_str(timedelta(seconds=llm_filter_call_seconds)),
666+
help=timedelta_to_str(filter_call_duration),
648667
)
649668

650669
timeout_stats = get_timeout_stats(state.llm_data)
@@ -718,21 +737,28 @@ def summarize_win():
718737
df.loc[loop, "COST($)"] = sum(tc.content["cost"] for tc in state.token_costs[loop])
719738

720739
# Time Stats
721-
if loop in state.times and state.times[loop]:
722-
exp_gen_time = coding_time = running_time = None
723-
all_steps_time = timedelta()
724-
for lpt in state.times[loop]:
725-
all_steps_time += lpt.end - lpt.start
726-
if lpt.step_idx == 0:
727-
exp_gen_time = lpt.end - lpt.start
728-
elif lpt.step_idx == 1:
729-
coding_time = lpt.end - lpt.start
730-
elif lpt.step_idx == 2:
731-
running_time = lpt.end - lpt.start
732-
df.loc[loop, "Time"] = timedelta_to_str(all_steps_time)
733-
df.loc[loop, "Exp Gen"] = timedelta_to_str(exp_gen_time)
734-
df.loc[loop, "Coding"] = timedelta_to_str(coding_time)
735-
df.loc[loop, "Running"] = timedelta_to_str(running_time)
740+
exp_gen_time = timedelta()
741+
coding_time = timedelta()
742+
running_time = timedelta()
743+
all_steps_time = timedelta()
744+
if loop in state.times:
745+
for step_name, step_time in state.times[loop].items():
746+
step_duration = step_time["end_time"] - step_time["start_time"]
747+
if step_name == "exp_gen":
748+
exp_gen_time += step_duration
749+
all_steps_time += step_duration
750+
elif step_name == "coding":
751+
coding_time += step_duration
752+
all_steps_time += step_duration
753+
elif step_name == "running":
754+
running_time += step_duration
755+
all_steps_time += step_duration
756+
elif step_name in ["feedback", "record"]:
757+
all_steps_time += step_duration
758+
df.loc[loop, "Time"] = timedelta_to_str(all_steps_time)
759+
df.loc[loop, "Exp Gen"] = timedelta_to_str(exp_gen_time)
760+
df.loc[loop, "Coding"] = timedelta_to_str(coding_time)
761+
df.loc[loop, "Running"] = timedelta_to_str(running_time)
736762

737763
if "running" in loop_data and "no_tag" in loop_data["running"]:
738764
try:
@@ -835,22 +861,10 @@ def summarize_win():
835861
df = df[df["Feedback"] == "✅"]
836862
st.dataframe(df[df.columns[~df.columns.isin(["Hypothesis", "Reason", "Others"])]])
837863

838-
# COST curve
839-
costs = df["COST($)"].astype(float)
840-
costs.index = [f"L{i}" for i in costs.index]
841-
cumulative_costs = costs.cumsum()
842-
with st.popover("COST Curve", icon="💰", use_container_width=True):
843-
fig = px.line(
844-
x=costs.index,
845-
y=[costs.values, cumulative_costs.values],
846-
labels={"x": "Loop", "value": "COST($)"},
847-
title="COST($) per Loop & Cumulative COST($)",
848-
markers=True,
849-
)
850-
fig.update_traces(mode="lines+markers")
851-
fig.data[0].name = "COST($) per Loop"
852-
fig.data[1].name = "Cumulative COST($)"
853-
st.plotly_chart(fig)
864+
# timeline figure
865+
if state.times:
866+
with st.popover("Timeline", icon="⏱️", use_container_width=True):
867+
st.plotly_chart(timeline_figure(state.times))
854868

855869
# scores curve
856870
vscores = {}
@@ -920,8 +934,8 @@ def comp_stat_func(x: pd.DataFrame):
920934
comp_df["Valid Rate"] = comp_df["Valid Rate"].apply(lambda x: f"{x}%")
921935
comp_df["Success Rate"] = comp_df["Success Rate"].apply(lambda x: f"{x}%")
922936
comp_df.loc["Total", "Avg e-loops(c)"] = round(df["e-loops(c)"].mean(), 2)
923-
st2.markdown("### Component Statistics")
924-
st2.dataframe(comp_df)
937+
with st2.popover("Component Statistics", icon="📊", use_container_width=True):
938+
st.dataframe(comp_df)
925939

926940
# component time statistics
927941
time_df = df.loc[:, ["Component", "Time", "Exp Gen", "Coding", "Running"]]
@@ -933,15 +947,32 @@ def comp_stat_func(x: pd.DataFrame):
933947
"Running": "timedelta64[ns]",
934948
}
935949
)
936-
st1.markdown("### Time Statistics")
937950
time_stat_df = time_df.groupby("Component").sum()
938951
time_stat_df.loc["Total"] = time_stat_df.sum()
939952
time_stat_df.loc[:, "Exp Gen(%)"] = (time_stat_df["Exp Gen"] / time_stat_df["Time"] * 100).round(2)
940953
time_stat_df.loc[:, "Coding(%)"] = (time_stat_df["Coding"] / time_stat_df["Time"] * 100).round(2)
941954
time_stat_df.loc[:, "Running(%)"] = (time_stat_df["Running"] / time_stat_df["Time"] * 100).round(2)
942955
for col in ["Time", "Exp Gen", "Coding", "Running"]:
943956
time_stat_df[col] = time_stat_df[col].map(timedelta_to_str)
944-
st1.dataframe(time_stat_df)
957+
with st1.popover("Time Statistics", icon="⏱️", use_container_width=True):
958+
st.dataframe(time_stat_df)
959+
960+
# COST curve
961+
costs = df["COST($)"].astype(float)
962+
costs.index = [f"L{i}" for i in costs.index]
963+
cumulative_costs = costs.cumsum()
964+
with st.popover("COST Curve", icon="💰", use_container_width=True):
965+
fig = px.line(
966+
x=costs.index,
967+
y=[costs.values, cumulative_costs.values],
968+
labels={"x": "Loop", "value": "COST($)"},
969+
title="COST($) per Loop & Cumulative COST($)",
970+
markers=True,
971+
)
972+
fig.update_traces(mode="lines+markers")
973+
fig.data[0].name = "COST($) per Loop"
974+
fig.data[1].name = "Cumulative COST($)"
975+
st.plotly_chart(fig)
945976

946977

947978
def stdout_win(loop_id: int):
@@ -1029,7 +1060,7 @@ def get_folders_sorted(log_path, sort_by_time=False):
10291060
st.toast("Please select a log path first!", icon="🟡")
10301061
st.stop()
10311062

1032-
state.times = load_times(state.log_folder / state.log_path)
1063+
state.times = load_times_info(state.log_folder / state.log_path)
10331064
state.data, state.llm_data, state.token_costs = load_data(state.log_folder / state.log_path)
10341065
state.sota_info = get_sota_exp_stat(Path(state.log_folder) / state.log_path, to_submit=True)
10351066
st.rerun()

0 commit comments

Comments
 (0)