Skip to content

Commit

Permalink
add gui to configure ssh
Browse files Browse the repository at this point in the history
  • Loading branch information
lievenhey committed Feb 3, 2022
1 parent ed17d32 commit a52b519
Show file tree
Hide file tree
Showing 11 changed files with 339 additions and 57 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ set(hotspot_SRCS
perfoutputwidgettext.cpp
perfoutputwidgetkonsole.cpp
costcontextmenu.cpp
ssh.cpp

# ui files:
mainwindow.ui
Expand Down
5 changes: 5 additions & 0 deletions src/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ MainWindow::MainWindow(QWidget* parent)
settings->setObjdump(m_settingsDialog->objdump());
});

connect(m_settingsDialog, &QDialog::accepted, m_recordPage, &RecordPage::onRemoteDevicesChanged);

connect(settings, &Settings::sysrootChanged, m_resultsPage, &ResultsPage::setSysroot);
connect(settings, &Settings::appPathChanged, m_resultsPage, &ResultsPage::setAppPath);
connect(settings, &Settings::objdumpChanged, m_resultsPage, &ResultsPage::setObjdump);
Expand Down Expand Up @@ -227,6 +229,9 @@ MainWindow::MainWindow(QWidget* parent)
settings->setDebuginfodUrls(m_config->group("debuginfod").readEntry("urls", QStringList()));
connect(Settings::instance(), &Settings::debuginfodUrlsChanged, this,
[this, settings] { m_config->group("debuginfod").writeEntry("urls", settings->debuginfodUrls()); });

const auto askpass = QStandardPaths::findExecutable(QLatin1String("ksshaskpass"));
settings->setSshaskpassPath(m_config->group("SSH").readEntry("sshaskpass", askpass));
}

auto* prettifySymbolsAction = ui->viewMenu->addAction(tr("Prettify Symbols"));
Expand Down
67 changes: 23 additions & 44 deletions src/perfrecordssh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,51 +16,29 @@
#include <csignal>

#include "hotspot-config.h"

QString sshOutput(const QString& hostname, const QStringList& command)
{
QProcess ssh;
ssh.setProgram(QStandardPaths::findExecutable(QLatin1String("ssh")));
const auto arguments = QStringList({hostname}) + command;
ssh.setArguments(arguments);
ssh.start();
ssh.waitForFinished();
return QString::fromUtf8(ssh.readAll());
}

int sshExitCode(const QString& hostname, const QStringList& command)
{
QProcess ssh;
ssh.setProgram(QStandardPaths::findExecutable(QLatin1String("ssh")));
const auto arguments = QStringList({hostname}) + command;
ssh.setArguments(arguments);
ssh.start();
ssh.waitForFinished();
return ssh.exitCode();
}
#include "ssh.h"

PerfRecordSSH::PerfRecordSSH(QObject* parent)
: PerfRecord(parent)
{
m_hostname = QStringLiteral("user@localhost");
}

PerfRecordSSH::~PerfRecordSSH() = default;

