From ed59be4199c2631703f20c45fb395b3012b24880 Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Mon, 10 Mar 2025 18:10:01 +0200 Subject: [PATCH] refactor: Extract performance logging to separate class (#124) This should not be responsibility of LLMClientInterface. Extracting this class also adds flexibility to silence logging output in tests. --- LLMClientInterface.cpp | 30 +++---------- LLMClientInterface.hpp | 10 ++--- logger/CMakeLists.txt | 3 ++ logger/EmptyRequestPerformanceLogger.hpp | 32 ++++++++++++++ logger/IRequestPerformanceLogger.hpp | 36 ++++++++++++++++ logger/RequestPerformanceLogger.cpp | 55 ++++++++++++++++++++++++ logger/RequestPerformanceLogger.hpp | 41 ++++++++++++++++++ qodeassist.cpp | 5 ++- 8 files changed, 180 insertions(+), 32 deletions(-) create mode 100644 logger/EmptyRequestPerformanceLogger.hpp create mode 100644 logger/IRequestPerformanceLogger.hpp create mode 100644 logger/RequestPerformanceLogger.cpp create mode 100644 logger/RequestPerformanceLogger.hpp diff --git a/LLMClientInterface.cpp b/LLMClientInterface.cpp index 45f840c..57a0893 100644 --- a/LLMClientInterface.cpp +++ b/LLMClientInterface.cpp @@ -42,12 +42,14 @@ LLMClientInterface::LLMClientInterface( const Settings::GeneralSettings &generalSettings, const Settings::CodeCompletionSettings &completeSettings, LLMCore::IProviderRegistry &providerRegistry, - LLMCore::IPromptProvider *promptProvider) + LLMCore::IPromptProvider *promptProvider, + IRequestPerformanceLogger &performanceLogger) : m_requestHandler(this) , m_generalSettings(generalSettings) , m_completeSettings(completeSettings) , m_providerRegistry(providerRegistry) , m_promptProvider(promptProvider) + , m_performanceLogger(performanceLogger) { connect( &m_requestHandler, @@ -85,7 +87,7 @@ void LLMClientInterface::sendData(const QByteArray &data) handleTextDocumentDidOpen(request); } else if (method == "getCompletionsCycling") { QString requestId = request["id"].toString(); - startTimeMeasurement(requestId); + m_performanceLogger.startTimeMeasurement(requestId); handleCompletion(request); } else if (method == "$/cancelRequest") { handleCancelRequest(request); @@ -324,32 +326,10 @@ void LLMClientInterface::sendCompletionToClient( .arg(QString::fromUtf8(QJsonDocument(response).toJson(QJsonDocument::Indented)))); QString requestId = request["id"].toString(); - endTimeMeasurement(requestId); + m_performanceLogger.endTimeMeasurement(requestId); emit messageReceived(LanguageServerProtocol::JsonRpcMessage(response)); } -void LLMClientInterface::startTimeMeasurement(const QString &requestId) -{ - m_requestStartTimes[requestId] = QDateTime::currentMSecsSinceEpoch(); -} - -void LLMClientInterface::endTimeMeasurement(const QString &requestId) -{ - if (m_requestStartTimes.contains(requestId)) { - qint64 startTime = m_requestStartTimes[requestId]; - qint64 endTime = QDateTime::currentMSecsSinceEpoch(); - qint64 totalTime = endTime - startTime; - logPerformance(requestId, "TotalCompletionTime", totalTime); - m_requestStartTimes.remove(requestId); - } -} - -void LLMClientInterface::logPerformance( - const QString &requestId, const QString &operation, qint64 elapsedMs) -{ - LOG_MESSAGE(QString("Performance: %1 %2 took %3 ms").arg(requestId, operation).arg(elapsedMs)); -} - void LLMClientInterface::parseCurrentMessage() {} } // namespace QodeAssist diff --git a/LLMClientInterface.hpp b/LLMClientInterface.hpp index 809d38d..f6bde8a 100644 --- a/LLMClientInterface.hpp +++ b/LLMClientInterface.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,8 @@ public: const Settings::GeneralSettings &generalSettings, const Settings::CodeCompletionSettings &completeSettings, LLMCore::IProviderRegistry &providerRegistry, - LLMCore::IPromptProvider *promptProvider); + LLMCore::IPromptProvider *promptProvider, + IRequestPerformanceLogger &performanceLogger); Utils::FilePath serverDeviceTemplate() const override; @@ -74,12 +76,8 @@ private: LLMCore::IPromptProvider *m_promptProvider = nullptr; LLMCore::IProviderRegistry &m_providerRegistry; LLMCore::RequestHandler m_requestHandler; + IRequestPerformanceLogger &m_performanceLogger; QElapsedTimer m_completionTimer; - QMap m_requestStartTimes; - - void startTimeMeasurement(const QString &requestId); - void endTimeMeasurement(const QString &requestId); - void logPerformance(const QString &requestId, const QString &operation, qint64 elapsedMs); }; } // namespace QodeAssist diff --git a/logger/CMakeLists.txt b/logger/CMakeLists.txt index 34fff4c..e23e273 100644 --- a/logger/CMakeLists.txt +++ b/logger/CMakeLists.txt @@ -1,6 +1,9 @@ add_library(QodeAssistLogger STATIC + EmptyRequestPerformanceLogger.hpp + IRequestPerformanceLogger.hpp Logger.cpp Logger.hpp + RequestPerformanceLogger.hpp RequestPerformanceLogger.cpp ) target_link_libraries(QodeAssistLogger diff --git a/logger/EmptyRequestPerformanceLogger.hpp b/logger/EmptyRequestPerformanceLogger.hpp new file mode 100644 index 0000000..34004b0 --- /dev/null +++ b/logger/EmptyRequestPerformanceLogger.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2025 Povilas Kanapickas + * + * This file is part of QodeAssist. + * + * QodeAssist is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * QodeAssist is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with QodeAssist. If not, see . + */ + +#include "IRequestPerformanceLogger.hpp" + +namespace QodeAssist { + +class EmptyRequestPerformanceLogger : public IRequestPerformanceLogger +{ +public: + void startTimeMeasurement(const QString &requestId) override {} + void endTimeMeasurement(const QString &requestId) override {} + void logPerformance(const QString &requestId, qint64 elapsedMs) override {} +}; + +} // namespace QodeAssist diff --git a/logger/IRequestPerformanceLogger.hpp b/logger/IRequestPerformanceLogger.hpp new file mode 100644 index 0000000..430bbd4 --- /dev/null +++ b/logger/IRequestPerformanceLogger.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2025 Povilas Kanapickas + * + * This file is part of QodeAssist. + * + * QodeAssist is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * QodeAssist is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with QodeAssist. If not, see . + */ + +#pragma once + +#include + +namespace QodeAssist { + +class IRequestPerformanceLogger +{ +public: + virtual ~IRequestPerformanceLogger() = default; + + virtual void startTimeMeasurement(const QString &requestId) = 0; + virtual void endTimeMeasurement(const QString &requestId) = 0; + virtual void logPerformance(const QString &requestId, qint64 elapsedMs) = 0; +}; + +} // namespace QodeAssist diff --git a/logger/RequestPerformanceLogger.cpp b/logger/RequestPerformanceLogger.cpp new file mode 100644 index 0000000..af845c1 --- /dev/null +++ b/logger/RequestPerformanceLogger.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2025 Povilas Kanapickas + * + * This file is part of QodeAssist. + * + * QodeAssist is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * QodeAssist is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with QodeAssist. If not, see . + */ + +#include "RequestPerformanceLogger.hpp" +#include "Logger.hpp" + +namespace QodeAssist { + +void RequestPerformanceLogger::startTimeMeasurement(const QString &requestId) +{ + m_requestStartTimes[requestId] = QDateTime::currentMSecsSinceEpoch(); +} + +void RequestPerformanceLogger::endTimeMeasurement(const QString &requestId) +{ + if (!m_requestStartTimes.contains(requestId)) { + return; + } + + qint64 startTime = m_requestStartTimes[requestId]; + qint64 endTime = QDateTime::currentMSecsSinceEpoch(); + qint64 totalTime = endTime - startTime; + logPerformance(requestId, totalTime); + m_requestStartTimes.remove(requestId); +} + +void RequestPerformanceLogger::logPerformance(const QString &requestId, qint64 elapsedMs) +{ + LOG_MESSAGE( + QString("Performance: %1 total completion time took %2 ms").arg(requestId).arg(elapsedMs)); +} + +void RequestPerformanceLogger::logPerformance( + const QString &requestId, const QString &operation, qint64 elapsedMs) +{ + LOG_MESSAGE(QString("Performance: %1 %2 took %3 ms").arg(requestId, operation).arg(elapsedMs)); +} + +} // namespace QodeAssist diff --git a/logger/RequestPerformanceLogger.hpp b/logger/RequestPerformanceLogger.hpp new file mode 100644 index 0000000..6b7fce3 --- /dev/null +++ b/logger/RequestPerformanceLogger.hpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2025 Povilas Kanapickas + * + * This file is part of QodeAssist. + * + * QodeAssist is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * QodeAssist is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with QodeAssist. If not, see . + */ + +#include "IRequestPerformanceLogger.hpp" +#include +#include + +namespace QodeAssist { + +class RequestPerformanceLogger : public IRequestPerformanceLogger +{ +public: + RequestPerformanceLogger() = default; + ~RequestPerformanceLogger() override = default; + + void startTimeMeasurement(const QString &requestId) override; + void endTimeMeasurement(const QString &requestId) override; + void logPerformance(const QString &requestId, qint64 elapsedMs) override; + void logPerformance(const QString &requestId, const QString &operation, qint64 elapsedMs); + +private: + QMap m_requestStartTimes; +}; + +} // namespace QodeAssist diff --git a/qodeassist.cpp b/qodeassist.cpp index 8cfb31a..802f9f4 100644 --- a/qodeassist.cpp +++ b/qodeassist.cpp @@ -48,6 +48,7 @@ #include "chat/NavigationPanel.hpp" #include "llmcore/PromptProviderFim.hpp" #include "llmcore/ProvidersManager.hpp" +#include "logger/RequestPerformanceLogger.hpp" #include "settings/GeneralSettings.hpp" #include "settings/ProjectSettingsPanel.hpp" #include "settings/SettingsConstants.hpp" @@ -142,7 +143,8 @@ public: Settings::generalSettings(), Settings::codeCompletionSettings(), LLMCore::ProvidersManager::instance(), - &m_promptProvider)); + &m_promptProvider, + m_performanceLogger)); } bool delayedInitialize() final @@ -184,6 +186,7 @@ private: QPointer m_qodeAssistClient; LLMCore::PromptProviderFim m_promptProvider; + RequestPerformanceLogger m_performanceLogger; QPointer m_chatOutputPane; QPointer m_navigationPanel; QPointer m_updater;