forked from qt-creator/qt-creator
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:
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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"));
|
||||
});
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user