void PerfRecordSSH::record(const QStringList& perfOptions, const QString& outputPath, bool /*elevatePrivileges*/,
const QString& exePath, const QStringList& exeOptions, const QString& workingDirectory)
{
int exitCode = sshExitCode(m_hostname, {QLatin1String("test"), QLatin1String("-e"), exePath});
int exitCode = sshExitCode(m_deviceName, {QLatin1String("test"), QLatin1String("-e"), exePath});
if (exitCode) {
emit recordingFailed(tr("File '%1' does not exist.").arg(exePath));
}

exitCode = sshExitCode(m_hostname, {QLatin1String("test"), QLatin1String("-f"), exePath});
exitCode = sshExitCode(m_deviceName, {QLatin1String("test"), QLatin1String("-f"), exePath});
if (exitCode) {
emit recordingFailed(tr("'%1' is not a file.").arg(exePath));
}

exitCode = sshExitCode(m_hostname, {QLatin1String("test"), QLatin1String("-x"), exePath});
exitCode = sshExitCode(m_deviceName, {QLatin1String("test"), QLatin1String("-x"), exePath});
if (exitCode) {
emit recordingFailed(tr("File '%1' is not executable.").arg(exePath));
}
Expand Down Expand Up @@ -110,32 +88,32 @@ void PerfRecordSSH::sendInput(const QByteArray& input)

QString PerfRecordSSH::currentUsername()
{
if (m_hostname.isEmpty())
if (m_deviceName.isEmpty())
return {};
return sshOutput(m_hostname, {QLatin1String("echo"), QLatin1String("$USERNAME")}).simplified();
return sshOutput(m_deviceName, {QLatin1String("echo"), QLatin1String("$USERNAME")}).simplified();
}

bool PerfRecordSSH::canTrace(const QString& path)
{
if (m_hostname.isEmpty())
if (m_deviceName.isEmpty())
return false;

// exit code == 0 -> true
bool isDir = sshExitCode(m_hostname, {QLatin1String("test"), QLatin1String("-d"), path}) == 0;
bool isReadable = sshExitCode(m_hostname, {QLatin1String("test"), QLatin1String("-r"), path}) == 0;
bool isDir = sshExitCode(m_deviceName, {QLatin1String("test"), QLatin1String("-d"), path}) == 0;
bool isReadable = sshExitCode(m_deviceName, {QLatin1String("test"), QLatin1String("-r"), path}) == 0;

if (!isDir || !isReadable) {
return false;
}

QString paranoid =
sshOutput(m_hostname, {QLatin1String("cat"), QLatin1String("/proc/sys/kernel/perf_event_paranoid")});
sshOutput(m_deviceName, {QLatin1String("cat"), QLatin1String("/proc/sys/kernel/perf_event_paranoid")});
return paranoid.trimmed() == QLatin1String("-1");
}

bool PerfRecordSSH::canProfileOffCpu()
{
if (m_hostname.isEmpty())
if (m_deviceName.isEmpty())
return false;
return canTrace(QStringLiteral("events/sched/sched_switch"));
}
Expand Down Expand Up @@ -166,16 +144,16 @@ static QString perfBuildOptions(const QString& hostname)

bool PerfRecordSSH::canSampleCpu()
{
if (m_hostname.isEmpty())
if (m_deviceName.isEmpty())
return false;
return perfRecordHelp(m_hostname).contains(QLatin1String("--sample-cpu"));
return perfRecordHelp(m_deviceName).contains(QLatin1String("--sample-cpu"));
}

bool PerfRecordSSH::canSwitchEvents()
{
if (m_hostname.isEmpty())
if (m_deviceName.isEmpty())
return false;
return perfRecordHelp(m_hostname).contains(QLatin1String("--switch-events"));
return perfRecordHelp(m_deviceName).contains(QLatin1String("--switch-events"));
}

bool PerfRecordSSH::canUseAio()
Expand All @@ -186,16 +164,16 @@ bool PerfRecordSSH::canUseAio()

bool PerfRecordSSH::canCompress()
{
if (m_hostname.isEmpty())
if (m_deviceName.isEmpty())
return false;
return Zstd_FOUND && perfBuildOptions(m_hostname).contains(QLatin1String("zstd: [ on ]"));
return Zstd_FOUND && perfBuildOptions(m_deviceName).contains(QLatin1String("zstd: [ on ]"));
}

bool PerfRecordSSH::isPerfInstalled()
{
if (m_hostname.isEmpty())
if (m_deviceName.isEmpty())
return false;
return sshExitCode(m_hostname, {QLatin1String("perf")}) != 127;
return sshExitCode(m_deviceName, {QLatin1String("perf")}) != 127;
}

void PerfRecordSSH::startRecording(const QStringList& perfOptions, const QString& outputPath,
Expand Down Expand Up @@ -230,12 +208,13 @@ void PerfRecordSSH::startRecording(const QStringList& perfOptions, const QString

m_recordProcess = new QProcess(this);
m_recordProcess->setProgram(QStandardPaths::findExecutable(QLatin1String("ssh")));
m_recordProcess->setArguments({m_hostname, QLatin1String("perf ") + perfCommand.join(QLatin1Char(' '))});
const auto arguments =
assembleSSHArguments(m_deviceName, {QLatin1String("perf ") + perfCommand.join(QLatin1Char(' '))});
m_recordProcess->setArguments(arguments);
m_recordProcess->setProcessEnvironment(sshEnvironment());
m_recordProcess->start();
m_recordProcess->waitForStarted();

qDebug() << m_recordProcess->arguments().join(QLatin1Char(' '));

emit recordingStarted(QLatin1String("perf"), perfCommand);

connect(m_recordProcess, &QProcess::readyReadStandardOutput, this,
Expand Down
7 changes: 6 additions & 1 deletion src/perfrecordssh.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ class PerfRecordSSH : public PerfRecord
PerfRecordSSH(QObject* parent = nullptr);
~PerfRecordSSH();

void setDeviceName(const QString& device)
{
m_deviceName = device;
}

void record(const QStringList& perfOptions, const QString& outputPath, bool elevatePrivileges,
const QString& exePath, const QStringList& exeOptions, const QString& workingDirectory) override;
void record(const QStringList& perfOptions, const QString& outputPath, bool elevatePrivileges,
Expand Down Expand Up @@ -50,6 +55,6 @@ class PerfRecordSSH : public PerfRecord

QProcess* m_recordProcess = nullptr;
QFile* m_outputFile;
QString m_hostname;
QString m_deviceName;
bool m_userTerminated = false;
};
25 changes: 19 additions & 6 deletions src/recordpage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,20 +407,19 @@ RecordPage::RecordPage(QWidget* parent)

perfRecordChanged();

ui->remoteTargetComboBox->addItem(QStringLiteral("localhost"));
ui->remoteTargetComboBox->addItem(QStringLiteral("remote test 1"));
const auto sshPath = QStandardPaths::findExecutable(QLatin1String("ssh"));
ui->remoteTargetGroup->setVisible(!sshPath.isEmpty());

onRemoteDevicesChanged();

connect(ui->remoteTargetComboBox, qOverload<int>(&QComboBox::currentIndexChanged), this,
[this, perfRecordChanged](int index) {
if (index == 0) {
m_perfRecord = new PerfRecord(this);
qDebug() << "PerfRecord";
} else {
auto recordSsh = new PerfRecordSSH(this);
// TODO: this
// recordSsh->setHostname();
recordSsh->setDeviceName(ui->remoteTargetComboBox->currentText());
m_perfRecord = recordSsh;
qDebug() << "PerfRecordSSH";
}
perfRecordChanged();
});
Expand Down Expand Up @@ -824,3 +823,17 @@ void RecordPage::updateOffCpuCheckboxState()
ui->offCpuCheckBox->setChecked(config().readEntry(QStringLiteral("offCpuProfiling"), false));
}
}

void RecordPage::onRemoteDevicesChanged()
{
ui->remoteTargetComboBox->clear();
ui->remoteTargetComboBox->addItem(QStringLiteral("localhost"));

const auto deviceConfig = KSharedConfig::openConfig()->group("devices");
auto t = deviceConfig.groupList();
for (const auto& device : deviceConfig.groupList()) {
if (deviceConfig.hasGroup(device)) {
ui->remoteTargetComboBox->addItem(device);
}
}
}
3 changes: 3 additions & 0 deletions src/recordpage.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ class RecordPage : public QWidget
void homeButtonClicked();
void openFile(QString filePath);

public slots:
void onRemoteDevicesChanged();

private slots:
void onApplicationNameChanged(const QString& filePath);
void onStartRecordingButtonClicked(bool checked);
Expand Down
6 changes: 6 additions & 0 deletions src/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,9 @@ void Settings::setCallgraphColors(const QColor& active, const QColor& inactive)
emit callgraphChanged();
}
}

