PerfProfiler: Add error handling to PerfDataReader

If we fail to write to the buffer files or the perfparser process we
should report a failure.

Change-Id: Ib9fc29ff2609d915320371aa73a52128e7861fa8
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Ulf Hermann
2019-01-07 14:30:39 +01:00
parent dec9b7eb04
commit 4c6a497c89
3 changed files with 43 additions and 41 deletions

View File

@@ -318,18 +318,28 @@ QStringList PerfDataReader::collectArguments(const QString &executableDirPath,
return arguments;
}
static bool checkedWrite(QIODevice *device, const QByteArray &input)
{
qint64 written = 0;
const qint64 size = input.size();
while (written < size) {
const qint64 bytes = device->write(input.constData() + written, size - written);
if (bytes < 0)
return false;
written += bytes;
}
return true;
}
void PerfDataReader::writeChunk()
{
if (!m_buffer.isEmpty()) {
if (m_input.bytesToWrite() < s_maxBufferSize) {
QScopedPointer<TempFile> file(m_buffer.takeFirst());
std::unique_ptr<Utils::TemporaryFile> file(m_buffer.takeFirst());
file->reset();
const QByteArray data(file->readAll());
for (qint64 i = 0, end = data.length(); i < end;) {
const qint64 written = m_input.write(data.constData() + i, end - i);
if (written >= 0) {
i += written;
} else {
if (!checkedWrite(&m_input, data)) {
m_input.disconnect();
m_input.kill();
emit finished();
@@ -339,7 +349,6 @@ void PerfDataReader::writeChunk()
"Your trace is incomplete."));
}
}
}
} else if (m_dataFinished) {
m_input.closeWriteChannel();
}
@@ -360,25 +369,23 @@ void PerfDataReader::clear()
PerfProfilerTraceFile::clear();
}
void PerfDataReader::feedParser(const QByteArray &input)
bool PerfDataReader::feedParser(const QByteArray &input)
{
if (m_buffer.isEmpty()) {
if (m_input.isOpen() && m_input.bytesToWrite() < s_maxBufferSize) {
m_input.write(input);
return;
}
TempFile *file = new TempFile;
m_buffer.append(file);
connect(file, &QIODevice::bytesWritten, this, &PerfDataReader::writeChunk);
file->write(input);
} else {
TempFile *file = m_buffer.last();
if (file->pos() > s_maxBufferSize) {
file = new TempFile;
m_buffer.append(file);
}
file->write(input);
if (!m_buffer.isEmpty()) {
auto *file = m_buffer.last();
if (file->pos() < s_maxBufferSize)
return checkedWrite(file, input);
} else if (m_input.isOpen() && m_input.bytesToWrite() < s_maxBufferSize) {
return checkedWrite(&m_input, input);
}
auto file = std::make_unique<Utils::TemporaryFile>("perfdatareader");
connect(file.get(), &QIODevice::bytesWritten, this, &PerfDataReader::writeChunk);
if (!file->open() || !checkedWrite(file.get(), input))
return false;
m_buffer.append(file.release());
return true;
}
QStringList PerfDataReader::findTargetArguments(const ProjectExplorer::RunConfiguration *rc) const

View File

@@ -54,7 +54,7 @@ public:
QStringList findTargetArguments(const ProjectExplorer::RunConfiguration *rc) const;
void clear();
void feedParser(const QByteArray &input);
bool feedParser(const QByteArray &input);
// Trigger after delay has passed
void triggerRecordingStateChange(bool recording);
@@ -81,12 +81,6 @@ protected:
private:
static const int s_maxBufferSize = 1 << 29;
class TempFile : public Utils::TemporaryFile
{
public:
TempFile() : Utils::TemporaryFile("perfdatareader") { open(); }
};
QStringList collectArguments(const QString &executableDirPath,
const ProjectExplorer::Kit *kit) const;
void writeChunk();
@@ -94,7 +88,7 @@ private:
bool m_recording;
bool m_dataFinished;
QProcess m_input;
QQueue<TempFile *> m_buffer;
QQueue<Utils::TemporaryFile *> m_buffer;
qint64 m_localProcessStart;
qint64 m_localRecordingEnd;
qint64 m_localRecordingStart;

View File

@@ -225,8 +225,9 @@ void PerfProfilerRunner::start()
appendMessage(QString::fromLocal8Bit(recorder->readAllStandardError()),
Utils::StdErrFormat);
});
connect(recorder, &DeviceProcess::readyReadStandardOutput, this, [reader, recorder] {
reader->feedParser(recorder->readAllStandardOutput());
connect(recorder, &DeviceProcess::readyReadStandardOutput, this, [this, reader, recorder] {
if (!reader->feedParser(recorder->readAllStandardOutput()))
reportFailure(tr("Failed to transfer perf data to perfparser"));
});
}