From 142f6466ae11863c6ee331d86f302d8a524cd5a5 Mon Sep 17 00:00:00 2001 From: Martchus Date: Sat, 23 Apr 2022 19:39:31 +0200 Subject: [PATCH] Show resource usage in UI --- libpkg/data/config.cpp | 5 ++++ libpkg/data/config.h | 1 + libpkg/data/storagegeneric.h | 13 ++++++++++ librepomgr/CMakeLists.txt | 3 +++ librepomgr/resourceusage.cpp | 40 +++++++++++++++++++++++++++++++ librepomgr/resourceusage.h | 26 ++++++++++++++++++++ librepomgr/serversetup.cpp | 8 ++++++- librepomgr/serversetup.h | 12 ++++++---- srv/static/js/globalstatuspage.js | 28 ++++++++++++++++++++-- 9 files changed, 128 insertions(+), 8 deletions(-) create mode 100644 librepomgr/resourceusage.cpp create mode 100644 librepomgr/resourceusage.h diff --git a/libpkg/data/config.cpp b/libpkg/data/config.cpp index f0b0f11..a21e9a1 100644 --- a/libpkg/data/config.cpp +++ b/libpkg/data/config.cpp @@ -62,6 +62,11 @@ void Config::initStorage(const char *path, std::uint32_t maxDbs) aur.initStorage(*m_storage); } +std::size_t Config::cachedPackages() const +{ + return m_storage ? m_storage->packageCache().size() : 0; +} + void Config::setPackageCacheLimit(std::size_t limit) { m_storage->packageCache().setLimit(limit); diff --git a/libpkg/data/config.h b/libpkg/data/config.h index a2edbac..fccf10c 100644 --- a/libpkg/data/config.h +++ b/libpkg/data/config.h @@ -121,6 +121,7 @@ struct LIBPKG_EXPORT Config : public Lockable, public ReflectiveRapidJSON::Binar // storage and caching void initStorage(const char *path = "libpkg.db", std::uint32_t maxDbs = 0); + std::size_t cachedPackages() const; void setPackageCacheLimit(std::size_t limit); std::unique_ptr &storage(); std::uint64_t restoreFromCache(); diff --git a/libpkg/data/storagegeneric.h b/libpkg/data/storagegeneric.h index 975acf5..8f11966 100644 --- a/libpkg/data/storagegeneric.h +++ b/libpkg/data/storagegeneric.h @@ -102,6 +102,7 @@ public: iterator begin(); iterator end(); void setLimit(std::size_t limit); + std::size_t size() const; private: EntryList m_entries; @@ -129,6 +130,11 @@ template inline auto StorageCacheEntries inline std::size_t StorageCacheEntries::size() const +{ + return m_entries.size(); +} + template struct StorageCache { using Entries = StorageEntriesType; using Entry = typename Entries::Entry; @@ -151,12 +157,19 @@ template void clear(Storage &storage); void clearCacheOnly(Storage &storage); void setLimit(std::size_t limit); + std::size_t size(); private: Entries m_entries; std::mutex m_mutex; }; +template +std::size_t StorageCache::size() +{ + return m_entries.size(); +} + } // namespace LibPkg #endif // LIBPKG_DATA_STORAGE_GENERIC_H diff --git a/librepomgr/CMakeLists.txt b/librepomgr/CMakeLists.txt index aadb31e..6e968d9 100644 --- a/librepomgr/CMakeLists.txt +++ b/librepomgr/CMakeLists.txt @@ -4,6 +4,7 @@ cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) set(HEADER_FILES errorhandling.h serversetup.h + resourceusage.h helper.h json.h logcontext.h @@ -32,6 +33,7 @@ set(SRC_FILES json.cpp errorhandling.cpp serversetup.cpp + resourceusage.cpp globallock.cpp authentication.cpp webapi/server.cpp @@ -128,6 +130,7 @@ add_reflection_generator_invocation( INPUT_FILES errorhandling.h serversetup.h + resourceusage.h buildactions/buildaction.h buildactions/buildactionmeta.h buildactions/buildactiontemplate.h diff --git a/librepomgr/resourceusage.cpp b/librepomgr/resourceusage.cpp new file mode 100644 index 0000000..7cb5eb0 --- /dev/null +++ b/librepomgr/resourceusage.cpp @@ -0,0 +1,40 @@ +#include "./resourceusage.h" + +#if defined(PLATFORM_WINDOWS) +#include +#include +#elif defined(PLATFORM_LINUX) || defined(PLATFORM_UNIX) +#include +#include +#include +#endif + +namespace LibRepoMgr { + +ResourceUsage::ResourceUsage() +{ +#if defined(PLATFORM_WINDOWS) + auto info = PROCESS_MEMORY_COUNTERS(); + GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); + physicalMemory = static_cast(info.WorkingSetSize); + physicalMemoryPeak = static_cast(info.PeakWorkingSetSize); +#elif defined(PLATFORM_LINUX) || defined(PLATFORM_UNIX) + if (auto *const statm = std::fopen("/proc/self/statm", "r")) { + auto pages = 0l, pagesInRealMemory = 0l, pagesShared = 0l; + if (std::fscanf(statm, "%ld%ld%ld", &pages, &pagesInRealMemory, &pagesShared) == 3) { + const auto pageSize = static_cast(sysconf(_SC_PAGESIZE)); + virtualMemory = static_cast(pages) * pageSize; + residentSetSize = static_cast(pagesInRealMemory) * pageSize; + sharedResidentSetSize = static_cast(pagesShared) * pageSize; + } + std::fclose(statm); + } + struct rusage rusage; + getrusage(RUSAGE_SELF, &rusage); + peakResidentSetSize = static_cast(rusage.ru_maxrss) * 1024u; +#endif +} + +} // namespace LibRepoMgr + +#include "reflection/resourceusage.h" diff --git a/librepomgr/resourceusage.h b/librepomgr/resourceusage.h new file mode 100644 index 0000000..080fadd --- /dev/null +++ b/librepomgr/resourceusage.h @@ -0,0 +1,26 @@ +#ifndef LIBREPOMGR_RESOURCE_USAGE_H +#define LIBREPOMGR_RESOURCE_USAGE_H + +#include "./global.h" + +#include + +namespace LibRepoMgr { + +struct LIBREPOMGR_EXPORT ResourceUsage : public ReflectiveRapidJSON::JsonSerializable { + explicit ResourceUsage(); + + std::size_t virtualMemory = 0; + std::size_t residentSetSize = 0; + std::size_t sharedResidentSetSize = 0; + std::size_t peakResidentSetSize = 0; + std::size_t packageDbSize = 0; + std::size_t actionsDbSize = 0; + std::size_t cachedPackages = 0; + std::size_t actionsCount = 0; + std::size_t runningActionsCount = 0; +}; + +} // namespace LibRepoMgr + +#endif // LIBREPOMGR_RESOURCE_USAGE_H diff --git a/librepomgr/serversetup.cpp b/librepomgr/serversetup.cpp index 5a18564..5586fee 100644 --- a/librepomgr/serversetup.cpp +++ b/librepomgr/serversetup.cpp @@ -869,12 +869,18 @@ std::string ServiceSetup::Locks::forDatabase(const LibPkg::Database &db) return forDatabase(db.name, db.arch); } -ServiceStatus::ServiceStatus(const ServiceSetup &setup) +ServiceStatus::ServiceStatus(ServiceSetup &setup) : version(applicationInfo.version) , config(setup.config.computeStatus()) , actions(setup.building.metaInfo) , presets(setup.building.presets) { + auto ec = std::error_code(); + resourceUsage.packageDbSize = std::filesystem::file_size(setup.dbPath, ec); + resourceUsage.actionsDbSize = std::filesystem::file_size(setup.building.dbPath, ec); + resourceUsage.cachedPackages = setup.config.cachedPackages(); + resourceUsage.actionsCount = setup.building.buildActionCount(); + resourceUsage.runningActionsCount = setup.building.runningBuildActionCount(); } } // namespace LibRepoMgr diff --git a/librepomgr/serversetup.h b/librepomgr/serversetup.h index 620956a..5759a6b 100644 --- a/librepomgr/serversetup.h +++ b/librepomgr/serversetup.h @@ -5,6 +5,7 @@ #include "./buildactions/buildaction.h" #include "./buildactions/buildactiontemplate.h" #include "./globallock.h" +#include "./resourceusage.h" #include "../libpkg/data/config.h" #include "../libpkg/data/lockable.h" @@ -57,7 +58,7 @@ struct LIBREPOMGR_EXPORT ServiceSetup : public LibPkg::Lockable { void initStorage(); int run(); int fixDb(); - ServiceStatus computeStatus() const; + ServiceStatus computeStatus(); // variables relevant for the web server; only changed when (re)loading config struct LIBREPOMGR_EXPORT WebServerSetup { @@ -142,7 +143,7 @@ struct LIBREPOMGR_EXPORT ServiceSetup : public LibPkg::Lockable { LibPkg::StorageID storeBuildAction(const std::shared_ptr &buildAction); void deleteBuildAction(const std::vector> &actions); std::size_t buildActionCount(); - std::size_t runningBuildActionCount(); + std::size_t runningBuildActionCount() const; void rebuildDb(); void forEachBuildAction(std::function count, std::function &&func, std::size_t limit, std::size_t start); @@ -185,7 +186,7 @@ inline bool ServiceSetup::BuildSetup::hasStorage() const return m_storage != nullptr; } -inline std::size_t ServiceSetup::BuildSetup::runningBuildActionCount() +inline std::size_t ServiceSetup::BuildSetup::runningBuildActionCount() const { return m_runningActions.size(); } @@ -214,15 +215,16 @@ inline std::pair { - ServiceStatus(const ServiceSetup &setup); + ServiceStatus(ServiceSetup &setup); const char *const version = nullptr; const LibPkg::Status config; const BuildActionMetaInfo &actions; const BuildPresets &presets; + ResourceUsage resourceUsage; }; -inline ServiceStatus ServiceSetup::computeStatus() const +inline ServiceStatus ServiceSetup::computeStatus() { return ServiceStatus(*this); } diff --git a/srv/static/js/globalstatuspage.js b/srv/static/js/globalstatuspage.js index 3e41042..e461b77 100644 --- a/srv/static/js/globalstatuspage.js +++ b/srv/static/js/globalstatuspage.js @@ -30,7 +30,7 @@ function handleGlobalStatusUpdate(ajaxRequest) Utils.getAndEmptyElement('application-version').appendChild(document.createTextNode(applicationVersion)); } const dbStats = responseJson.config.dbStats; - const table = GenericRendering.renderTableFromJsonArray({ + const dbTable = GenericRendering.renderTableFromJsonArray({ rows: dbStats, columnHeaders: ['Arch', 'Database', 'Package count', 'Last update', 'Synced from mirror'], columnAccessors: ['arch', 'name', 'packageCount', 'lastUpdate', 'syncFromMirror'], @@ -49,7 +49,31 @@ function handleGlobalStatusUpdate(ajaxRequest) }, }, }); - globalStatus.appendChild(table); + globalStatus.appendChild(dbTable); + + const resourceUsageHeading = document.createElement('h2'); + resourceUsageHeading.appendChild(document.createTextNode('Resource usage')); + globalStatus.appendChild(resourceUsageHeading); + const resTable = GenericRendering.renderTableFromJsonObject({ + data: responseJson.resourceUsage, + displayLabels: [ + 'Virtual memory', 'Resident set size', 'Peak resident set size', 'Shared resident set size', + 'Package-DB size', 'Actions-DB size', 'Cached packages', 'Actions', 'Running actions', + ], + fieldAccessors: [ + 'virtualMemory', 'residentSetSize', 'peakResidentSetSize', 'sharedResidentSetSize', + 'packageDbSize', 'actionsDbSize', 'cachedPackages', 'actionsCount', 'runningActionsCount', + ], + customRenderer: { + virtualMemory: GenericRendering.renderDataSize, + residentSetSize: GenericRendering.renderDataSize, + peakResidentSetSize: GenericRendering.renderDataSize, + sharedResidentSetSize: GenericRendering.renderDataSize, + packageDbSize: GenericRendering.renderDataSize, + actionsDbSize: GenericRendering.renderDataSize, + }, + }); + globalStatus.appendChild(resTable); // update database selections const repoSelections = [