void Settings::setSshaskpassPath(const QString& sshaskpath)
{
m_sshaskpassPath = sshaskpath;
emit sshaskpassChanged(m_sshaskpassPath);
}
8 changes: 8 additions & 0 deletions src/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ class Settings : public QObject
return m_callgraphColor;
}

QString sshaskpassPath() const
{
return m_sshaskpassPath;
}

signals:
void prettifySymbolsChanged(bool);
void collapseTemplatesChanged(bool);
Expand All @@ -134,6 +139,7 @@ class Settings : public QObject
void archChanged(const QString& arch);
void objdumpChanged(const QString& objdump);
void callgraphChanged();
void sshaskpassChanged(const QString& path);

public slots:
void setPrettifySymbols(bool prettifySymbols);
Expand All @@ -152,6 +158,7 @@ public slots:
void setCallgraphParentDepth(int parent);
void setCallgraphChildDepth(int child);
void setCallgraphColors(const QColor& active, const QColor& inactive);
void setSshaskpassPath(const QString& sshaskpath);

private:
Settings() = default;
Expand All @@ -172,6 +179,7 @@ public slots:
QString m_appPath;
QString m_arch;
QString m_objdump;
QString m_sshaskpassPath;

int m_callgraphParentDepth = 3;
int m_callgraphChildDepth = 2;
Expand Down
Loading

0 comments on commit a52b519

Please sign in to comment.