From dd4edb83316ee33518b2d25b95ddcc93bd6cf36f Mon Sep 17 00:00:00 2001 From: you-n-g Date: Mon, 1 Sep 2025 15:58:05 +0800 Subject: [PATCH] feat: ui, support disable cache (#1217) * fix: (drop) add cache_enable for functions in ui.utils * fix: (drop) handle no logging, rename sota_exp to last_sota_exp for clarity in running_win --- rdagent/log/ui/ds_trace.py | 12 +++++++----- rdagent/log/ui/utils.py | 30 ++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/rdagent/log/ui/ds_trace.py b/rdagent/log/ui/ds_trace.py index 8f7427ba..6ed43f87 100644 --- a/rdagent/log/ui/ds_trace.py +++ b/rdagent/log/ui/ds_trace.py @@ -475,7 +475,7 @@ def coding_win(data, base_exp, llm_data: dict | None = None): workspace_win(data["no_tag"].experiment_workspace) -def running_win(data, base_exp, llm_data=None, sota_exp=None): +def running_win(data, base_exp, llm_data=None, last_sota_exp=None): st.header("Running", divider="blue", anchor="running") if llm_data is not None: common_llm_data = llm_data.pop("no_tag", []) @@ -491,7 +491,7 @@ def running_win(data, base_exp, llm_data=None, sota_exp=None): st.subheader("Exp Workspace (running final)") workspace_win( data["no_tag"].experiment_workspace, - cmp_workspace=sota_exp.experiment_workspace if sota_exp else None, + cmp_workspace=last_sota_exp.experiment_workspace if last_sota_exp else None, cmp_name="last SOTA(to_submit)", ) st.subheader("Result") @@ -555,7 +555,7 @@ def main_win(loop_id, llm_data=None): ) if "running" in loop_data: # get last SOTA_exp_to_submit - sota_exp = None + last_sota_exp = None if "record" in loop_data: current_trace = loop_data["record"]["trace"] current_selection = current_trace.get_current_selection() @@ -565,13 +565,15 @@ def main_win(loop_id, llm_data=None): if len(parent_idxs) >= 2 and hasattr(current_trace, "idx2loop_id"): parent_idx = parent_idxs[-2] parent_loop_id = current_trace.idx2loop_id[parent_idx] - sota_exp = state.data[parent_loop_id]["record"].get("sota_exp_to_submit", None) + if parent_loop_id in state.data: + # in some cases, the state.data is synthesized, logs does not necessarily exist + last_sota_exp = state.data[parent_loop_id]["record"].get("sota_exp_to_submit", None) running_win( loop_data["running"], base_exp=loop_data["coding"].get("no_tag", None), llm_data=llm_data["running"] if llm_data else None, - sota_exp=sota_exp, + last_sota_exp=last_sota_exp, ) if "feedback" in loop_data: feedback_win(loop_data["feedback"], llm_data.get("feedback", None) if llm_data else None) diff --git a/rdagent/log/ui/utils.py b/rdagent/log/ui/utils.py index 69993219..a872b91c 100644 --- a/rdagent/log/ui/utils.py +++ b/rdagent/log/ui/utils.py @@ -161,7 +161,6 @@ def map_stat(sota_mle_score: dict | None) -> str: return sota_exp_stat -@cache_with_pickle(_log_path_hash_func, force=True) def get_best_report(log_path: Path) -> dict | None: log_storage = FileStorage(log_path) mle_reports = [extract_json(i.content) for i in log_storage.iter_msg(pattern="**/running/mle_score/*/*.pkl")] @@ -176,11 +175,14 @@ def get_best_report(log_path: Path) -> dict | None: return None +if UI_SETTING.enable_cache: + get_best_report = cache_with_pickle(_log_path_hash_func, force=True)(get_best_report) + + def _get_sota_exp_stat_hash_func(log_path: Path, selector: Literal["auto", "best_valid"] = "auto") -> str: return _log_path_hash_func(log_path) + selector -@cache_with_pickle(_get_sota_exp_stat_hash_func, force=True) def get_sota_exp_stat( log_path: Path, selector: Literal["auto", "best_valid"] = "auto" ) -> tuple[DSExperiment | None, int | None, dict | None, str | None]: @@ -253,11 +255,14 @@ def get_sota_exp_stat( return sota_exp, sota_loop_id, sota_mle_score, map_stat(sota_mle_score) +if UI_SETTING.enable_cache: + get_sota_exp_stat = cache_with_pickle(_get_sota_exp_stat_hash_func, force=True)(get_sota_exp_stat) + + def _get_score_stat_hash_func(log_path: Path, sota_loop_id: int) -> str: return _log_path_hash_func(log_path) + str(sota_loop_id) -@cache_with_pickle(_get_score_stat_hash_func, force=True) def get_score_stat(log_path: Path, sota_loop_id: int) -> tuple[float | None, float | None, bool, float | None]: """ Get the scores before and after merge period. @@ -351,7 +356,10 @@ def get_score_stat(log_path: Path, sota_loop_id: int) -> tuple[float | None, flo return valid_improve, test_improve, submit_is_merge, merge_sota_rate -@cache_with_pickle(_log_path_hash_func, force=True) +if UI_SETTING.enable_cache: + get_score_stat = cache_with_pickle(_get_score_stat_hash_func, force=True)(get_score_stat) + + def load_times_deprecated(log_path: Path): try: session_path = log_path / "__session__" @@ -365,7 +373,10 @@ def load_times_deprecated(log_path: Path): return rd_times -@cache_with_pickle(_log_path_hash_func, force=True) +if UI_SETTING.enable_cache: + load_times_deprecated = cache_with_pickle(_log_path_hash_func, force=True)(load_times_deprecated) + + def load_times_info(log_path: Path) -> dict[int, dict[str, dict[Literal["start_time", "end_time"], datetime]]]: """ Load timing information for each loop and step. @@ -403,6 +414,10 @@ def load_times_info(log_path: Path) -> dict[int, dict[str, dict[Literal["start_t return times_info +if UI_SETTING.enable_cache: + load_times_info = cache_with_pickle(_log_path_hash_func, force=True)(load_times_info) + + def _log_folders_summary_hash_func(log_folder: str | Path, hours: int | None = None): summary_p = Path(log_folder) / (f"summary.pkl" if hours is None else f"summary_{hours}h.pkl") if summary_p.exists(): @@ -412,7 +427,6 @@ def _log_folders_summary_hash_func(log_folder: str | Path, hours: int | None = N return md5_hash(hash_str) -@cache_with_pickle(_log_folders_summary_hash_func, force=True) def get_summary_df(log_folder: str | Path, hours: int | None = None) -> tuple[dict, pd.DataFrame]: """Process experiment logs and generate summary DataFrame. @@ -645,6 +659,10 @@ def get_summary_df(log_folder: str | Path, hours: int | None = None) -> tuple[di return summary, base_df +if UI_SETTING.enable_cache: + get_summary_df = cache_with_pickle(_log_folders_summary_hash_func, force=True)(get_summary_df) + + def percent_df(summary_df: pd.DataFrame, show_origin=True) -> pd.DataFrame: """ Convert the summary DataFrame to a percentage format.