Profiler support. Currently JProfiler and JVisualVM are implemented.

This commit is contained in:
Jan Dalheimer
2014-02-15 14:19:35 +01:00
parent 5cf599673d
commit efa8e26a3f
16 changed files with 505 additions and 17 deletions

View File

@ -33,6 +33,7 @@
#include <QLabel>
#include <QToolButton>
#include <QWidgetAction>
#include <QProgressDialog>
#include "osutils.h"
#include "userutils.h"
@ -97,6 +98,9 @@
#include <logic/updater/NotificationChecker.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)
{
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)
return;
@ -1194,11 +1198,11 @@ void MainWindow::doLaunch(bool online)
// update first if the server actually responded
if (session->auth_server_online)
{
updateInstance(m_selectedInstance, session);
updateInstance(m_selectedInstance, session, profile);
}
else
{
launchInstance(m_selectedInstance, session);
launchInstance(m_selectedInstance, session, profile);
}
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();
if (!updateTask)
{
launchInstance(instance, session);
launchInstance(instance, session, profile);
return;
}
ProgressDialog tDialog(this);
connect(updateTask.get(), &Task::succeeded, [this, instance, session]
{ launchInstance(instance, session); });
connect(updateTask.get(), &Task::succeeded, [this, instance, session, profile]
{ launchInstance(instance, session, profile); });
connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString)));
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(session.get() != nullptr, "launchInstance", "session is NULL");
@ -1237,6 +1241,33 @@ void MainWindow::launchInstance(BaseInstance *instance, AuthSessionPtr session)
proc->setLogin(session);
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)
@ -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()
{
this->show();

View File

@ -107,22 +107,24 @@ slots:
void on_actionEditInstNotes_triggered();
void on_actionProfileInstance_triggered();
/*!
* Launches the currently selected instance with the default 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.
* 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.
*/
void updateInstance(BaseInstance *instance, AuthSessionPtr account);
void updateInstance(BaseInstance *instance, AuthSessionPtr account, bool profile = false);
void onGameUpdateError(QString error);

View File

@ -108,6 +108,7 @@
<addaction name="actionChangeInstIcon"/>
<addaction name="actionLaunchInstance"/>
<addaction name="actionLaunchInstanceOffline"/>
<addaction name="actionProfileInstance"/>
<addaction name="separator"/>
<addaction name="actionEditInstNotes"/>
<addaction name="actionChangeInstGroup"/>
@ -528,12 +529,19 @@
<string>Launch the selected instance.</string>
</property>
</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>
<layoutdefault spacing="6" margin="11"/>
<resources>
<include location="../resources/instances/instances.qrc"/>
<include location="../resources/multimc/multimc.qrc"/>
<include location="../resources/backgrounds/backgrounds.qrc"/>
<include location="../resources/instances/instances.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -29,6 +29,8 @@
#include "logic/updater/UpdateChecker.h"
#include "logic/profiler/BaseProfiler.h"
#include <settingsobject.h>
#include <pathutils.h>
#include <QFileDialog>
@ -368,6 +370,22 @@ void SettingsDialog::applySettings(SettingsObject *s)
}
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)
@ -447,6 +465,23 @@ void SettingsDialog::loadSettings(SettingsObject *s)
// Custom Commands
ui->preLaunchCmdTextBox->setText(s->get("PreLaunchCommand").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()
@ -503,3 +538,53 @@ void SettingsDialog::checkFinished(JavaCheckResult result)
"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));
}
}
}

View File

@ -75,6 +75,11 @@ slots:
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.
*/

View File

@ -863,6 +863,116 @@
</item>
</layout>
</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>
</item>
<item>
@ -938,7 +1048,7 @@
</connection>
</connections>
<buttongroups>
<buttongroup name="proxyGroup"/>
<buttongroup name="sortingModeGroup"/>
<buttongroup name="proxyGroup"/>
</buttongroups>
</ui>