From c46ecd18fad1767f15d748e218abafed3481febd Mon Sep 17 00:00:00 2001 From: Nayan Date: Sat, 19 Jul 2025 15:40:16 -0400 Subject: [PATCH] UI: Clear Model Cache (#1058) * clear model cache * add cache size * move to model manager * fix handling for default model --------- Co-authored-by: DevTekVE Co-authored-by: James Vecellio-Grant <159560811+Discountchubbs@users.noreply.github.com> --- common/params_keys.h | 1 + .../qt/offroad/settings/models_panel.cc | 38 +++++++++++++++++++ .../qt/offroad/settings/models_panel.h | 3 ++ sunnypilot/models/manager.py | 29 ++++++++++++++ system/hardware/hw.h | 4 ++ 5 files changed, 75 insertions(+) diff --git a/common/params_keys.h b/common/params_keys.h index 7aa4bc6b72..dfcf410a51 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -156,6 +156,7 @@ inline static std::unordered_map keys = { // Model Manager params {"ModelManager_ActiveBundle", PERSISTENT}, + {"ModelManager_ClearCache", CLEAR_ON_MANAGER_START}, {"ModelManager_DownloadIndex", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"ModelManager_LastSyncTime", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"ModelManager_ModelsCache", PERSISTENT | BACKUP}, diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc index e565269eb7..c4cb4b4767 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include "common/model.h" #include "selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h" @@ -66,6 +68,11 @@ ModelsPanel::ModelsPanel(QWidget *parent) : QWidget(parent) { connect(uiStateSP(), &UIStateSP::uiUpdate, this, &ModelsPanel::updateLabels); list->addItem(currentModelLblBtn); + clearModelCacheBtn = new ButtonControlSP(tr("Clear Model Cache"), tr("CLEAR"), "", this); + connect(clearModelCacheBtn, &ButtonControlSP::clicked, this, &ModelsPanel::clearModelCache); + + list->addItem(clearModelCacheBtn); + // Create progress bars for downloads supercomboProgressBar = createProgressBar(this); QString supercomboType = tr("Driving Model"); @@ -367,6 +374,8 @@ void ModelsPanel::updateLabels() { delay_control->setLabel(QString::number(value, 'f', 2) + "s"); delay_control->showDescription(); } + + clearModelCacheBtn->setValue(QString::number(calculateCacheSize(), 'f', 2) + " MB"); } /** @@ -387,3 +396,32 @@ void ModelsPanel::showResetParamsDialog() { params.remove("LiveTorqueParameters"); } } + +void ModelsPanel::clearModelCache() { + QString confirmMsg = tr("This will delete ALL downloaded models from the cache" + "
except the currently active model." + "

Are you sure you want to continue?"); + QString content("

" + tr("Driving Model Selector") + "


" + "

" + confirmMsg + "

"); + if (showConfirmationDialog( + content, + tr("Clear Cache"))) { + params.putBool("ModelManager_ClearCache", true); + } +} + +double ModelsPanel::calculateCacheSize() { + QFuture future_ModelCacheSize = QtConcurrent::run([=]() { + + QDir model_dir(QString::fromStdString(Path::model_root())); + QFileInfoList model_files = model_dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot); + qint64 totalSize = 0; + for (const QFileInfo &model_file : model_files) { + if (model_file.isFile()) { + totalSize += model_file.size(); + } + } + return totalSize; + }); + return static_cast(future_ModelCacheSize) / (1024.0 * 1024.0); +} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h index 61f15e6d3c..06a2380f39 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h @@ -41,6 +41,8 @@ private: cereal::ModelManagerSP::Reader model_manager; cereal::ModelManagerSP::DownloadStatus download_status{}; cereal::ModelManagerSP::DownloadStatus prev_download_status{}; + void clearModelCache(); + double calculateCacheSize(); bool canContinueOnMeteredDialog() { if (!is_metered) return true; @@ -75,5 +77,6 @@ private: QProgressBar *policyProgressBar; QFrame *policyFrame; Params params; + ButtonControlSP *clearModelCacheBtn; }; diff --git a/sunnypilot/models/manager.py b/sunnypilot/models/manager.py index 630d6a8d77..8913135203 100644 --- a/sunnypilot/models/manager.py +++ b/sunnypilot/models/manager.py @@ -178,6 +178,10 @@ class ModelManagerSP: finally: self.params.put("ModelManager_DownloadIndex", "") + if self.params.get("ModelManager_ClearCache", block=False, encoding="utf-8"): + self.clear_model_cache() + self.params.remove("ModelManager_ClearCache") + self._report_status() rk.keep_time() @@ -185,6 +189,31 @@ class ModelManagerSP: cloudlog.exception(f"Error in main thread: {str(e)}") rk.keep_time() + def clear_model_cache(self) -> None: + """ + Clears the model cache directory of all files except those in the active model bundle. + """ + + # Get list of files used by active model bundle + active_files = [] + if self.active_bundle is not None: # When the default model is active + for model in self.active_bundle.models: + if hasattr(model, 'artifact') and model.artifact.fileName: + active_files.append(model.artifact.fileName) + if hasattr(model, 'metadata') and model.metadata.fileName: + active_files.append(model.metadata.fileName) + + # Remove all files except active ones + model_dir = Paths.model_root() + try: + for filename in os.listdir(model_dir): + if filename not in active_files: + file_path = os.path.join(model_dir, filename) + if os.path.isfile(file_path): + os.remove(file_path) + cloudlog.info("Model cache cleared, keeping active model files") + except Exception as e: + cloudlog.exception(f"Error clearing model cache: {str(e)}") def main(): ModelManagerSP().main_thread() diff --git a/system/hardware/hw.h b/system/hardware/hw.h index d2083a5985..bc9d17dd81 100644 --- a/system/hardware/hw.h +++ b/system/hardware/hw.h @@ -55,4 +55,8 @@ namespace Path { return "/dev/shm"; #endif } + + inline std::string model_root() { + return Hardware::PC() ? Path::comma_home() + "/media/0/models" : "/data/media/0/models"; + } } // namespace Path