-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[analyzer] Introduce per-entry-point statistics #131175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
6b6d80d
[analyzer] Introduce per-entry-point statistics
necto c8e024f
[NFC] Fix darker python formatting
necto 0485df7
Write documentation
necto a9caa3b
Update clang/docs/analyzer/developer-docs/Statistics.rst
necto 84e3571
Update clang/include/clang/StaticAnalyzer/Core/PathSensitive/EntryPoi…
necto 3a9d14c
Rename parameter to dump-entry-point-stats-to-csv
necto 7b11c65
Add the missing test case
necto 886f5ae
[NFC] Fix typo in a class name
necto 8e58d6c
Remove unnecesary canonicalization
necto 36c8346
Update clang/docs/analyzer/developer-docs/Statistics.rst
necto 991340d
[NFC] Fix header comment widths
necto 788465a
Hyperlink the documentation
necto ff60af4
Doc fix
necto 933e090
[NFC] Rename dumpDynamicStatsAsCSV to dumpAsCSV
necto 548eaad
Expand acronym
necto File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
=================== | ||
Analysis Statistics | ||
=================== | ||
|
||
Clang Static Analyzer enjoys two facilities to collect statistics: per translation unit and per entry point. | ||
We use `llvm/ADT/Statistic.h`_ for numbers describing the entire translation unit. | ||
We use `clang/StaticAnalyzer/Core/PathSensitive/EntryPointStats.h`_ to collect data for each symbolic-execution entry point. | ||
|
||
.. _llvm/ADT/Statistic.h: https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/ADT/Statistic.h#L171 | ||
.. _clang/StaticAnalyzer/Core/PathSensitive/EntryPointStats.h: https://github.com/llvm/llvm-project/blob/main/clang/include/clang/StaticAnalyzer/Core/PathSensitive/EntryPointStats.h | ||
|
||
In many cases, it makes sense to collect statistics on both translation-unit level and entry-point level. You can use the two macros defined in EntryPointStats.h for that: | ||
|
||
- ``STAT_COUNTER`` for additive statistics, for example, "the number of steps executed", "the number of functions inlined". | ||
- ``STAT_MAX`` for maximizing statistics, for example, "the maximum environment size", or "the longest execution path". | ||
|
||
If you want to define a statistic that makes sense only for the entire translation unit, for example, "the number of entry points", Statistic.h defines two macros: ``STATISTIC`` and ``ALWAYS_ENABLED_STATISTIC``. | ||
You should prefer ``ALWAYS_ENABLED_STATISTIC`` unless you have a good reason not to. | ||
``STATISTIC`` is controlled by ``LLVM_ENABLE_STATS`` / ``LLVM_FORCE_ENABLE_STATS``. | ||
However, note that with ``LLVM_ENABLE_STATS`` disabled, only storage of the values is disabled, the computations producing those values still carry on unless you took an explicit precaution to make them conditional too. | ||
|
||
If you want to define a statistic only for entry point, EntryPointStats.h has four classes at your disposal: | ||
|
||
|
||
- ``BoolEPStat`` - a boolean value assigned at most once per entry point. For example: "has the inline limit been reached". | ||
- ``UnsignedEPStat`` - an unsigned value assigned at most once per entry point. For example: "the number of source characters in an entry-point body". | ||
- ``CounterEPStat`` - an additive statistic. It starts with 0 and you can add to it as many times as needed. For example: "the number of bugs discovered". | ||
- ``UnsignedMaxEPStat`` - a maximizing statistic. It starts with 0 and when you join it with a value, it picks the maximum of the previous value and the new one. For example, "the longest execution path of a bug". | ||
|
||
To produce a CSV file with all the statistics collected per entry point, use the ``dump-entry-point-stats-to-csv=<file>.csv`` parameter. | ||
|
||
Note, EntryPointStats.h is not meant to be complete, and if you feel it is lacking certain kind of statistic, odds are that it does. | ||
Feel free to extend it! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
162 changes: 162 additions & 0 deletions
162
clang/include/clang/StaticAnalyzer/Core/PathSensitive/EntryPointStats.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
// EntryPointStats.h - Tracking statistics per entry point ------*- C++ -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef CLANG_INCLUDE_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENTRYPOINTSTATS_H | ||
#define CLANG_INCLUDE_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENTRYPOINTSTATS_H | ||
|
||
#include "llvm/ADT/Statistic.h" | ||
#include "llvm/ADT/StringRef.h" | ||
|
||
namespace llvm { | ||
class raw_ostream; | ||
} // namespace llvm | ||
|
||
namespace clang { | ||
class Decl; | ||
|
||
namespace ento { | ||
|
||
class EntryPointStat { | ||
public: | ||
llvm::StringLiteral name() const { return Name; } | ||
|
||
static void lockRegistry(); | ||
|
||
static void takeSnapshot(const Decl *EntryPoint); | ||
static void dumpStatsAsCSV(llvm::raw_ostream &OS); | ||
static void dumpStatsAsCSV(llvm::StringRef FileName); | ||
|
||
protected: | ||
explicit EntryPointStat(llvm::StringLiteral Name) : Name{Name} {} | ||
EntryPointStat(const EntryPointStat &) = delete; | ||
EntryPointStat(EntryPointStat &&) = delete; | ||
EntryPointStat &operator=(EntryPointStat &) = delete; | ||
EntryPointStat &operator=(EntryPointStat &&) = delete; | ||
|
||
private: | ||
llvm::StringLiteral Name; | ||
}; | ||
|
||
class BoolEPStat : public EntryPointStat { | ||
std::optional<bool> Value = {}; | ||
|
||
public: | ||
explicit BoolEPStat(llvm::StringLiteral Name); | ||
unsigned value() const { return Value && *Value; } | ||
void set(bool V) { | ||
assert(!Value.has_value()); | ||
Value = V; | ||
} | ||
void reset() { Value = {}; } | ||
}; | ||
|
||
// used by CounterEntryPointTranslationUnitStat | ||
class CounterEPStat : public EntryPointStat { | ||
using EntryPointStat::EntryPointStat; | ||
unsigned Value = {}; | ||
|
||
public: | ||
explicit CounterEPStat(llvm::StringLiteral Name); | ||
unsigned value() const { return Value; } | ||
void reset() { Value = {}; } | ||
CounterEPStat &operator++() { | ||
++Value; | ||
return *this; | ||
} | ||
|
||
CounterEPStat &operator++(int) { | ||
// No difference as you can't extract the value | ||
return ++(*this); | ||
} | ||
|
||
CounterEPStat &operator+=(unsigned Inc) { | ||
Value += Inc; | ||
return *this; | ||
} | ||
}; | ||
|
||
// used by UnsignedMaxEtryPointTranslationUnitStatistic | ||
class UnsignedMaxEPStat : public EntryPointStat { | ||
using EntryPointStat::EntryPointStat; | ||
unsigned Value = {}; | ||
|
||
public: | ||
explicit UnsignedMaxEPStat(llvm::StringLiteral Name); | ||
unsigned value() const { return Value; } | ||
void reset() { Value = {}; } | ||
void updateMax(unsigned X) { Value = std::max(Value, X); } | ||
}; | ||
|
||
class UnsignedEPStat : public EntryPointStat { | ||
using EntryPointStat::EntryPointStat; | ||
std::optional<unsigned> Value = {}; | ||
|
||
public: | ||
explicit UnsignedEPStat(llvm::StringLiteral Name); | ||
unsigned value() const { return Value.value_or(0); } | ||
void reset() { Value.reset(); } | ||
void set(unsigned V) { | ||
assert(!Value.has_value()); | ||
Value = V; | ||
} | ||
}; | ||
|
||
class CounterEntryPointTranslationUnitStat { | ||
CounterEPStat M; | ||
llvm::TrackingStatistic S; | ||
|
||
public: | ||
CounterEntryPointTranslationUnitStat(const char *DebugType, | ||
llvm::StringLiteral Name, | ||
llvm::StringLiteral Desc) | ||
: M(Name), S(DebugType, Name.data(), Desc.data()) {} | ||
CounterEntryPointTranslationUnitStat &operator++() { | ||
++M; | ||
++S; | ||
return *this; | ||
} | ||
|
||
CounterEntryPointTranslationUnitStat &operator++(int) { | ||
// No difference with prefix as the value is not observable. | ||
return ++(*this); | ||
} | ||
|
||
CounterEntryPointTranslationUnitStat &operator+=(unsigned Inc) { | ||
M += Inc; | ||
S += Inc; | ||
return *this; | ||
} | ||
}; | ||
|
||
class UnsignedMaxEntryPointTranslationUnitStatistic { | ||
UnsignedMaxEPStat M; | ||
llvm::TrackingStatistic S; | ||
|
||
public: | ||
UnsignedMaxEntryPointTranslationUnitStatistic(const char *DebugType, | ||
llvm::StringLiteral Name, | ||
llvm::StringLiteral Desc) | ||
: M(Name), S(DebugType, Name.data(), Desc.data()) {} | ||
void updateMax(uint64_t Value) { | ||
M.updateMax(static_cast<unsigned>(Value)); | ||
S.updateMax(Value); | ||
} | ||
}; | ||
|
||
#define STAT_COUNTER(VARNAME, DESC) \ | ||
static clang::ento::CounterEntryPointTranslationUnitStat VARNAME = { \ | ||
DEBUG_TYPE, #VARNAME, DESC} | ||
|
||
#define STAT_MAX(VARNAME, DESC) \ | ||
static clang::ento::UnsignedMaxEntryPointTranslationUnitStatistic VARNAME = \ | ||
{DEBUG_TYPE, #VARNAME, DESC} | ||
|
||
} // namespace ento | ||
} // namespace clang | ||
|
||
#endif // CLANG_INCLUDE_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENTRYPOINTSTATS_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.