/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Author: Milian Wolff, KDAB (milian.wolff@kdab.com)
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "valgrindsettings.h"
#include "valgrindplugin.h"
#include "valgrindconfigwidget.h"
#include
#include
#include
#include
#include
#include
using namespace Utils;
namespace Valgrind {
namespace Internal {
//////////////////////////////////////////////////////////////////
//
// ValgrindBaseSettings
//
//////////////////////////////////////////////////////////////////
ValgrindBaseSettings::ValgrindBaseSettings()
{
// Note that this is used twice, once for project settings in the .user files
// and once for global settings in QtCreator.ini. This uses intentionally
// the same key to facilitate copying using fromMap/toMap.
QString base = "Analyzer.Valgrind.";
group.registerAspect(&valgrindExecutable);
valgrindExecutable.setSettingsKey(base + "ValgrindExecutable");
valgrindExecutable.setDefaultValue("valgrind");
valgrindExecutable.setDisplayStyle(StringAspect::PathChooserDisplay);
valgrindExecutable.setExpectedKind(PathChooser::Command);
valgrindExecutable.setHistoryCompleter("Valgrind.Command.History");
valgrindExecutable.setDisplayName(tr("Valgrind Command"));
valgrindExecutable.setLabelText(tr("Valgrind executable:"));
if (Utils::HostOsInfo::isWindowsHost()) {
// On Window we know that we don't have a local valgrind
// executable, so having the "Browse" button in the path chooser
// (which is needed for the remote executable) is confusing.
// FIXME: not deadly, still...
//valgrindExecutable. ... buttonAtIndex(0)->hide();
}
group.registerAspect(&valgrindArguments);
valgrindArguments.setSettingsKey(base + "ValgrindArguments");
valgrindArguments.setDisplayStyle(StringAspect::LineEditDisplay);
valgrindArguments.setLabelText(tr("Valgrind arguments:"));
group.registerAspect(&selfModifyingCodeDetection);
selfModifyingCodeDetection.setSettingsKey(base + "SelfModifyingCodeDetection");
selfModifyingCodeDetection.setDefaultValue(DetectSmcStackOnly);
selfModifyingCodeDetection.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
selfModifyingCodeDetection.addOption("No");
selfModifyingCodeDetection.addOption("Only on Stack");
selfModifyingCodeDetection.addOption("Everywhere");
selfModifyingCodeDetection.addOption("Everywhere Except in File-backend Mappings");
selfModifyingCodeDetection.setLabelText(tr("Detect self-modifying code:"));
// Memcheck
group.registerAspect(&memcheckArguments);
memcheckArguments.setSettingsKey(base + "Memcheck.Arguments");
memcheckArguments.setDisplayStyle(StringAspect::LineEditDisplay);
memcheckArguments.setLabelText(tr("Extra MemCheck arguments:"));
group.registerAspect(&filterExternalIssues);
filterExternalIssues.setSettingsKey(base + "FilterExternalIssues");
filterExternalIssues.setDefaultValue(true);
filterExternalIssues.setIcon(Icons::FILTER.icon());
filterExternalIssues.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
filterExternalIssues.setLabelText(tr("Show Project Costs Only"));
filterExternalIssues.setToolTip(tr("Show only profiling info that originated from this project source."));
group.registerAspect(&trackOrigins);
trackOrigins.setSettingsKey(base + "TrackOrigins");
trackOrigins.setDefaultValue(true);
trackOrigins.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
trackOrigins.setLabelText(tr("Track origins of uninitialized memory"));
group.registerAspect(&showReachable);
showReachable.setSettingsKey(base + "ShowReachable");
showReachable.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
showReachable.setLabelText(tr("Show reachable and indirectly lost blocks"));
group.registerAspect(&leakCheckOnFinish);
leakCheckOnFinish.setSettingsKey(base + "LeakCheckOnFinish");
leakCheckOnFinish.setDefaultValue(LeakCheckOnFinishSummaryOnly);
leakCheckOnFinish.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
leakCheckOnFinish.addOption(tr("No"));
leakCheckOnFinish.addOption(tr("Summary Only"));
leakCheckOnFinish.addOption(tr("Full"));
leakCheckOnFinish.setLabelText(tr("Check for leaks on finish:"));
group.registerAspect(&numCallers);
numCallers.setSettingsKey(base + "NumCallers");
numCallers.setDefaultValue(25);
numCallers.setLabelText(tr("Backtrace frame count:"));
// Callgrind
group.registerAspect(&kcachegrindExecutable);
kcachegrindExecutable.setSettingsKey(base + "KCachegrindExecutable");
kcachegrindExecutable.setDefaultValue("kcachegrind");
kcachegrindExecutable.setDisplayStyle(StringAspect::PathChooserDisplay);
kcachegrindExecutable.setLabelText(tr("KCachegrind executable:"));
kcachegrindExecutable.setExpectedKind(Utils::PathChooser::Command);
kcachegrindExecutable.setDisplayName(tr("KCachegrind Command"));
group.registerAspect(&callgrindArguments);
callgrindArguments.setSettingsKey(base + "Callgrind.Arguments");
callgrindArguments.setDisplayStyle(StringAspect::LineEditDisplay);
callgrindArguments.setLabelText(tr("Extra CallGrind arguments:"));
group.registerAspect(&enableEventToolTips);
enableEventToolTips.setDefaultValue(true);
enableEventToolTips.setSettingsKey(base + "Callgrind.EnableEventToolTips");
enableEventToolTips.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
enableEventToolTips.setLabelText(tr("Show additional information for events in tooltips"));
group.registerAspect(&enableCacheSim);
enableCacheSim.setSettingsKey(base + "Callgrind.EnableCacheSim");
enableCacheSim.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
enableCacheSim.setLabelText(tr("Enable cache simulation"));
enableCacheSim.setToolTip("" + tr(
"Does full cache simulation.
\n"
"By default, only instruction read accesses will be counted (\"Ir\").
\n"
"\n"
"With cache simulation, further event counters are enabled:\n"
"
- Cache misses on instruction reads (\"I1mr\"/\"I2mr\").
\n"
"- Data read accesses (\"Dr\") and related cache misses (\"D1mr\"/\"D2mr\").
\n"
"- Data write accesses (\"Dw\") and related cache misses (\"D1mw\"/\"D2mw\").
\n"
"
") + "");
group.registerAspect(&enableBranchSim);
enableBranchSim.setSettingsKey(base + "Callgrind.EnableBranchSim");
enableBranchSim.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
enableBranchSim.setLabelText(tr("Enable branch prediction simulation"));
enableBranchSim.setToolTip("\n" + tr(
"Does branch prediction simulation.
\n"
"Further event counters are enabled:
\n"
"- Number of executed conditional branches and related predictor misses (\n"
"\"Bc\"/\"Bcm\").
\n"
"- Executed indirect jumps and related misses of the jump address predictor (\n"
"\"Bi\"/\"Bim\").)
") + "");
group.registerAspect(&collectSystime);
collectSystime.setSettingsKey(base + "Callgrind.CollectSystime");
collectSystime.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
collectSystime.setLabelText(tr("Collect system call time"));
collectSystime.setToolTip(tr("Collects information for system call times."));
group.registerAspect(&collectBusEvents);
collectBusEvents.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel);
collectBusEvents.setSettingsKey(base + "Callgrind.CollectBusEvents");
collectBusEvents.setLabelText(tr("Collect global bus events"));
collectBusEvents.setToolTip(tr("Collect the number of global bus events that are executed. "
"The event type \"Ge\" is used for these events."));
group.registerAspect(&minimumInclusiveCostRatio);
minimumInclusiveCostRatio.setSettingsKey(base + "Callgrind.MinimumCostRatio");
minimumInclusiveCostRatio.setDefaultValue(0.01);
minimumInclusiveCostRatio.setSuffix(tr("%"));
minimumInclusiveCostRatio.setLabelText(tr("Result view: Minimum event cost:"));
minimumInclusiveCostRatio.setToolTip(tr("Limits the amount of results the profiler gives you. "
"A lower limit will likely increase performance."));
group.registerAspect(&visualizationMinimumInclusiveCostRatio);
visualizationMinimumInclusiveCostRatio.setSettingsKey(base + "Callgrind.VisualisationMinimumCostRatio");
visualizationMinimumInclusiveCostRatio.setDefaultValue(10.0);
visualizationMinimumInclusiveCostRatio.setLabelText(tr("Visualization: Minimum event cost:"));
visualizationMinimumInclusiveCostRatio.setSuffix(tr("%"));
group.registerAspect(&visibleErrorKinds);
visibleErrorKinds.setSettingsKey(base + "VisibleErrorKinds");
QList defaultErrorKinds;
for (int i = 0; i < Valgrind::XmlProtocol::MemcheckErrorKindCount; ++i)
defaultErrorKinds << i;
visibleErrorKinds.setDefaultValue(defaultErrorKinds);
}
void ValgrindBaseSettings::fromMap(const QVariantMap &map)
{
group.fromMap(map);
if (ValgrindGlobalSettings::instance() != this) {
// FIXME: Update project page e.g. on "Restore Global", aspects
// there are 'autoapply', and Aspect::cancel() is normally part of
// the 'manual apply' machinery.
group.setAutoApply(false);
group.cancel();
group.setAutoApply(true);
}
}
void ValgrindBaseSettings::toMap(QVariantMap &map) const
{
group.toMap(map);
}
//////////////////////////////////////////////////////////////////
//
// ValgrindGlobalSettings
//
//////////////////////////////////////////////////////////////////
static ValgrindGlobalSettings *theGlobalSettings = nullptr;
ValgrindGlobalSettings::ValgrindGlobalSettings()
{
theGlobalSettings = this;
const QString base = "Analyzer.Valgrind";
group.registerAspect(&suppressionFiles_);
suppressionFiles_.setSettingsKey(base + "SupressionFiles");
group.registerAspect(&lastSuppressionDirectory);
lastSuppressionDirectory.setSettingsKey(base + "LastSuppressionDirectory");
group.registerAspect(&lastSuppressionHistory);
lastSuppressionHistory.setSettingsKey(base + "LastSuppressionHistory");
group.registerAspect(&detectCycles);
detectCycles.setSettingsKey(base + "Callgrind.CycleDetection");
detectCycles.setDefaultValue(true);
detectCycles.setLabelText("O"); // FIXME: Create a real icon
detectCycles.setToolTip(tr("Enable cycle detection to properly handle recursive "
"or circular function calls."));
group.registerAspect(&costFormat);
costFormat.setSettingsKey(base + "Callgrind.CostFormat");
costFormat.setDefaultValue(CostDelegate::FormatRelative);
costFormat.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
group.registerAspect(&shortenTemplates);
shortenTemplates.setSettingsKey(base + "Callgrind.ShortenTemplates");
shortenTemplates.setDefaultValue(true);
shortenTemplates.setLabelText("<>"); // FIXME: Create a real icon
shortenTemplates.setToolTip(tr("Remove template parameter lists when displaying function names."));
setConfigWidgetCreator([this] { return ValgrindOptionsPage::createSettingsWidget(this); });
readSettings();
group.forEachAspect([](BaseAspect *aspect) { aspect->setAutoApply(false); });
}
ValgrindGlobalSettings *ValgrindGlobalSettings::instance()
{
return theGlobalSettings;
}
//
// Memcheck
//
QStringList ValgrindGlobalSettings::suppressionFiles() const
{
return suppressionFiles_.value();
}
void ValgrindGlobalSettings::addSuppressionFiles(const QStringList &suppressions)
{
suppressionFiles_.appendValues(suppressions);
}
void ValgrindGlobalSettings::removeSuppressionFiles(const QStringList &suppressions)
{
suppressionFiles_.removeValues(suppressions);
}
QVariantMap ValgrindBaseSettings::defaultSettings() const
{
QVariantMap defaults;
group.forEachAspect([&defaults](BaseAspect *aspect) {
defaults.insert(aspect->settingsKey(), aspect->defaultValue());
});
return defaults;
}
static const char groupC[] = "Analyzer";
void ValgrindGlobalSettings::readSettings()
{
QVariantMap defaults = defaultSettings();
// Read stored values
QSettings *settings = Core::ICore::settings();
settings->beginGroup(groupC);
QVariantMap map = defaults;
for (QVariantMap::ConstIterator it = defaults.constBegin(); it != defaults.constEnd(); ++it)
map.insert(it.key(), settings->value(it.key(), it.value()));
settings->endGroup();
fromMap(map);
}
void ValgrindGlobalSettings::writeSettings() const
{
const QVariantMap defaults = defaultSettings();
Utils::QtcSettings *settings = Core::ICore::settings();
settings->beginGroup(groupC);
QVariantMap map;
toMap(map);
for (QVariantMap::ConstIterator it = map.constBegin(); it != map.constEnd(); ++it)
settings->setValueWithDefault(it.key(), it.value(), defaults.value(it.key()));
settings->endGroup();
}
//////////////////////////////////////////////////////////////////
//
// ValgrindProjectSettings
//
//////////////////////////////////////////////////////////////////
ValgrindProjectSettings::ValgrindProjectSettings()
{
setConfigWidgetCreator([this] { return ValgrindOptionsPage::createSettingsWidget(this); });
group.registerAspect(&disabledGlobalSuppressionFiles);
disabledGlobalSuppressionFiles.setSettingsKey("Analyzer.Valgrind.RemovedSuppressionFiles");
group.registerAspect(&addedSuppressionFiles);
addedSuppressionFiles.setSettingsKey("Analyzer.Valgrind.AddedSuppressionFiles");
}
//
// Memcheck
//
void ValgrindProjectSettings::addSuppressionFiles(const QStringList &suppressions)
{
const QStringList globalSuppressions = ValgrindGlobalSettings::instance()->suppressionFiles();
for (const QString &s : suppressions) {
if (addedSuppressionFiles.value().contains(s))
continue;
disabledGlobalSuppressionFiles.removeValue(s);
if (!globalSuppressions.contains(s))
addedSuppressionFiles.appendValue(s);
}
}
void ValgrindProjectSettings::removeSuppressionFiles(const QStringList &suppressions)
{
const QStringList globalSuppressions = ValgrindGlobalSettings::instance()->suppressionFiles();
for (const QString &s : suppressions) {
addedSuppressionFiles.removeValue(s);
if (globalSuppressions.contains(s))
disabledGlobalSuppressionFiles.appendValue(s);
}
}
QStringList ValgrindProjectSettings::suppressionFiles() const
{
QStringList ret = ValgrindGlobalSettings::instance()->suppressionFiles();
for (const QString &s : disabledGlobalSuppressionFiles.value())
ret.removeAll(s);
ret.append(addedSuppressionFiles.value());
return ret;
}
} // namespace Internal
} // namespace Valgrind