Commit e56118cc authored by Eike Ziller's avatar Eike Ziller
Browse files

Merge remote-tracking branch 'origin/3.4'


Change-Id: I316199fe0a257cb085668ccb183b1590555278f2
parents 97631c25 fd0b3839
** Copyright (C) 2015 The Qt Company Ltd.
** Contact:
** This file is part of Qt Creator
** GNU Free Documentation License
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of this
** file.
// **********************************************************************
// NOTE: the sections are not ordered by their logical order to avoid
// reshuffling the file each time the index order changes (i.e., often).
// Run the script to adjust the links to the index order.
// **********************************************************************
\contentspage {Qt Creator Manual}
\previouspage creator-clang-static-analyzer.html
\page creator-cpu-usage-analyzer.html
\nextpage creator-advanced.html
\title Analyzing CPU Usage
\QC is integrated with the Linux Perf tool (commercial only) that can be
used to analyze the CPU usage of an application on embedded devices and, to
a limited extent, on Linux desktop platforms. The CPU Usage Analyzer uses
the Perf tool bundled with the Linux kernel to take periodic snapshots of
the call chain of an application and visualizes them in a timeline view.
\section1 Using the CPU Usage Analyzer
The CPU Usage Analyzer needs to be able to locate debug symbols for the
binaries involved. For debug builds, debug symbols are always generated.
Edit the project build settings to generate debug symbols also for release
To use the CPU Usage Analyzer:
\list 1
\li To generate debug symbols also for applications compiled in release
mode, select \uicontrol {Projects}, and then select
\uicontrol Details next to \uicontrol {Build Steps} to view the
build steps.
\li Select the \uicontrol {Generate separate debug info} check box, and
then select \uicontrol Yes to recompile the project.
\li Select \uicontrol {Analyze > CPU Usage Analyzer} to profile the
current application.
\li Select the
\inlineimage qtcreator-analyze-start-button.png
(\uicontrol Start) button to start the application from the
CPU Usage Analyzer.
\note If data collection does not start automatically, select the
\inlineimage qtcreator-analyzer-button.png
(\uicontrol {Collect profile data}) button.
When you start analyzing an application, the application is launched, and
the CPU Usage Analyzer immediately begins to collect data. This is indicated
by the time running in the \uicontrol Recorded field. However, as the data
is passed through the Perf tool and an extra helper program bundled with
\QC, and both buffer and process it on the fly, data may arrive in \QC
several seconds after it was generated. An estimate for this delay is given
in the \uicontrol {Processing delay} field.
Data is collected until you select the
\uicontrol {Stop collecting profile data} button or terminate the
Select the \uicontrol {Stop collecting profile data} button to disable the
automatic start of the data collection when an application is launched.
Profile data will still be generated, but \QC will discard it until you
select the button again.
\section1 Specifying CPU Usage Analyzer Settings
To specify global settings for the CPU Usage Analyzer, select
\uicontrol Tools > \uicontrol Options > \uicontrol Analyzer >
\uicontrol {CPU Usage Analyzer}. For each run configuration, you can also
use specialized settings. Select \uicontrol Projects > \uicontrol Run, and
then select \uicontrol Details next to
\uicontrol {CPU Usage Analyzer Settings}.
\section2 Selecting Call Graph Mode
Select the command to invoke Perf in the \uicontrol {Call graph mode} field.
The \uicontrol {Frame Pointer}, or \c fp, mode relies on frame pointers
being available in the profiled application.
The \uicontrol {Dwarf} mode works also without frame pointers, but
generates significantly more data. Qt and most system libraries are
compiled without frame pointers by default, so the frame pointer mode is
only useful with customized systems.
\section2 Setting Stack Snapshot Size
In the dwarf mode, Perf takes periodic snapshots of the application stack,
which are then analyzed and \e unwound by the CPU Usage Analyzer. Set the
size of the stack snapshots in the \uicontrol {Stack snapshot size} field.
Large stack snapshots result in a larger volume of data to be transferred
and processed. Small stack snapshots may fail to capture call chains of
highly recursive applications or other intense stack usage.
\section2 Setting Sampling Frequency
Set the sampling frequency for Perf in the \uicontrol {Sampling frequency}
field. High sampling frequencies result in more accurate data, at the
expense of a higher overhead and a larger volume of profiling data being
generated. The actual sampling frequency is determined by the Linux kernel
on the target device, which takes the frequency set for Perf merely as
advice. There may be a significant difference between the sampling frequency
you request and the actual result.
In general, if you configure the CPU Usage Analyzer to collect more data
than it can transmit over the connection between the target and the host
device, the application may get blocked while Perf is trying to send the
data, and the processing delay may grow excessively. You should then lower
the \uicontrol {Sampling frequency} or the \uicontrol {Stack snapshot size}.
\section1 Analyzing Collected Data
The \uicontrol Timeline view displays a graphical representation of CPU
usage per thread and a condensed view of all recorded events.
\image cpu-usage-analyzer.png "CPU Usage Analyzer"
Each category in the timeline describes a thread in the application. Move
the cursor on an event (6) on a row to see how long it takes and which
function in the source it represents. To display the information only when
an event is selected, disable the
\uicontrol {View Event Information on Mouseover} button (5).
The outline (10) summarizes the period for which data was collected. Drag
the zoom range (8) or click the outline to move on the outline. You can
also move between events by selecting the
\uicontrol {Jump to Previous Event} (1) and \uicontrol {Jump to Next Event}
(2) buttons.
Select the \uicontrol {Show Zoom Slider} button (3) to open a slider that
you can use to set the zoom level. You can also drag the zoom handles (9).
To reset the default zoom level, right-click the timeline to open the
context menu, and select \uicontrol {Reset Zoom}.
\section2 Selecting Event Ranges
You can select an event range (7) to view the time it represents or to zoom
into a specific region of the trace. Select the \uicontrol {Select Range}
button (4) to activate the selection tool. Then click in the timeline to
specify the beginning of the event range. Drag the selection handle to
define the end of the range.
You can use event ranges also to measure delays between two subsequent
events. Place a range between the end of the first event and the beginning
of the second event. The \uicontrol Duration field displays the delay
between the events in milliseconds.
To zoom into an event range, double-click it.
To remove an event range, close the \uicontrol Selection dialog.
\section2 Understanding the Data
Generally, events in the timeline view indicate how long a function call
took. Move the mouse over them to see details. The details always include
the address of the function, the approximate duration of the call, the ELF
file the function resides in, the number of samples collected with this
function call active, the total number of times this function was
encountered in the thread, and the number of samples this function was
encountered in at least once.
For functions with debug information available, the details include the
location in source code and the name of the function. You can click on such
events to move the cursor in the code editor to the part of the code the
event is associated with.
As the Perf tool only provides periodic samples, the CPU Usage Analyzer
cannot determine the exact time when a function was called or when it
returned. You can, however, see exactly when a sample was taken on the
second row of each thread. The CPU Usage Analyzer assumes that if the same
function is present in the same place in the call chain in multiple samples
on a row, then this represents a single call to the respective function.
This is, of course, a simplification. Also, there may be other functions
being called between the samples taken, which do not show up in the profile
data. However, statistically, the data is likely to show the functions that
spend the most CPU time most prominently.
If a function without debug information is encountered, further unwinding
of the stack may fail. Unwinding will also fail if a QML or JavaScript
function is encountered, and for some symbols implemented in assembler. If
unwinding fails, only part of the call chain is displayed, and the
surrounding functions may seem to be interrupted. This does not necessarily
mean they were actually interrupted during the execution of the
application, but only that they could not be found in the stacks where the
unwinding failed.
Kernel functions included in call chains are shown on the third row of each
thread. All kernel functions are summarized and not differentiated any
further, because most of the time kernel symbols cannot be resolved when the
data is analyzed.
The coloring of the events represents the actual sample rate for the
specific thread they belong to, across their duration. The Linux kernel
will only take a sample of a thread if the thread is active. At the same
time, the kernel tries to maintain a constant overall sampling frequency.
Thus, differences in the sampling frequency between different threads
indicate that the thread with more samples taken is more likely to be the
overall bottleneck, and the thread with less samples taken has likely spent
time waiting for external events such as I/O or a mutex.
\section1 Loading Perf Data Files
You can load any \c files generated by recent versions of the
Linux Perf tool and view them in \QC. Select \uicontrol Analyze >
\uicontrol {Load Trace} to load a file. The CPU Usage Analyzer needs to know
the context in which the data was recorded to find the debug symbols.
Therefore, you have to specify the kit that the application was built with
and the folder where the application executable is located.
The Perf data files are generated by calling \c {perf record}. Make sure to
generate call graphs when recording data by starting Perf with the
\c {--call-graph} option. Also check that the necessary debug symbols are
available to the CPU Usage Analyzer, either at a standard location
(\c /usr/lib/debug or next to the binaries), or as part of the Qt package
you are using.
The CPU Usage Analyzer can read Perf data files generated in either frame
pointer or dwarf mode. However, to generate the files correctly, numerous
preconditions have to be met. All system images for the
{Qt for Device Creation reference devices}, except for Freescale iMX53 Quick
Start Board and SILICA Architect Tibidabo, are correctly set up for
profiling in the dwarf mode. For other devices, check whether Perf can read
back its own data in a sensible way by checking the output of
\c {perf report} or \c {perf script} in the recorded Perf data files.
......@@ -66,6 +66,12 @@
integrates the Clang Static Analyzer source code analysis tool
(commercial only).
\li \l{Analyzing CPU Usage}{CPU Usage Analyzer}
You can analyze the CPU usage of embedded applications and Linux
desktop applications with the CPU Usage Analyzer (commercial only)
that integrates the Linux Perf tool.
......@@ -27,7 +27,7 @@
\contentspage {Qt Creator Manual}
\previouspage creator-running-valgrind-remotely.html
\page creator-clang-static-analyzer.html
\nextpage creator-advanced.html
\nextpage creator-cpu-usage-analyzer.html
\title Using Clang Static Analyzer
......@@ -24,7 +24,7 @@
\contentspage {Qt Creator Manual}
\previouspage creator-clang-static-analyzer.html
\previouspage creator-cpu-usage-analyzer.html
\page creator-advanced.html
\nextpage creator-os-supported-platforms.html
......@@ -41,6 +41,7 @@
\li Memory usage
\li Input events
\li \l{Analyzing CPU Usage}{CPU Usage Analyzer}
\li \l{}{Qt Quick Compiler}
\li \l{Using Qt Quick Designer Extensions}
......@@ -268,6 +268,7 @@
\li \l{Running Valgrind Tools on External Applications}
\li \l{Using Clang Static Analyzer}
\li \l{Analyzing CPU Usage}
......@@ -705,8 +705,8 @@ void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding
foreach (ClassOrNamespace *u, binding->usings())
lookup_helper(name, u, result, processed, binding->_templateId);
Anonymouses::const_iterator cit = binding->_anonymouses.begin();
Anonymouses::const_iterator citEnd = binding->_anonymouses.end();
Anonymouses::const_iterator cit = binding->_anonymouses.constBegin();
Anonymouses::const_iterator citEnd = binding->_anonymouses.constEnd();
for (; cit != citEnd; ++cit) {
const AnonymousNameId *anonymousNameId = cit.key();
ClassOrNamespace *a = cit.value();
......@@ -802,8 +802,8 @@ ClassOrNamespace *ClassOrNamespace::lookupType(const Name *name, Block *block)
QHash<Block *, ClassOrNamespace *>::const_iterator citBlock = _blocks.find(block);
if (citBlock != _blocks.end()) {
QHash<Block *, ClassOrNamespace *>::const_iterator citBlock = _blocks.constFind(block);
if (citBlock != _blocks.constEnd()) {
ClassOrNamespace *nestedBlock = citBlock.value();
QSet<ClassOrNamespace *> processed;
if (ClassOrNamespace *foundInNestedBlock
......@@ -815,7 +815,7 @@ ClassOrNamespace *ClassOrNamespace::lookupType(const Name *name, Block *block)
for (citBlock = _blocks.begin(); citBlock != _blocks.end(); ++citBlock) {
for (citBlock = _blocks.constBegin(); citBlock != _blocks.constEnd(); ++citBlock) {
if (ClassOrNamespace *foundNestedBlock = citBlock.value()->lookupType(name, block))
return foundNestedBlock;
......@@ -1027,8 +1027,8 @@ ClassOrNamespace *ClassOrNamespace::findOrCreateNestedAnonymousType(
const AnonymousNameId *anonymousNameId)
QHash<const AnonymousNameId *, ClassOrNamespace *>::const_iterator cit
= _anonymouses.find(anonymousNameId);
if (cit != _anonymouses.end()) {
= _anonymouses.constFind(anonymousNameId);
if (cit != _anonymouses.constEnd()) {
return cit.value();
} else {
ClassOrNamespace *newAnonymous = _factory->allocClassOrNamespace(this);
......@@ -1083,8 +1083,8 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
} else {
QMap<const TemplateNameId *, ClassOrNamespace *>::const_iterator citInstantiation
= reference->_instantiations.find(templId);
if (citInstantiation != reference->_instantiations.end())
= reference->_instantiations.constFind(templId);
if (citInstantiation != reference->_instantiations.constEnd())
return citInstantiation.value();
TemplateNameId *nonConstTemplId = const_cast<TemplateNameId *>(templId);
// make this instantiation looks like specialization which help to find
......@@ -1589,8 +1589,8 @@ void PluginManagerPrivate::profilingSummary() const
total += it1.value();
Sorter::ConstIterator it2 = sorter.begin();
Sorter::ConstIterator et2 = sorter.end();
Sorter::ConstIterator it2 = sorter.constBegin();
Sorter::ConstIterator et2 = sorter.constEnd();
for (; it2 != et2; ++it2)
qDebug("%-22s %8dms ( %5.2f%% )", qPrintable(it2.value()->name()),
it2.key(), 100.0 * it2.key() / total);
......@@ -83,6 +83,8 @@ enum Columns { NameColumn, LoadedColumn, VersionColumn, VendorColumn, };
enum IconIndex { OkIcon, ErrorIcon, NotLoadedIcon };
static const int SortRole = Qt::UserRole + 1;
static const QIcon &icon(int num)
static QIcon icons[] = {
......@@ -106,7 +108,7 @@ public:
switch (column) {
case NameColumn:
if (role == Qt::DisplayRole)
if (role == Qt::DisplayRole || role == SortRole)
return m_spec->name();
if (role == Qt::ToolTipRole) {
QString toolTip;
......@@ -133,17 +135,17 @@ public:
case LoadedColumn:
if (!m_spec->isAvailableForHostPlatform()) {
if (role == Qt::CheckStateRole)
if (role == Qt::CheckStateRole || role == SortRole)
return Qt::Unchecked;
if (role == Qt::ToolTipRole)
return PluginView::tr("Plugin is not available on this platform.");
} else if (m_spec->isRequired()) {
if (role == Qt::CheckStateRole)
if (role == Qt::CheckStateRole || role == SortRole)
return Qt::Checked;
if (role == Qt::ToolTipRole)
return PluginView::tr("Plugin is required.");
} else {
if (role == Qt::CheckStateRole)
if (role == Qt::CheckStateRole || role == SortRole)
return m_spec->isEnabledBySettings() ? Qt::Checked : Qt::Unchecked;
if (role == Qt::ToolTipRole)
return PluginView::tr("Load on startup");
......@@ -151,12 +153,12 @@ public:
case VersionColumn:
if (role == Qt::DisplayRole)
if (role == Qt::DisplayRole || role == SortRole)
return QString::fromLatin1("%1 (%2)").arg(m_spec->version(), m_spec->compatVersion());
case VendorColumn:
if (role == Qt::DisplayRole)
if (role == Qt::DisplayRole || role == SortRole)
return m_spec->vendor();
......@@ -211,7 +213,7 @@ public:
QVariant data(int column, int role) const
if (column == NameColumn) {
if (role == Qt::DisplayRole)
if (role == Qt::DisplayRole || role == SortRole)
return m_name;
if (role == Qt::DecorationRole) {
foreach (PluginSpec *spec, m_plugins) {
......@@ -227,7 +229,7 @@ public:
if (column == LoadedColumn) {
if (role == Qt::ToolTipRole)
return PluginView::tr("Load on Startup");
if (role == Qt::CheckStateRole) {
if (role == Qt::CheckStateRole || role == SortRole) {
int checkedCount = 0;
foreach (PluginSpec *spec, m_plugins) {
if (spec->isEnabledBySettings())
......@@ -298,6 +300,7 @@ PluginView::PluginView(QWidget *parent)
m_sortModel = new QSortFilterProxyModel(this);
QGridLayout *gridLayout = new QGridLayout(this);
......@@ -438,7 +438,7 @@ void SshConnectionPrivate::handleCurrentPacket()
QHash<SshPacketType, HandlerInStates>::ConstIterator it
= m_packetHandlers.find(m_incomingPacket.type());
= m_packetHandlers.constFind(m_incomingPacket.type());
if (it == m_packetHandlers.constEnd()) {
......@@ -104,7 +104,7 @@ bool SshHostKeyDatabase::store(const QString &filePath, QString *error) const
SshHostKeyDatabase::KeyLookupResult SshHostKeyDatabase::matchHostKey(const QString &hostName,
const QByteArray &key) const
auto it = d->hostKeys.find(hostName);
auto it = d->hostKeys.constFind(hostName);
if (it == d->hostKeys.constEnd())
return KeyLookupNoMatch;
if (it.value() == key)
......@@ -681,7 +681,8 @@ static bool mergeGradleProperties(const QString &path, GradleProperties properti
for (GradleProperties::const_iterator it = properties.begin(); it != properties.end(); ++it)
for (GradleProperties::const_iterator it = properties.constBegin(); it != properties.constEnd();
file.write(it.key() + '=' + it.value() + '\n');
......@@ -521,9 +521,9 @@ ParserTreeItem::ConstPtr Parser::getCachedOrParseDocumentTree(const CPlusPlus::D
const QString &fileName = doc->fileName();
ParserTreeItem::ConstPtr item = d->cachedDocTrees.value(fileName);
CitCachedDocTreeRevision citCachedDocTreeRevision = d->cachedDocTreesRevision.find(fileName);
CitCachedDocTreeRevision citCachedDocTreeRevision = d->cachedDocTreesRevision.constFind(fileName);
if (!item.isNull()
&& citCachedDocTreeRevision != d->cachedDocTreesRevision.end()
&& citCachedDocTreeRevision != d->cachedDocTreesRevision.constEnd()
&& citCachedDocTreeRevision.value() == doc->revision()) {
return item;
......@@ -759,9 +759,9 @@ QStringList Parser::addProjectNode(const ParserTreeItem::Ptr &item, const Projec
// our own files
QStringList fileList;
CitCachedPrjFileLists cit = d->cachedPrjFileLists.find(nodePath);
CitCachedPrjFileLists cit = d->cachedPrjFileLists.constFind(nodePath);
// try to improve parsing speed by internal cache
if (cit != d->cachedPrjFileLists.end()) {
if (cit != d->cachedPrjFileLists.constEnd()) {
fileList = cit.value();
} else {
fileList = projectNodeFileList(node);
......@@ -800,9 +800,9 @@ QStringList Parser::getAllFiles(const ProjectNode *node)
const QString nodePath = node->path().toString();
CitCachedPrjFileLists cit = d->cachedPrjFileLists.find(nodePath);
CitCachedPrjFileLists cit = d->cachedPrjFileLists.constFind(nodePath);
// try to improve parsing speed by internal cache
if (cit != d->cachedPrjFileLists.end()) {
if (cit != d->cachedPrjFileLists.constEnd()) {
fileList = cit.value();
} else {
fileList = projectNodeFileList(node);
......@@ -80,8 +80,8 @@ void ClearCaseSync::invalidateStatus(const QDir &viewRootDir,
void ClearCaseSync::invalidateStatusAllFiles()
const StatusMap::ConstIterator send = m_statusMap->end();
for (StatusMap::ConstIterator it = m_statusMap->begin(); it != send; ++it)
const StatusMap::ConstIterator send = m_statusMap->constEnd();
for (StatusMap::ConstIterator it = m_statusMap->constBegin(); it != send; ++it)
m_plugin->setStatus(it.key(), FileStatus::Unknown, false);
......@@ -249,8 +249,8 @@ bool CppSourceProcessor::checkFile(const QString &absoluteFilePath) const
QString CppSourceProcessor::resolveFile(const QString &fileName, IncludeType type)
if (type == IncludeGlobal) {
QHash<QString, QString>::ConstIterator it = m_fileNameCache.find(fileName);
if (it != m_fileNameCache.end())
QHash<QString, QString>::ConstIterator it = m_fileNameCache.constFind(fileName);
if (it != m_fileNameCache.constEnd())
return it.value();
const QString fn = resolveFile_helper(fileName, type);
m_fileNameCache.insert(fileName, fn);
......@@ -1850,8 +1850,8 @@ QString GdbEngine::cleanupFullName(const QString &fileName)
const QString base = FileName::fromString(fileName).fileName();
QMap<QString, QString>::const_iterator jt = m_baseNameToFullName.find(base);
while (jt != m_baseNameToFullName.end() && jt.key() == base) {
QMap<QString, QString>::const_iterator jt = m_baseNameToFullName.constFind(base);
while (jt != m_baseNameToFullName.constEnd() && jt.key() == base) {
// FIXME: Use some heuristics to find the "best" match.
return jt.value();
......@@ -4018,7 +4018,7 @@ bool GdbEngine::handleCliDisassemblerResult(const QByteArray &output, Disassembl
currentFunction = -1;
DisassemblerLines result;
for (LineMap::const_iterator it = lineMap.begin(), et = lineMap.end(); it != et; ++it) {
for (LineMap::const_iterator it = lineMap.constBegin(), et = lineMap.constEnd(); it != et; ++it) {
LineData d = *it;
if (d.function != currentFunction) {
if (d.function != -1) {
......@@ -1510,8 +1510,8 @@ void QmlV8DebuggerClient::setCurrentFrameDetails(const QVariant &bodyVal, const
// Expand watch data that were previously expanded
QHash<quint64, QByteArray>::const_iterator itEnd = handlesToLookup.end();
for (QHash<quint64, QByteArray>::const_iterator it = handlesToLookup.begin(); it != itEnd; ++it)
QHash<quint64, QByteArray>::const_iterator itEnd = handlesToLookup.constEnd();
for (QHash<quint64, QByteArray>::const_iterator it = handlesToLookup.constBegin(); it != itEnd; ++it)
expandObject(it.value(), it.key());
emit stackFrameCompleted();
......@@ -124,6 +124,7 @@ const char KeyFileKey[] = "KeyFile";
const char PasswordKey[] = "Password";
const char TimeoutKey[] = "Timeout";
const char HostKeyCheckingKey[] = "HostKeyChecking";
const char SshOptionsKey[] = "SshOptions";
const char DebugServerKey[] = "DebugServerKey";
......@@ -328,6 +329,8 @@ void IDevice::fromMap(const QVariantMap &map)
d->sshParameters.timeout = map.value(QLatin1String(TimeoutKey), DefaultTimeout).toInt();
d->sshParameters.hostKeyCheckingMode = static_cast<QSsh::SshHostKeyCheckingMode>
(map.value(QLatin1String(HostKeyCheckingKey), QSsh::SshHostKeyCheckingNone).toInt());
= QSsh::SshConnectionOptions(map.value(QLatin1String(SshOptionsKey)).toInt());
d->freePorts = Utils::PortList::fromString(map.value(QLatin1String(PortsSpecKey),
......@@ -360,6 +363,7 @@ QVariantMap IDevice::toMap() const
map.insert(QLatin1String(KeyFileKey), d->sshParameters.privateKeyFile);
map.insert(QLatin1String(TimeoutKey), d->sshParameters.timeout);
map.insert(QLatin1String(HostKeyCheckingKey), d->sshParameters.hostKeyCheckingMode);
map.insert(QLatin1String(SshOptionsKey), static_cast<int>(d->sshParameters.options));
map.insert(QLatin1String(PortsSpecKey), d->freePorts.toString());
map.insert(QLatin1String(VersionKey), d->version);
......@@ -317,7 +317,7 @@ Utils::Environment MsvcToolChain::readEnvironmentSetting(Utils::Environment& env
// Now loop through and process them
QMap<QString,QString>::const_iterator envIter;
for (envIter = envPairs.begin(); envIter!=envPairs.end(); ++envIter) {