Instanciated the profiler + added a way to dump the export the profilin data in the UI
This commit is contained in:
@@ -14,6 +14,7 @@ add_executable(lms
|
||||
ui/admin/InitWizardView.cpp
|
||||
ui/admin/MediaLibrariesView.cpp
|
||||
ui/admin/MediaLibraryModal.cpp
|
||||
ui/admin/ProfilerController.cpp
|
||||
ui/admin/ScannerController.cpp
|
||||
ui/admin/ScanSettingsView.cpp
|
||||
ui/admin/UserView.cpp
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "utils/IChildProcessManager.hpp"
|
||||
#include "utils/IConfig.hpp"
|
||||
#include "utils/IOContextRunner.hpp"
|
||||
#include "utils/IProfiler.hpp"
|
||||
#include "utils/Service.hpp"
|
||||
#include "utils/String.hpp"
|
||||
#include "utils/WtLogger.hpp"
|
||||
@@ -75,6 +76,20 @@ namespace
|
||||
throw LmsException{ "Invalid config value for 'log-min-severity'" };
|
||||
}
|
||||
|
||||
std::optional<profiling::Level> getProfilingLevel()
|
||||
{
|
||||
std::string_view profilingLevel{ Service<IConfig>::get()->getString("profiling-level", "disabled") };
|
||||
|
||||
if (profilingLevel == "disabled")
|
||||
return std::nullopt;
|
||||
else if (profilingLevel == "overview")
|
||||
return profiling::Level::Overview;
|
||||
else if (profilingLevel == "detailed")
|
||||
return profiling::Level::Detailed;
|
||||
|
||||
throw LmsException{ "Invalid config value for 'profiling-level'" };
|
||||
}
|
||||
|
||||
std::vector<std::string> generateWtConfig(std::string execPath, Severity minSeverity)
|
||||
{
|
||||
std::vector<std::string> args;
|
||||
@@ -233,6 +248,9 @@ int main(int argc, char* argv[])
|
||||
Service<IConfig> config{ createConfig(configFilePath) };
|
||||
const Severity minLogSeverity{getLogMinSeverity()};
|
||||
Service<ILogger> logger{ std::make_unique<WtLogger>(minLogSeverity) };
|
||||
std::optional<Service<profiling::IProfiler>> profiler;
|
||||
if (const auto level{ getProfilingLevel() })
|
||||
profiler.emplace(profiling::createProfiler(level.value(), config->getULong("profiling-buffer-size", profiling::MinBufferSizeInMBytes)));
|
||||
|
||||
// use system locale. libarchive relies on this to write filenames
|
||||
if (char* locale{ ::setlocale(LC_ALL, "") })
|
||||
@@ -243,6 +261,7 @@ int main(int argc, char* argv[])
|
||||
// Make sure the working directory exists
|
||||
std::filesystem::create_directories(config->getPath("working-dir"));
|
||||
std::filesystem::create_directories(config->getPath("working-dir") / "cache");
|
||||
std::filesystem::create_directories(config->getPath("working-dir") / "profiling");
|
||||
|
||||
// Construct WT configuration and get the argc/argv back
|
||||
const std::vector<std::string> wtServerArgs{ generateWtConfig(argv[0], minLogSeverity) };
|
||||
|
||||
@@ -38,15 +38,17 @@
|
||||
#include "database/User.hpp"
|
||||
#include "services/scrobbling/IScrobblingService.hpp"
|
||||
#include "utils/ILogger.hpp"
|
||||
#include "utils/IProfiler.hpp"
|
||||
#include "utils/Service.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "admin/InitWizardView.hpp"
|
||||
#include "admin/MediaLibrariesView.hpp"
|
||||
#include "admin/ProfilerController.hpp"
|
||||
#include "admin/ScannerController.hpp"
|
||||
#include "admin/ScanSettingsView.hpp"
|
||||
#include "admin/UserView.hpp"
|
||||
#include "admin/UsersView.hpp"
|
||||
#include "admin/ScannerController.hpp"
|
||||
#include "common/Template.hpp"
|
||||
#include "explore/Explore.hpp"
|
||||
#include "explore/Filters.hpp"
|
||||
@@ -77,6 +79,7 @@ namespace UserInterface
|
||||
res->use(appRoot + "admin-initwizard");
|
||||
res->use(appRoot + "admin-medialibraries");
|
||||
res->use(appRoot + "admin-medialibrary");
|
||||
res->use(appRoot + "admin-profilercontroller");
|
||||
res->use(appRoot + "admin-scannercontroller");
|
||||
res->use(appRoot + "admin-scansettings");
|
||||
res->use(appRoot + "admin-user");
|
||||
@@ -119,6 +122,7 @@ namespace UserInterface
|
||||
IdxAdminScanner,
|
||||
IdxAdminUsers,
|
||||
IdxAdminUser,
|
||||
IdxAdminProfiler,
|
||||
};
|
||||
|
||||
void handlePathChange(Wt::WStackedWidget& stack, bool isAdmin)
|
||||
@@ -146,6 +150,7 @@ namespace UserInterface
|
||||
{ "/admin/scanner", IdxAdminScanner, true, Wt::WString::tr("Lms.Admin.ScannerController.scanner") },
|
||||
{ "/admin/users", IdxAdminUsers, true, Wt::WString::tr("Lms.Admin.Users.users") },
|
||||
{ "/admin/user", IdxAdminUser, true, std::nullopt },
|
||||
{ "/admin/profiler", IdxAdminProfiler, true, Wt::WString::tr("Lms.Admin.ProfilerController.profiler") },
|
||||
};
|
||||
|
||||
LMS_LOG(UI, DEBUG, "Internal path changed to '" << wApp->internalPath() << "'");
|
||||
@@ -264,6 +269,8 @@ namespace UserInterface
|
||||
|
||||
void LmsApplication::init()
|
||||
{
|
||||
LMS_SCOPED_PROFILE_OVERVIEW("UI", "ApplicationInit");
|
||||
|
||||
setTheme(std::make_shared<LmsTheme>());
|
||||
|
||||
useStyleSheet("resources/font-awesome/css/font-awesome.min.css");
|
||||
@@ -381,6 +388,8 @@ namespace UserInterface
|
||||
|
||||
void LmsApplication::createHome()
|
||||
{
|
||||
LMS_SCOPED_PROFILE_OVERVIEW("UI", "ApplicationCreateHome");
|
||||
|
||||
_coverResource = std::make_shared<CoverResource>();
|
||||
|
||||
declareJavaScriptFunction("onLoadCover", "function(id) { id.className += \" Lms-cover-loaded\"}");
|
||||
@@ -436,6 +445,11 @@ namespace UserInterface
|
||||
navbar->bindNew<Wt::WAnchor>("scan-settings", Wt::WLink{ Wt::LinkType::InternalPath, "/admin/scan-settings" }, Wt::WString::tr("Lms.Admin.menu-scan-settings"));
|
||||
navbar->bindNew<Wt::WAnchor>("scanner", Wt::WLink{ Wt::LinkType::InternalPath, "/admin/scanner" }, Wt::WString::tr("Lms.Admin.menu-scanner"));
|
||||
navbar->bindNew<Wt::WAnchor>("users", Wt::WLink{ Wt::LinkType::InternalPath, "/admin/users" }, Wt::WString::tr("Lms.Admin.menu-users"));
|
||||
// Hide the entry if the profiler is not enabled
|
||||
if (Service<::profiling::IProfiler>::get())
|
||||
navbar->bindNew<Wt::WAnchor>("profiler", Wt::WLink{ Wt::LinkType::InternalPath, "/admin/profiler" }, Wt::WString::tr("Lms.Admin.menu-profiler"));
|
||||
else
|
||||
navbar->bindEmpty("profiler");
|
||||
}
|
||||
|
||||
// Contents
|
||||
@@ -467,6 +481,7 @@ namespace UserInterface
|
||||
mainStack->addNew<ScannerController>();
|
||||
mainStack->addNew<UsersView>();
|
||||
mainStack->addNew<UserView>();
|
||||
mainStack->addNew<ProfilerController>();
|
||||
}
|
||||
|
||||
explore->getPlayQueueController().setMaxTrackCountToEnqueue(_playQueue->getCapacity());
|
||||
@@ -544,6 +559,7 @@ namespace UserInterface
|
||||
{
|
||||
try
|
||||
{
|
||||
LMS_SCOPED_PROFILE_OVERVIEW("UI", "ProcessEvent");
|
||||
WApplication::notify(event);
|
||||
}
|
||||
catch (LmsApplicationException& e)
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS 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.
|
||||
*
|
||||
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ProfilerController.hpp"
|
||||
|
||||
#include <Wt/Http/Response.h>
|
||||
#include <Wt/WDateTime.h>
|
||||
#include <Wt/WPushButton.h>
|
||||
#include <Wt/WResource.h>
|
||||
|
||||
#include "utils/IProfiler.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
namespace
|
||||
{
|
||||
class ReportResource : public Wt::WResource
|
||||
{
|
||||
public:
|
||||
ReportResource(::profiling::IProfiler& profiler)
|
||||
: _profiler{ profiler }
|
||||
{
|
||||
}
|
||||
|
||||
~ReportResource()
|
||||
{
|
||||
beingDeleted();
|
||||
}
|
||||
|
||||
void handleRequest(const Wt::Http::Request&, Wt::Http::Response& response)
|
||||
{
|
||||
suggestFileName(StringUtils::toISO8601String(Wt::WDateTime::currentDateTime()) + "-profiling.json");
|
||||
response.setMimeType("application/json");
|
||||
_profiler.dumpCurrentBuffer(response.out());
|
||||
}
|
||||
|
||||
private:
|
||||
profiling::IProfiler& _profiler;
|
||||
};
|
||||
}
|
||||
|
||||
ProfilerController::ProfilerController()
|
||||
: Wt::WTemplate{ Wt::WString::tr("Lms.Admin.ProfilerController.template") }
|
||||
{
|
||||
addFunction("tr", &Wt::WTemplate::Functions::tr);
|
||||
|
||||
Wt::WPushButton* dumpBtn{ bindNew<Wt::WPushButton>("export-btn", Wt::WString::tr("Lms.Admin.ProfilerController.export-current-buffer")) };
|
||||
|
||||
if (auto profiler{ Service<profiling::IProfiler>::get() })
|
||||
{
|
||||
Wt::WLink link{ std::make_shared<ReportResource>(*profiler) };
|
||||
link.setTarget(Wt::LinkTarget::NewWindow);
|
||||
dumpBtn->setLink(link);
|
||||
}
|
||||
else
|
||||
dumpBtn->setEnabled(false);
|
||||
}
|
||||
} // namespace UserInterface
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS 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.
|
||||
*
|
||||
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Wt/WTemplate.h>
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
class ProfilerController : public Wt::WTemplate
|
||||
{
|
||||
public:
|
||||
ProfilerController();
|
||||
};
|
||||
} // namespace UserInterface
|
||||
Reference in New Issue
Block a user