Profiler support. Currently JProfiler and JVisualVM are implemented.
This commit is contained in:
parent
5cf599673d
commit
efa8e26a3f
@ -498,6 +498,14 @@ logic/assets/AssetsMigrateTask.h
|
|||||||
logic/assets/AssetsMigrateTask.cpp
|
logic/assets/AssetsMigrateTask.cpp
|
||||||
logic/assets/AssetsUtils.h
|
logic/assets/AssetsUtils.h
|
||||||
logic/assets/AssetsUtils.cpp
|
logic/assets/AssetsUtils.cpp
|
||||||
|
|
||||||
|
# Profiling
|
||||||
|
logic/profiler/BaseProfiler.h
|
||||||
|
logic/profiler/BaseProfiler.cpp
|
||||||
|
logic/profiler/JProfiler.h
|
||||||
|
logic/profiler/JProfiler.cpp
|
||||||
|
logic/profiler/JVisualVM.h
|
||||||
|
logic/profiler/JVisualVM.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
25
MultiMC.cpp
25
MultiMC.cpp
@ -31,6 +31,9 @@
|
|||||||
#include "logic/updater/UpdateChecker.h"
|
#include "logic/updater/UpdateChecker.h"
|
||||||
#include "logic/updater/NotificationChecker.h"
|
#include "logic/updater/NotificationChecker.h"
|
||||||
|
|
||||||
|
#include "logic/profiler/JProfiler.h"
|
||||||
|
#include "logic/profiler/JVisualVM.h"
|
||||||
|
|
||||||
#include "pathutils.h"
|
#include "pathutils.h"
|
||||||
#include "cmdutils.h"
|
#include "cmdutils.h"
|
||||||
#include <inisettingsobject.h>
|
#include <inisettingsobject.h>
|
||||||
@ -41,8 +44,9 @@
|
|||||||
using namespace Util::Commandline;
|
using namespace Util::Commandline;
|
||||||
|
|
||||||
MultiMC::MultiMC(int &argc, char **argv, bool root_override)
|
MultiMC::MultiMC(int &argc, char **argv, bool root_override)
|
||||||
: QApplication(argc, argv), m_version{VERSION_MAJOR, VERSION_MINOR, VERSION_HOTFIX,
|
: QApplication(argc, argv),
|
||||||
VERSION_BUILD, MultiMCVersion::VERSION_TYPE, VERSION_CHANNEL, BUILD_PLATFORM}
|
m_version{VERSION_MAJOR, VERSION_MINOR, VERSION_HOTFIX, VERSION_BUILD,
|
||||||
|
MultiMCVersion::VERSION_TYPE, VERSION_CHANNEL, BUILD_PLATFORM}
|
||||||
{
|
{
|
||||||
setOrganizationName("MultiMC");
|
setOrganizationName("MultiMC");
|
||||||
setApplicationName("MultiMC5");
|
setApplicationName("MultiMC5");
|
||||||
@ -211,6 +215,15 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
|
|||||||
// init proxy settings
|
// init proxy settings
|
||||||
updateProxySettings();
|
updateProxySettings();
|
||||||
|
|
||||||
|
m_profilers.insert("jprofiler",
|
||||||
|
std::shared_ptr<BaseProfilerFactory>(new JProfilerFactory()));
|
||||||
|
m_profilers.insert("jvisualvm",
|
||||||
|
std::shared_ptr<BaseProfilerFactory>(new JVisualVMFactory()));
|
||||||
|
for (auto profiler : m_profilers.values())
|
||||||
|
{
|
||||||
|
profiler->registerSettings(m_settings.get());
|
||||||
|
}
|
||||||
|
|
||||||
// launch instance, if that's what should be done
|
// launch instance, if that's what should be done
|
||||||
// WARNING: disabled until further notice
|
// WARNING: disabled until further notice
|
||||||
/*
|
/*
|
||||||
@ -426,6 +439,9 @@ void MultiMC::initGlobalSettings()
|
|||||||
m_settings->registerSetting("ConsoleWindowGeometry", "");
|
m_settings->registerSetting("ConsoleWindowGeometry", "");
|
||||||
|
|
||||||
m_settings->registerSetting("SettingsGeometry", "");
|
m_settings->registerSetting("SettingsGeometry", "");
|
||||||
|
|
||||||
|
// Profilers
|
||||||
|
m_settings->registerSetting("CurrentProfiler");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiMC::initHttpMetaCache()
|
void MultiMC::initHttpMetaCache()
|
||||||
@ -554,6 +570,11 @@ std::shared_ptr<JavaVersionList> MultiMC::javalist()
|
|||||||
return m_javalist;
|
return m_javalist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<BaseProfilerFactory> MultiMC::currentProfiler()
|
||||||
|
{
|
||||||
|
return m_profilers.value(m_settings->get("CurrentProfiler").toString());
|
||||||
|
}
|
||||||
|
|
||||||
void MultiMC::installUpdates(const QString updateFilesDir, UpdateFlags flags)
|
void MultiMC::installUpdates(const QString updateFilesDir, UpdateFlags flags)
|
||||||
{
|
{
|
||||||
// if we are going to update on exit, save the params now
|
// if we are going to update on exit, save the params now
|
||||||
|
@ -22,6 +22,7 @@ class UpdateChecker;
|
|||||||
class NotificationChecker;
|
class NotificationChecker;
|
||||||
class NewsChecker;
|
class NewsChecker;
|
||||||
class StatusChecker;
|
class StatusChecker;
|
||||||
|
class BaseProfilerFactory;
|
||||||
|
|
||||||
#if defined(MMC)
|
#if defined(MMC)
|
||||||
#undef MMC
|
#undef MMC
|
||||||
@ -127,6 +128,12 @@ public:
|
|||||||
|
|
||||||
std::shared_ptr<JavaVersionList> javalist();
|
std::shared_ptr<JavaVersionList> javalist();
|
||||||
|
|
||||||
|
QMap<QString, std::shared_ptr<BaseProfilerFactory>> profilers()
|
||||||
|
{
|
||||||
|
return m_profilers;
|
||||||
|
}
|
||||||
|
std::shared_ptr<BaseProfilerFactory> currentProfiler();
|
||||||
|
|
||||||
void installUpdates(const QString updateFilesDir, UpdateFlags flags = None);
|
void installUpdates(const QString updateFilesDir, UpdateFlags flags = None);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -198,6 +205,7 @@ private:
|
|||||||
std::shared_ptr<ForgeVersionList> m_forgelist;
|
std::shared_ptr<ForgeVersionList> m_forgelist;
|
||||||
std::shared_ptr<MinecraftVersionList> m_minecraftlist;
|
std::shared_ptr<MinecraftVersionList> m_minecraftlist;
|
||||||
std::shared_ptr<JavaVersionList> m_javalist;
|
std::shared_ptr<JavaVersionList> m_javalist;
|
||||||
|
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
|
||||||
QsLogging::DestinationPtr m_fileDestination;
|
QsLogging::DestinationPtr m_fileDestination;
|
||||||
QsLogging::DestinationPtr m_debugDestination;
|
QsLogging::DestinationPtr m_debugDestination;
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
#include <QWidgetAction>
|
#include <QWidgetAction>
|
||||||
|
#include <QProgressDialog>
|
||||||
|
|
||||||
#include "osutils.h"
|
#include "osutils.h"
|
||||||
#include "userutils.h"
|
#include "userutils.h"
|
||||||
@ -97,6 +98,9 @@
|
|||||||
#include <logic/updater/NotificationChecker.h>
|
#include <logic/updater/NotificationChecker.h>
|
||||||
#include <logic/tasks/ThreadTask.h>
|
#include <logic/tasks/ThreadTask.h>
|
||||||
|
|
||||||
|
#include "logic/profiler/BaseProfiler.h"
|
||||||
|
#include "logic/OneSixInstance.h"
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
|
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
|
||||||
{
|
{
|
||||||
MultiMCPlatform::fixWM_CLASS(this);
|
MultiMCPlatform::fixWM_CLASS(this);
|
||||||
@ -1078,7 +1082,7 @@ void MainWindow::on_actionLaunchInstanceOffline_triggered()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::doLaunch(bool online)
|
void MainWindow::doLaunch(bool online, bool profile)
|
||||||
{
|
{
|
||||||
if (!m_selectedInstance)
|
if (!m_selectedInstance)
|
||||||
return;
|
return;
|
||||||
@ -1194,11 +1198,11 @@ void MainWindow::doLaunch(bool online)
|
|||||||
// update first if the server actually responded
|
// update first if the server actually responded
|
||||||
if (session->auth_server_online)
|
if (session->auth_server_online)
|
||||||
{
|
{
|
||||||
updateInstance(m_selectedInstance, session);
|
updateInstance(m_selectedInstance, session, profile);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
launchInstance(m_selectedInstance, session);
|
launchInstance(m_selectedInstance, session, profile);
|
||||||
}
|
}
|
||||||
tryagain = false;
|
tryagain = false;
|
||||||
}
|
}
|
||||||
@ -1206,22 +1210,22 @@ void MainWindow::doLaunch(bool online)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateInstance(BaseInstance *instance, AuthSessionPtr session)
|
void MainWindow::updateInstance(BaseInstance *instance, AuthSessionPtr session, bool profile)
|
||||||
{
|
{
|
||||||
auto updateTask = instance->doUpdate();
|
auto updateTask = instance->doUpdate();
|
||||||
if (!updateTask)
|
if (!updateTask)
|
||||||
{
|
{
|
||||||
launchInstance(instance, session);
|
launchInstance(instance, session, profile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ProgressDialog tDialog(this);
|
ProgressDialog tDialog(this);
|
||||||
connect(updateTask.get(), &Task::succeeded, [this, instance, session]
|
connect(updateTask.get(), &Task::succeeded, [this, instance, session, profile]
|
||||||
{ launchInstance(instance, session); });
|
{ launchInstance(instance, session, profile); });
|
||||||
connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString)));
|
connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString)));
|
||||||
tDialog.exec(updateTask.get());
|
tDialog.exec(updateTask.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session)
|
void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session, bool profile)
|
||||||
{
|
{
|
||||||
Q_ASSERT_X(instance != NULL, "launchInstance", "instance is NULL");
|
Q_ASSERT_X(instance != NULL, "launchInstance", "instance is NULL");
|
||||||
Q_ASSERT_X(session.get() != nullptr, "launchInstance", "session is NULL");
|
Q_ASSERT_X(session.get() != nullptr, "launchInstance", "session is NULL");
|
||||||
@ -1237,6 +1241,33 @@ void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session)
|
|||||||
|
|
||||||
proc->setLogin(session);
|
proc->setLogin(session);
|
||||||
proc->launch();
|
proc->launch();
|
||||||
|
|
||||||
|
if (profile && qobject_cast<OneSixInstance *>(instance))
|
||||||
|
{
|
||||||
|
BaseProfiler *profiler = MMC->currentProfiler()->createProfiler(
|
||||||
|
qobject_cast<OneSixInstance *>(instance), this);
|
||||||
|
QProgressDialog dialog;
|
||||||
|
dialog.setMinimum(0);
|
||||||
|
dialog.setMaximum(0);
|
||||||
|
dialog.setValue(0);
|
||||||
|
dialog.setLabelText(tr("Waiting for profiler..."));
|
||||||
|
dialog.show();
|
||||||
|
connect(profiler, &BaseProfiler::readyToLaunch, [&dialog, this](const QString &message)
|
||||||
|
{
|
||||||
|
dialog.accept();
|
||||||
|
QMessageBox msg;
|
||||||
|
msg.setText(tr("The launch of Minecraft itself is delayed until you press the "
|
||||||
|
"button. This is the right time to setup the profiler, as the "
|
||||||
|
"profiler server is running now.\n\n%1").arg(message));
|
||||||
|
msg.setWindowTitle(tr("Waiting"));
|
||||||
|
msg.setIcon(QMessageBox::Information);
|
||||||
|
msg.addButton(tr("Launch"), QMessageBox::AcceptRole);
|
||||||
|
msg.exec();
|
||||||
|
proc->write("launch onesix\n");
|
||||||
|
});
|
||||||
|
profiler->beginProfiling(proc);
|
||||||
|
dialog.exec();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onGameUpdateError(QString error)
|
void MainWindow::onGameUpdateError(QString error)
|
||||||
@ -1416,6 +1447,15 @@ void MainWindow::on_actionEditInstNotes_triggered()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionProfileInstance_triggered()
|
||||||
|
{
|
||||||
|
if (m_selectedInstance)
|
||||||
|
{
|
||||||
|
NagUtils::checkJVMArgs(m_selectedInstance->settings().get("JvmArgs").toString(), this);
|
||||||
|
doLaunch(true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::instanceEnded()
|
void MainWindow::instanceEnded()
|
||||||
{
|
{
|
||||||
this->show();
|
this->show();
|
||||||
|
@ -107,22 +107,24 @@ slots:
|
|||||||
|
|
||||||
void on_actionEditInstNotes_triggered();
|
void on_actionEditInstNotes_triggered();
|
||||||
|
|
||||||
|
void on_actionProfileInstance_triggered();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Launches the currently selected instance with the default account.
|
* Launches the currently selected instance with the default account.
|
||||||
* If no default account is selected, prompts the user to pick an account.
|
* If no default account is selected, prompts the user to pick an account.
|
||||||
*/
|
*/
|
||||||
void doLaunch(bool online = true);
|
void doLaunch(bool online = true, bool profile = false);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Launches the given instance with the given account.
|
* Launches the given instance with the given account.
|
||||||
* This function assumes that the given account has a valid, usable access token.
|
* This function assumes that the given account has a valid, usable access token.
|
||||||
*/
|
*/
|
||||||
void launchInstance(BaseInstance *instance, AuthSessionPtr session);
|
void launchInstance(BaseInstance *instance, AuthSessionPtr session, bool profile = false);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Prepares the given instance for launch with the given account.
|
* Prepares the given instance for launch with the given account.
|
||||||
*/
|
*/
|
||||||
void updateInstance(BaseInstance *instance, AuthSessionPtr account);
|
void updateInstance(BaseInstance *instance, AuthSessionPtr account, bool profile = false);
|
||||||
|
|
||||||
void onGameUpdateError(QString error);
|
void onGameUpdateError(QString error);
|
||||||
|
|
||||||
|
@ -108,6 +108,7 @@
|
|||||||
<addaction name="actionChangeInstIcon"/>
|
<addaction name="actionChangeInstIcon"/>
|
||||||
<addaction name="actionLaunchInstance"/>
|
<addaction name="actionLaunchInstance"/>
|
||||||
<addaction name="actionLaunchInstanceOffline"/>
|
<addaction name="actionLaunchInstanceOffline"/>
|
||||||
|
<addaction name="actionProfileInstance"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionEditInstNotes"/>
|
<addaction name="actionEditInstNotes"/>
|
||||||
<addaction name="actionChangeInstGroup"/>
|
<addaction name="actionChangeInstGroup"/>
|
||||||
@ -528,12 +529,19 @@
|
|||||||
<string>Launch the selected instance.</string>
|
<string>Launch the selected instance.</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionProfileInstance">
|
||||||
|
<property name="text">
|
||||||
|
<string>Profile</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Starts a profiling session with the current instance</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../resources/instances/instances.qrc"/>
|
|
||||||
<include location="../resources/multimc/multimc.qrc"/>
|
<include location="../resources/multimc/multimc.qrc"/>
|
||||||
<include location="../resources/backgrounds/backgrounds.qrc"/>
|
<include location="../resources/instances/instances.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
|
|
||||||
#include "logic/updater/UpdateChecker.h"
|
#include "logic/updater/UpdateChecker.h"
|
||||||
|
|
||||||
|
#include "logic/profiler/BaseProfiler.h"
|
||||||
|
|
||||||
#include <settingsobject.h>
|
#include <settingsobject.h>
|
||||||
#include <pathutils.h>
|
#include <pathutils.h>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
@ -368,6 +370,22 @@ void SettingsDialog::applySettings(SettingsObject *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
s->set("PostExitCommand", ui->postExitCmdTextBox->text());
|
s->set("PostExitCommand", ui->postExitCmdTextBox->text());
|
||||||
|
|
||||||
|
// Profilers
|
||||||
|
s->set("JProfilerPath", ui->jprofilerPathEdit->text());
|
||||||
|
s->set("JVisualVMPath", ui->jvisualvmPathEdit->text());
|
||||||
|
if (ui->profilerNoneBtn->isChecked())
|
||||||
|
{
|
||||||
|
s->set("CurrentProfiler", QString());
|
||||||
|
}
|
||||||
|
else if (ui->jprofilerBtn->isChecked())
|
||||||
|
{
|
||||||
|
s->set("CurrentProfiler", "jprofiler");
|
||||||
|
}
|
||||||
|
else if (ui->jvisualvmBtn->isChecked())
|
||||||
|
{
|
||||||
|
s->set("CurrentProfiler", "jvisualvm");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsDialog::loadSettings(SettingsObject *s)
|
void SettingsDialog::loadSettings(SettingsObject *s)
|
||||||
@ -447,6 +465,23 @@ void SettingsDialog::loadSettings(SettingsObject *s)
|
|||||||
// Custom Commands
|
// Custom Commands
|
||||||
ui->preLaunchCmdTextBox->setText(s->get("PreLaunchCommand").toString());
|
ui->preLaunchCmdTextBox->setText(s->get("PreLaunchCommand").toString());
|
||||||
ui->postExitCmdTextBox->setText(s->get("PostExitCommand").toString());
|
ui->postExitCmdTextBox->setText(s->get("PostExitCommand").toString());
|
||||||
|
|
||||||
|
// Profilers
|
||||||
|
ui->jprofilerPathEdit->setText(s->get("JProfilerPath").toString());
|
||||||
|
ui->jvisualvmPathEdit->setText(s->get("JVisualVMPath").toString());
|
||||||
|
const QString currentProfiler = s->get("CurrentProfiler").toString();
|
||||||
|
if (currentProfiler.isEmpty())
|
||||||
|
{
|
||||||
|
ui->profilerNoneBtn->setChecked(true);
|
||||||
|
}
|
||||||
|
else if (currentProfiler == "jprofiler")
|
||||||
|
{
|
||||||
|
ui->jprofilerBtn->setChecked(true);
|
||||||
|
}
|
||||||
|
else if (currentProfiler == "jvisualvm")
|
||||||
|
{
|
||||||
|
ui->jvisualvmBtn->setChecked(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsDialog::on_javaDetectBtn_clicked()
|
void SettingsDialog::on_javaDetectBtn_clicked()
|
||||||
@ -503,3 +538,53 @@ void SettingsDialog::checkFinished(JavaCheckResult result)
|
|||||||
"or set the path to the java executable."));
|
"or set the path to the java executable."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsDialog::on_jprofilerPathBtn_clicked()
|
||||||
|
{
|
||||||
|
QString raw_dir = QFileDialog::getExistingDirectory(this, tr("JProfiler Directory"),
|
||||||
|
ui->jprofilerPathEdit->text());
|
||||||
|
QString cooked_dir = NormalizePath(raw_dir);
|
||||||
|
|
||||||
|
// do not allow current dir - it's dirty. Do not allow dirs that don't exist
|
||||||
|
if (!cooked_dir.isEmpty() && QDir(cooked_dir).exists())
|
||||||
|
{
|
||||||
|
ui->jprofilerPathEdit->setText(cooked_dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void SettingsDialog::on_jprofilerCheckBtn_clicked()
|
||||||
|
{
|
||||||
|
if (!ui->jprofilerPathEdit->text().isEmpty())
|
||||||
|
{
|
||||||
|
QString error;
|
||||||
|
if (!MMC->profilers()["jprofiler"]->check(ui->jprofilerPathEdit->text(), &error))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"),
|
||||||
|
tr("Error while checking JProfiler install:\n%1").arg(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsDialog::on_jvisualvmPathBtn_clicked()
|
||||||
|
{
|
||||||
|
QString raw_dir = QFileDialog::getOpenFileName(this, tr("JVisualVM Executable"),
|
||||||
|
ui->jvisualvmPathEdit->text());
|
||||||
|
QString cooked_dir = NormalizePath(raw_dir);
|
||||||
|
|
||||||
|
// do not allow current dir - it's dirty. Do not allow dirs that don't exist
|
||||||
|
if (!cooked_dir.isEmpty() && QDir(cooked_dir).exists())
|
||||||
|
{
|
||||||
|
ui->jvisualvmPathEdit->setText(cooked_dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void SettingsDialog::on_jvisualvmCheckBtn_clicked()
|
||||||
|
{
|
||||||
|
if (!ui->jvisualvmPathEdit->text().isEmpty())
|
||||||
|
{
|
||||||
|
QString error;
|
||||||
|
if (!MMC->profilers()["jvisualvm"]->check(ui->jvisualvmPathEdit->text(), &error))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"),
|
||||||
|
tr("Error while checking JVisualVM install:\n%1").arg(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -75,6 +75,11 @@ slots:
|
|||||||
|
|
||||||
void checkFinished(JavaCheckResult result);
|
void checkFinished(JavaCheckResult result);
|
||||||
|
|
||||||
|
void on_jprofilerPathBtn_clicked();
|
||||||
|
void on_jprofilerCheckBtn_clicked();
|
||||||
|
void on_jvisualvmPathBtn_clicked();
|
||||||
|
void on_jvisualvmCheckBtn_clicked();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Updates the list of update channels in the combo box.
|
* Updates the list of update channels in the combo box.
|
||||||
*/
|
*/
|
||||||
|
@ -863,6 +863,116 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="profilingTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Profiling</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_4">
|
||||||
|
<property name="title">
|
||||||
|
<string>Active profiler</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_12">
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="profilerNoneBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>None</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="jprofilerBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>JProfiler</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="jvisualvmBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>JVisualVM</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
|
<property name="title">
|
||||||
|
<string>JProfiler</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="jprofilerPathEdit"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="jprofilerPathBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="jprofilerCheckBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Check</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_3">
|
||||||
|
<property name="title">
|
||||||
|
<string>JVisualVM</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_11">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="jvisualvmPathEdit"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="jvisualvmPathBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="jvisualvmCheckBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Check</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -938,7 +1048,7 @@
|
|||||||
</connection>
|
</connection>
|
||||||
</connections>
|
</connections>
|
||||||
<buttongroups>
|
<buttongroups>
|
||||||
<buttongroup name="proxyGroup"/>
|
|
||||||
<buttongroup name="sortingModeGroup"/>
|
<buttongroup name="sortingModeGroup"/>
|
||||||
|
<buttongroup name="proxyGroup"/>
|
||||||
</buttongroups>
|
</buttongroups>
|
||||||
</ui>
|
</ui>
|
||||||
|
@ -228,7 +228,6 @@ MinecraftProcess *OneSixInstance::prepareForLaunch(AuthSessionPtr session)
|
|||||||
launchScript += "ext " + finfo.absoluteFilePath() + "\n";
|
launchScript += "ext " + finfo.absoluteFilePath() + "\n";
|
||||||
}
|
}
|
||||||
launchScript += "natives " + natives_dir.absolutePath() + "\n";
|
launchScript += "natives " + natives_dir.absolutePath() + "\n";
|
||||||
launchScript += "launch onesix\n";
|
|
||||||
|
|
||||||
// create the process and set its parameters
|
// create the process and set its parameters
|
||||||
MinecraftProcess *proc = new MinecraftProcess(this);
|
MinecraftProcess *proc = new MinecraftProcess(this);
|
||||||
|
19
logic/profiler/BaseProfiler.cpp
Normal file
19
logic/profiler/BaseProfiler.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include "BaseProfiler.h"
|
||||||
|
|
||||||
|
BaseProfiler::BaseProfiler(OneSixInstance *instance, QObject *parent)
|
||||||
|
: QObject(parent), m_instance(instance)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseProfiler::~BaseProfiler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseProfiler::beginProfiling(MinecraftProcess *process)
|
||||||
|
{
|
||||||
|
beginProfilingImpl(process);
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseProfilerFactory::~BaseProfilerFactory()
|
||||||
|
{
|
||||||
|
}
|
39
logic/profiler/BaseProfiler.h
Normal file
39
logic/profiler/BaseProfiler.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class OneSixInstance;
|
||||||
|
class SettingsObject;
|
||||||
|
class MinecraftProcess;
|
||||||
|
|
||||||
|
class BaseProfiler : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit BaseProfiler(OneSixInstance *instance, QObject *parent = 0);
|
||||||
|
virtual ~BaseProfiler();
|
||||||
|
|
||||||
|
public
|
||||||
|
slots:
|
||||||
|
void beginProfiling(MinecraftProcess *process);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
OneSixInstance *m_instance;
|
||||||
|
|
||||||
|
virtual void beginProfilingImpl(MinecraftProcess *process) = 0;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void readyToLaunch(const QString &message);
|
||||||
|
};
|
||||||
|
|
||||||
|
class BaseProfilerFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~BaseProfilerFactory();
|
||||||
|
|
||||||
|
virtual void registerSettings(SettingsObject *settings) = 0;
|
||||||
|
|
||||||
|
virtual BaseProfiler *createProfiler(OneSixInstance *instance, QObject *parent = 0) = 0;
|
||||||
|
|
||||||
|
virtual bool check(const QString &path, QString *error) = 0;
|
||||||
|
};
|
56
logic/profiler/JProfiler.cpp
Normal file
56
logic/profiler/JProfiler.cpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include "JProfiler.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include "settingsobject.h"
|
||||||
|
#include "logic/MinecraftProcess.h"
|
||||||
|
#include "logic/OneSixInstance.h"
|
||||||
|
#include "MultiMC.h"
|
||||||
|
|
||||||
|
JProfiler::JProfiler(OneSixInstance *instance, QObject *parent) : BaseProfiler(instance, parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void JProfiler::beginProfilingImpl(MinecraftProcess *process)
|
||||||
|
{
|
||||||
|
int port = MMC->settings()->get("JProfilerPort").toInt();
|
||||||
|
QProcess *profiler = new QProcess(this);
|
||||||
|
profiler->setArguments(QStringList() << "-d" << QString::number(process->pid()) << "--gui"
|
||||||
|
<< "-p" << QString::number(port));
|
||||||
|
profiler->setProgram(QDir(MMC->settings()->get("JProfilerPath").toString())
|
||||||
|
.absoluteFilePath("bin/jpenable"));
|
||||||
|
connect(profiler, &QProcess::started, [this, port]()
|
||||||
|
{ emit readyToLaunch(tr("Listening on port: %1").arg(port)); });
|
||||||
|
connect(profiler, SIGNAL(finished(int)), profiler, SLOT(deleteLater()));
|
||||||
|
profiler->start();
|
||||||
|
QMessageBox::information(0, tr("JProfiler"),
|
||||||
|
tr("JProfiler started and listening on port %1").arg(port));
|
||||||
|
}
|
||||||
|
|
||||||
|
void JProfilerFactory::registerSettings(SettingsObject *settings)
|
||||||
|
{
|
||||||
|
settings->registerSetting("JProfilerPath");
|
||||||
|
settings->registerSetting("JProfilerPort", 42042);
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseProfiler *JProfilerFactory::createProfiler(OneSixInstance *instance, QObject *parent)
|
||||||
|
{
|
||||||
|
return new JProfiler(instance, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JProfilerFactory::check(const QString &path, QString *error)
|
||||||
|
{
|
||||||
|
QDir dir(path);
|
||||||
|
if (!dir.exists())
|
||||||
|
{
|
||||||
|
*error = QObject::tr("Path does not exist");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!dir.exists("bin") || !dir.exists("bin/jprofiler") || !dir.exists("bin/agent.jar"))
|
||||||
|
{
|
||||||
|
*error = QObject::tr("Invalid JProfiler install");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
21
logic/profiler/JProfiler.h
Normal file
21
logic/profiler/JProfiler.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "BaseProfiler.h"
|
||||||
|
|
||||||
|
class JProfiler : public BaseProfiler
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
JProfiler(OneSixInstance *instance, QObject *parent = 0);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void beginProfilingImpl(MinecraftProcess *process);
|
||||||
|
};
|
||||||
|
|
||||||
|
class JProfilerFactory : public BaseProfilerFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void registerSettings(SettingsObject *settings) override;
|
||||||
|
BaseProfiler *createProfiler(OneSixInstance *instance, QObject *parent = 0) override;
|
||||||
|
bool check(const QString &path, QString *error) override;
|
||||||
|
};
|
46
logic/profiler/JVisualVM.cpp
Normal file
46
logic/profiler/JVisualVM.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include "JVisualVM.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
|
||||||
|
#include "settingsobject.h"
|
||||||
|
#include "logic/MinecraftProcess.h"
|
||||||
|
#include "logic/OneSixInstance.h"
|
||||||
|
|
||||||
|
JVisualVM::JVisualVM(OneSixInstance *instance, QObject *parent) : BaseProfiler(instance, parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void JVisualVM::beginProfilingImpl(MinecraftProcess *process)
|
||||||
|
{
|
||||||
|
QProcess *profiler = new QProcess(this);
|
||||||
|
profiler->setArguments(QStringList() << "--jdkhome"
|
||||||
|
<< m_instance->settings().get("JavaPath").toString()
|
||||||
|
<< "--openpid" << QString::number(process->pid()));
|
||||||
|
profiler->setProgram("jvisualvm");
|
||||||
|
connect(profiler, &QProcess::started, [this]()
|
||||||
|
{ emit readyToLaunch(tr("JVisualVM started")); });
|
||||||
|
connect(profiler, SIGNAL(finished(int)), profiler, SLOT(deleteLater()));
|
||||||
|
profiler->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JVisualVMFactory::registerSettings(SettingsObject *settings)
|
||||||
|
{
|
||||||
|
settings->registerSetting("JVisualVMPath");
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseProfiler *JVisualVMFactory::createProfiler(OneSixInstance *instance, QObject *parent)
|
||||||
|
{
|
||||||
|
return new JVisualVM(instance, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JVisualVMFactory::check(const QString &path, QString *error)
|
||||||
|
{
|
||||||
|
QString resolved = QStandardPaths::findExecutable(path);
|
||||||
|
if (resolved.isEmpty() && !QDir::isAbsolutePath(path))
|
||||||
|
{
|
||||||
|
*error = QObject::tr("Invalid path to JVisualVM");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
21
logic/profiler/JVisualVM.h
Normal file
21
logic/profiler/JVisualVM.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "BaseProfiler.h"
|
||||||
|
|
||||||
|
class JVisualVM : public BaseProfiler
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
JVisualVM(OneSixInstance *instance, QObject *parent = 0);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void beginProfilingImpl(MinecraftProcess *process);
|
||||||
|
};
|
||||||
|
|
||||||
|
class JVisualVMFactory : public BaseProfilerFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void registerSettings(SettingsObject *settings) override;
|
||||||
|
BaseProfiler *createProfiler(OneSixInstance *instance, QObject *parent = 0) override;
|
||||||
|
bool check(const QString &path, QString *error) override;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user