├── TopHeaders
├── packages.config
├── TopHeaders.vcxproj.filters
├── main.cpp
└── TopHeaders.vcxproj
├── LongCodeGenFinder
├── packages.config
├── LongCodeGenFinder.vcxproj.filters
├── main.cpp
└── LongCodeGenFinder.vcxproj
├── LongModuleFinder
├── packages.config
├── LongModuleFinder.vcxproj.filters
├── main.cpp
└── LongModuleFinder.vcxproj
├── BottleneckCompileFinder
├── packages.config
├── BottleneckCompileFinder.vcxproj.filters
├── main.cpp
└── BottleneckCompileFinder.vcxproj
├── CAToolsetPerfDataCollector
├── packages.config
├── README.md
├── PerfDataCollector.h
├── main.cpp
├── CAToolsetPerfDataCollector.vcxproj
└── PerfDataCollector.cpp
├── FunctionBottlenecks
├── packages.config
├── FunctionBottlenecks.vcxproj.filters
├── main.cpp
└── FunctionBottlenecks.vcxproj
├── LongHeaderUnitFinder
├── packages.config
├── LongHeaderUnitFinder.vcxproj.filters
├── main.cpp
└── LongHeaderUnitFinder.vcxproj
├── LongPrecompiledHeaderFinder
├── packages.config
├── LongPrecompiledHeaderFinder.vcxproj.filters
├── main.cpp
└── LongPrecompiledHeaderFinder.vcxproj
├── RecursiveTemplateInspector
├── packages.config
├── RecursiveTemplateInspector.vcxproj.filters
├── main.cpp
└── RecursiveTemplateInspector.vcxproj
├── CODE_OF_CONDUCT.md
├── LICENSE
├── SECURITY.md
├── README.md
├── .gitignore
└── Samples.sln
/TopHeaders/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/LongCodeGenFinder/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/LongModuleFinder/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/BottleneckCompileFinder/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/CAToolsetPerfDataCollector/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/FunctionBottlenecks/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/LongHeaderUnitFinder/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/LongPrecompiledHeaderFinder/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/RecursiveTemplateInspector/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 |
--------------------------------------------------------------------------------
/TopHeaders/TopHeaders.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LongCodeGenFinder/LongCodeGenFinder.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/BottleneckCompileFinder/BottleneckCompileFinder.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/FunctionBottlenecks/FunctionBottlenecks.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LongModuleFinder/LongModuleFinder.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LongHeaderUnitFinder/LongHeaderUnitFinder.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/RecursiveTemplateInspector/RecursiveTemplateInspector.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LongPrecompiledHeaderFinder/LongPrecompiledHeaderFinder.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/LongCodeGenFinder/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | using namespace Microsoft::Cpp::BuildInsights;
5 | using namespace Activities;
6 |
7 | class LongCodeGenFinder : public IAnalyzer
8 | {
9 | public:
10 | // Called by the analysis driver every time an activity stop event
11 | // is seen in the trace.
12 | AnalysisControl OnStopActivity(const EventStack& eventStack) override
13 | {
14 | // This will check whether the event stack matches
15 | // TopFunctionsFinder::CheckForTopFunction's signature.
16 | // If it does, it will forward the event to the function.
17 |
18 | MatchEventStackInMemberFunction(eventStack, this,
19 | &LongCodeGenFinder::CheckForLongFunctionCodeGen);
20 |
21 | // Tells the analysis driver to proceed to the next event
22 |
23 | return AnalysisControl::CONTINUE;
24 | }
25 |
26 | // This function is used to capture Function activity events that are
27 | // within a CodeGeneration activity, and to print a list of functions
28 | // that take more than 500 milliseconds to generate.
29 |
30 | void CheckForLongFunctionCodeGen(CodeGeneration cg, Function f)
31 | {
32 | using namespace std::chrono;
33 |
34 | if (f.Duration() < milliseconds(500)) {
35 | return;
36 | }
37 |
38 | std::cout << "Duration: " << duration_cast(
39 | f.Duration()).count();
40 |
41 | std::cout << "\t Function Name: " << f.Name() << std::endl;
42 | }
43 | };
44 |
45 | int main(int argc, char *argv[])
46 | {
47 | if (argc <= 1) return -1;
48 |
49 | LongCodeGenFinder lcgf;
50 |
51 | // Let's make a group of analyzers that will receive
52 | // events in the trace. We only have one; easy!
53 | auto group = MakeStaticAnalyzerGroup(&lcgf);
54 |
55 | // argv[1] should contain the path to a trace file
56 | int numberOfPasses = 1;
57 | return Analyze(argv[1], numberOfPasses, group);
58 | }
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/LongModuleFinder/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | using namespace Microsoft::Cpp::BuildInsights;
10 | using namespace Activities;
11 | using namespace SimpleEvents;
12 |
13 | class LongModuleFinder : public IAnalyzer
14 | {
15 | struct FrontEndPassData
16 | {
17 | std::wstring Name;
18 | unsigned InvocationId;
19 | double Duration;
20 |
21 | bool operator<(const FrontEndPassData& other) const {
22 | return Duration > other.Duration;
23 | }
24 | };
25 |
26 | public:
27 | LongModuleFinder() :
28 | cachedFrontEndPassIds_{},
29 | FrontEndPassData_{}
30 | {}
31 |
32 | AnalysisControl OnBeginAnalysisPass() override
33 | {
34 | return AnalysisControl::CONTINUE;
35 | }
36 |
37 | AnalysisControl OnStopActivity(const EventStack& eventStack)
38 | override
39 | {
40 | MatchEventStackInMemberFunction(eventStack, this,
41 | &LongModuleFinder::OnStopFrontEndPass);
42 |
43 | return AnalysisControl::CONTINUE;
44 | }
45 |
46 | AnalysisControl OnSimpleEvent(const EventStack& eventStack) override
47 | {
48 | MatchEventStackInMemberFunction(eventStack, this,
49 | &LongModuleFinder::OnModuleEvent);
50 |
51 | return AnalysisControl::CONTINUE;
52 | }
53 |
54 | void OnStopFrontEndPass(Compiler cl, FrontEndPass frontEndPass)
55 | {
56 | // if the EventInstanceId of the current FrontEndPass has been saved
57 |
58 | auto itInvocation = cachedFrontEndPassIds_.find(
59 | frontEndPass.EventInstanceId());
60 |
61 | if (itInvocation == cachedFrontEndPassIds_.end()) {
62 | return;
63 | }
64 |
65 | using namespace std::chrono;
66 |
67 | if (frontEndPass.Duration() < std::chrono::seconds(1)) {
68 | return;
69 | }
70 |
71 | double duration = static_cast(duration_cast(frontEndPass.Duration()).count()) / 1000;
72 |
73 | std::wstring inputSourcePathWstr(frontEndPass.InputSourcePath());
74 |
75 | FrontEndPassData_[frontEndPass.EventInstanceId()] = { inputSourcePathWstr, cl.InvocationId(), duration };
76 | }
77 |
78 | void OnModuleEvent(FrontEndPass frontEndPass, Module m)
79 | {
80 | // Save the EventInstanceId of the current FrontEndPass
81 | cachedFrontEndPassIds_.insert(frontEndPass.EventInstanceId());
82 | }
83 |
84 | AnalysisControl OnEndAnalysis() override
85 | {
86 | std::vector sortedFrontEndPassData;
87 |
88 | for (auto& p : FrontEndPassData_) {
89 | sortedFrontEndPassData.push_back(p.second);
90 | }
91 |
92 | std::sort(sortedFrontEndPassData.begin(), sortedFrontEndPassData.end());
93 |
94 | for (auto& frontEndPassData : sortedFrontEndPassData)
95 | {
96 | std::cout << "File Name: ";
97 | std::wcout << frontEndPassData.Name;
98 | std::cout << "\t\tCL Invocation " << frontEndPassData.InvocationId << "\t\tDuration: " << frontEndPassData.Duration << " s " << std::endl;
99 | }
100 |
101 | return AnalysisControl::CONTINUE;
102 | }
103 |
104 | private:
105 | std::unordered_set cachedFrontEndPassIds_;
106 |
107 | std::unordered_map FrontEndPassData_;
109 | };
110 |
111 | int main(int argc, char* argv[])
112 | {
113 | if (argc <= 1) return -1;
114 |
115 | LongModuleFinder lmf;
116 |
117 | auto group = MakeStaticAnalyzerGroup(&lmf);
118 |
119 | // argv[1] should contain the path to a trace file
120 | int numberOfPasses = 1;
121 |
122 | return Analyze(argv[1], numberOfPasses, group);
123 | }
--------------------------------------------------------------------------------
/LongHeaderUnitFinder/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | using namespace Microsoft::Cpp::BuildInsights;
10 | using namespace Activities;
11 | using namespace SimpleEvents;
12 |
13 | class LongHeaderUnitFinder : public IAnalyzer
14 | {
15 | struct FrontEndPassData
16 | {
17 | std::wstring Name;
18 | unsigned InvocationId;
19 | double Duration;
20 |
21 | bool operator<(const FrontEndPassData& other) const {
22 | return Duration > other.Duration;
23 | }
24 | };
25 |
26 | public:
27 | LongHeaderUnitFinder() :
28 | cachedFrontEndPassIds_{},
29 | FrontEndPassData_{}
30 | {}
31 |
32 | AnalysisControl OnBeginAnalysisPass() override
33 | {
34 | return AnalysisControl::CONTINUE;
35 | }
36 |
37 | AnalysisControl OnStopActivity(const EventStack& eventStack)
38 | override
39 | {
40 | MatchEventStackInMemberFunction(eventStack, this,
41 | &LongHeaderUnitFinder::OnStopFrontEndPass);
42 |
43 | return AnalysisControl::CONTINUE;
44 | }
45 |
46 | AnalysisControl OnSimpleEvent(const EventStack& eventStack) override
47 | {
48 | MatchEventStackInMemberFunction(eventStack, this,
49 | &LongHeaderUnitFinder::OnHeaderUnitEvent);
50 |
51 | return AnalysisControl::CONTINUE;
52 | }
53 |
54 | void OnStopFrontEndPass(Compiler cl, FrontEndPass frontEndPass)
55 | {
56 | // if the EventInstanceId of the current FrontEndPass has been saved
57 |
58 | auto itInvocation = cachedFrontEndPassIds_.find(
59 | frontEndPass.EventInstanceId());
60 |
61 | if (itInvocation == cachedFrontEndPassIds_.end()) {
62 | return;
63 | }
64 |
65 | using namespace std::chrono;
66 |
67 | if (frontEndPass.Duration() < std::chrono::seconds(1)) {
68 | return;
69 | }
70 |
71 | double duration = static_cast(duration_cast(frontEndPass.Duration()).count()) / 1000;
72 |
73 | std::wstring inputSourcePathWstr(frontEndPass.InputSourcePath());
74 |
75 | FrontEndPassData_[frontEndPass.EventInstanceId()] = { inputSourcePathWstr, cl.InvocationId(), duration };
76 | }
77 |
78 | void OnHeaderUnitEvent(FrontEndPass frontEndPass, HeaderUnit hu)
79 | {
80 | // Save the EventInstanceId of the current FrontEndPass
81 | cachedFrontEndPassIds_.insert(frontEndPass.EventInstanceId());
82 | }
83 |
84 | AnalysisControl OnEndAnalysis() override
85 | {
86 | std::vector sortedFrontEndPassData;
87 |
88 | for (auto& p : FrontEndPassData_) {
89 | sortedFrontEndPassData.push_back(p.second);
90 | }
91 |
92 | std::sort(sortedFrontEndPassData.begin(), sortedFrontEndPassData.end());
93 |
94 | for (auto& frontEndPassData : sortedFrontEndPassData)
95 | {
96 | std::cout << "File Name: ";
97 | std::wcout << frontEndPassData.Name;
98 | std::cout << "\t\tCL Invocation " << frontEndPassData.InvocationId << "\t\tDuration: " << frontEndPassData.Duration << " s " << std::endl;
99 | }
100 |
101 | return AnalysisControl::CONTINUE;
102 | }
103 |
104 | private:
105 | std::unordered_set cachedFrontEndPassIds_;
106 |
107 | std::unordered_map FrontEndPassData_;
109 | };
110 |
111 | int main(int argc, char* argv[])
112 | {
113 | if (argc <= 1) return -1;
114 |
115 | LongHeaderUnitFinder lhuf;
116 |
117 | auto group = MakeStaticAnalyzerGroup(&lhuf);
118 |
119 | // argv[1] should contain the path to a trace file
120 | int numberOfPasses = 1;
121 |
122 | return Analyze(argv[1], numberOfPasses, group);
123 | }
--------------------------------------------------------------------------------
/LongPrecompiledHeaderFinder/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | using namespace Microsoft::Cpp::BuildInsights;
10 | using namespace Activities;
11 | using namespace SimpleEvents;
12 |
13 | class LongPrecompiledHeaderFinder : public IAnalyzer
14 | {
15 | struct FrontEndPassData
16 | {
17 | std::wstring Name;
18 | unsigned InvocationId;
19 | double Duration;
20 |
21 | bool operator<(const FrontEndPassData& other) const {
22 | return Duration > other.Duration;
23 | }
24 | };
25 |
26 | public:
27 | LongPrecompiledHeaderFinder() :
28 | cachedFrontEndPassIds_{},
29 | FrontEndPassData_{}
30 | {}
31 |
32 | AnalysisControl OnBeginAnalysisPass() override
33 | {
34 | return AnalysisControl::CONTINUE;
35 | }
36 |
37 | AnalysisControl OnStopActivity(const EventStack& eventStack)
38 | override
39 | {
40 | MatchEventStackInMemberFunction(eventStack, this,
41 | &LongPrecompiledHeaderFinder::OnStopFrontEndPass);
42 |
43 | return AnalysisControl::CONTINUE;
44 | }
45 |
46 | AnalysisControl OnSimpleEvent(const EventStack& eventStack) override
47 | {
48 | MatchEventStackInMemberFunction(eventStack, this,
49 | &LongPrecompiledHeaderFinder::OnPrecompiledHeaderEvent);
50 |
51 | return AnalysisControl::CONTINUE;
52 | }
53 |
54 | void OnStopFrontEndPass(Compiler cl, FrontEndPass frontEndPass)
55 | {
56 | // if the EventInstanceId of the current FrontEndPass has been saved
57 |
58 | auto itInvocation = cachedFrontEndPassIds_.find(
59 | frontEndPass.EventInstanceId());
60 |
61 | if (itInvocation == cachedFrontEndPassIds_.end()) {
62 | return;
63 | }
64 |
65 | using namespace std::chrono;
66 |
67 | if (frontEndPass.Duration() < std::chrono::seconds(1)) {
68 | return;
69 | }
70 |
71 | double duration = static_cast(duration_cast(frontEndPass.Duration()).count()) / 1000;
72 |
73 | std::wstring inputSourcePathWstr(frontEndPass.InputSourcePath());
74 |
75 | FrontEndPassData_[frontEndPass.EventInstanceId()] = { inputSourcePathWstr, cl.InvocationId(), duration };
76 | }
77 |
78 | void OnPrecompiledHeaderEvent(FrontEndPass frontEndPass, PrecompiledHeader pch)
79 | {
80 | // Save the EventInstanceId of the current FrontEndPass
81 | cachedFrontEndPassIds_.insert(frontEndPass.EventInstanceId());
82 | }
83 |
84 | AnalysisControl OnEndAnalysis() override
85 | {
86 | std::vector sortedFrontEndPassData;
87 |
88 | for (auto& p : FrontEndPassData_) {
89 | sortedFrontEndPassData.push_back(p.second);
90 | }
91 |
92 | std::sort(sortedFrontEndPassData.begin(), sortedFrontEndPassData.end());
93 |
94 | for (auto& frontEndPassData : sortedFrontEndPassData)
95 | {
96 | std::cout << "File Name: ";
97 | std::wcout << frontEndPassData.Name;
98 | std::cout << "\t\tCL Invocation " << frontEndPassData.InvocationId << "\t\tDuration: " << frontEndPassData.Duration << " s " << std::endl;
99 | }
100 |
101 | return AnalysisControl::CONTINUE;
102 | }
103 |
104 | private:
105 | std::unordered_set cachedFrontEndPassIds_;
106 |
107 | std::unordered_map FrontEndPassData_;
109 | };
110 |
111 | int main(int argc, char* argv[])
112 | {
113 | if (argc <= 1) return -1;
114 |
115 | LongPrecompiledHeaderFinder lpchf;
116 |
117 | auto group = MakeStaticAnalyzerGroup(&lpchf);
118 |
119 | // argv[1] should contain the path to a trace file
120 | int numberOfPasses = 1;
121 |
122 | return Analyze(argv[1], numberOfPasses, group);
123 | }
--------------------------------------------------------------------------------
/BottleneckCompileFinder/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | using namespace Microsoft::Cpp::BuildInsights;
7 | using namespace Activities;
8 | using namespace SimpleEvents;
9 |
10 | class BottleneckCompileFinder : public IAnalyzer
11 | {
12 | struct InvocationInfo
13 | {
14 | bool IsBottleneck;
15 | bool UsesParallelFlag;
16 | };
17 |
18 | public:
19 | BottleneckCompileFinder()
20 | {}
21 |
22 | AnalysisControl OnStartActivity(const EventStack& eventStack)
23 | override
24 | {
25 | MatchEventStackInMemberFunction(eventStack, this,
26 | &BottleneckCompileFinder::OnStartInvocation);
27 |
28 | return AnalysisControl::CONTINUE;
29 | }
30 |
31 | AnalysisControl OnStopActivity(const EventStack& eventStack)
32 | override
33 | {
34 | MatchEventStackInMemberFunction(eventStack, this,
35 | &BottleneckCompileFinder::OnStopInvocation);
36 |
37 | return AnalysisControl::CONTINUE;
38 | }
39 |
40 | AnalysisControl OnSimpleEvent(const EventStack& eventStack)
41 | override
42 | {
43 | MatchEventStackInMemberFunction(eventStack, this,
44 | &BottleneckCompileFinder::OnCompilerCommandLine);
45 |
46 | return AnalysisControl::CONTINUE;
47 | }
48 |
49 | void OnStartInvocation(InvocationGroup group)
50 | {
51 | // We need to match groups because CL can
52 | // start a linker, and a linker can restart
53 | // itself. When this happens, the event stack
54 | // contains the parent invocations in earlier
55 | // positions.
56 |
57 | // A linker that is spawned by a previous tool is
58 | // not considered an invocation that runs in
59 | // parallel with the tool that spawned it.
60 | if (group.Size() > 1) {
61 | return;
62 | }
63 |
64 | // An invocation is speculatively considered a bottleneck
65 | // if no other invocations are currently running when it starts.
66 | bool isBottleneck = concurrentInvocations_.empty();
67 |
68 | // If there is already an invocation running, it is no longer
69 | // considered a bottleneck because we are spawning another one
70 | // that will run alongside it. Clear its bottleneck flag.
71 | if (concurrentInvocations_.size() == 1) {
72 | concurrentInvocations_.begin()->second.IsBottleneck = false;
73 | }
74 |
75 | InvocationInfo& info = concurrentInvocations_[group.Back().EventInstanceId()];
76 |
77 | info.IsBottleneck = isBottleneck;
78 | }
79 |
80 | void OnCompilerCommandLine(Compiler cl, CommandLine commandLine)
81 | {
82 | auto it = concurrentInvocations_.find(cl.EventInstanceId());
83 |
84 | if (it == concurrentInvocations_.end()) {
85 | return;
86 | }
87 |
88 | // Keep track of CL invocations that don't use MP so that we can
89 | // warn the user if this invocation is a bottleneck.
90 |
91 | std::wstring str = commandLine.Value();
92 |
93 | if (str.find(L" /MP ") != std::wstring::npos ||
94 | str.find(L" -MP ") != std::wstring::npos)
95 | {
96 | it->second.UsesParallelFlag = true;
97 | }
98 | }
99 |
100 | void OnStopInvocation(Invocation invocation)
101 | {
102 | using namespace std::chrono;
103 |
104 | auto it = concurrentInvocations_.find(invocation.EventInstanceId());
105 |
106 | if (it == concurrentInvocations_.end()) {
107 | return;
108 | }
109 |
110 | if (invocation.Type() == Invocation::Type::CL &&
111 | it->second.IsBottleneck &&
112 | !it->second.UsesParallelFlag)
113 | {
114 | std::cout << std::endl << "WARNING: Found a compiler invocation that is a " <<
115 | "bottleneck but that doesn't use the /MP flag. Consider adding " <<
116 | "the /MP flag." << std::endl;
117 |
118 | std::cout << "Information about the invocation:" << std::endl;
119 | std::wcout << "Working directory: " << invocation.WorkingDirectory() << std::endl;
120 | std::cout << "Duration: " << duration_cast(invocation.Duration()).count() <<
121 | " s" << std::endl;
122 | }
123 |
124 | concurrentInvocations_.erase(invocation.EventInstanceId());
125 | }
126 |
127 | private:
128 | // A hash table that maps cl or link invocations to a flag
129 | // that indicates whether this invocation is a bottleneck.
130 | // In this sample, an invocation is considered a bottleneck
131 | // when no other compiler or linker is running alonside it
132 | // at any point.
133 | std::unordered_map concurrentInvocations_;
134 | };
135 |
136 | int main(int argc, char* argv[])
137 | {
138 | if (argc <= 1) return -1;
139 |
140 | BottleneckCompileFinder bcf;
141 |
142 | auto group = MakeStaticAnalyzerGroup(&bcf);
143 |
144 | // argv[1] should contain the path to a trace file
145 | int numberOfPasses = 1;
146 | return Analyze(argv[1], numberOfPasses, group);
147 | }
--------------------------------------------------------------------------------
/TopHeaders/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | using namespace Microsoft::Cpp::BuildInsights;
12 | using namespace Activities;
13 |
14 | class TopHeaders : public IAnalyzer
15 | {
16 | struct FileInfo
17 | {
18 | std::chrono::nanoseconds TotalParsingTime;
19 | std::string Path;
20 | std::unordered_set PassIds;
21 |
22 | bool operator<(const FileInfo& other) const {
23 | return TotalParsingTime > other.TotalParsingTime;
24 | }
25 | };
26 |
27 | public:
28 | TopHeaders(int headerCountToDump):
29 | headerCountToDump_{headerCountToDump > 0 ?
30 | headerCountToDump : 5},
31 | frontEndAggregatedDuration_{0},
32 | fileInfo_{}
33 | {}
34 |
35 | AnalysisControl OnStopActivity(const EventStack& eventStack) override
36 | {
37 | switch (eventStack.Back().EventId())
38 | {
39 | case EVENT_ID_FRONT_END_FILE:
40 | MatchEventStackInMemberFunction(eventStack, this,
41 | &TopHeaders::OnStopFile);
42 | break;
43 |
44 | case EVENT_ID_FRONT_END_PASS:
45 | // Keep track of the overall front-end aggregated duration.
46 | // We use this value when determining how significant is
47 | // a header's total parsing time when compared to the total
48 | // front-end time.
49 | frontEndAggregatedDuration_ += eventStack.Back().Duration();
50 | break;
51 |
52 | default:
53 | break;
54 | }
55 |
56 | return AnalysisControl::CONTINUE;
57 | }
58 |
59 | AnalysisControl OnStopFile(FrontEndPass fe, FrontEndFile file)
60 | {
61 | // Make the path lowercase for comparing
62 | std::string path = file.Path();
63 |
64 | std::transform(path.begin(), path.end(), path.begin(),
65 | [](unsigned char c) { return std::tolower(c); });
66 |
67 | auto result = fileInfo_.try_emplace(std::move(path), FileInfo{});
68 |
69 | auto it = result.first;
70 | bool wasInserted = result.second;
71 |
72 | FileInfo& fi = it->second;
73 |
74 | fi.PassIds.insert(fe.EventInstanceId());
75 | fi.TotalParsingTime += file.Duration();
76 |
77 | if (result.second) {
78 | fi.Path = file.Path();
79 | }
80 |
81 | return AnalysisControl::CONTINUE;
82 | }
83 |
84 | AnalysisControl OnEndAnalysis() override
85 | {
86 | using namespace std::chrono;
87 |
88 | auto topHeaders = GetTopHeaders();
89 |
90 | if (headerCountToDump_ == 1) {
91 | std::cout << "Top header file:";
92 | }
93 | else {
94 | std::cout << "Top " << headerCountToDump_ <<
95 | " header files:";
96 | }
97 |
98 | std::cout << std::endl << std::endl;
99 |
100 | for (auto& info : topHeaders)
101 | {
102 | double frontEndPercentage =
103 | static_cast(info.TotalParsingTime.count()) /
104 | frontEndAggregatedDuration_.count() * 100.;
105 |
106 | std::cout << "Aggregated Parsing Duration: " <<
107 | duration_cast(
108 | info.TotalParsingTime).count() <<
109 | " ms" << std::endl;
110 | std::cout << "Front-End Time Percentage: " <<
111 | std::setprecision(2) << frontEndPercentage << "% " <<
112 | std::endl;
113 | std::cout << "Inclusion Count: " <<
114 | info.PassIds.size() << std::endl;
115 | std::cout << "Path: " <<
116 | info.Path << std::endl << std::endl;
117 | }
118 |
119 | return AnalysisControl::CONTINUE;
120 | }
121 |
122 | private:
123 | std::multiset GetTopHeaders()
124 | {
125 | std::multiset topHeaders;
126 |
127 | for (auto& p : fileInfo_)
128 | {
129 | if (topHeaders.size() < headerCountToDump_) {
130 | topHeaders.insert(p.second);
131 | }
132 | else
133 | {
134 | auto itLast = --topHeaders.end();
135 |
136 | if (p.second.TotalParsingTime >
137 | itLast->TotalParsingTime)
138 | {
139 | topHeaders.insert(p.second);
140 | topHeaders.erase(itLast);
141 | }
142 | }
143 | }
144 |
145 | return topHeaders;
146 | }
147 |
148 | int headerCountToDump_;
149 |
150 | std::chrono::nanoseconds frontEndAggregatedDuration_;
151 |
152 | std::unordered_map fileInfo_;
153 | };
154 |
155 | int main(int argc, char* argv[])
156 | {
157 | if (argc <= 1) return -1;
158 |
159 | int headerCountToDump = 0;
160 |
161 | if (argc >= 3) {
162 | headerCountToDump = std::atoi(argv[2]);
163 | }
164 |
165 | TopHeaders th{ headerCountToDump };
166 |
167 | auto group = MakeStaticAnalyzerGroup(&th);
168 |
169 | // argv[1] should contain the path to a trace file
170 | int numberOfPasses = 1;
171 | return Analyze(argv[1], numberOfPasses, group);
172 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - C++
5 | products:
6 | - cpp-build-insights
7 | description: "This repository provides buildable and runnable samples for the C++ Build Insights SDK. Use it as a learning resource."
8 | urlFragment: "cpp-build-insights-samples"
9 | ---
10 |
11 | # C++ Build Insights SDK samples
12 |
13 | 
14 |
15 | This repository provides buildable and runnable samples for the C++ Build Insights SDK. Use it as a learning resource.
16 |
17 | ## Contents
18 |
19 | | Sample | Description |
20 | |-------------------|--------------------------------------------|
21 | | BottleneckCompileFinder | Finds CL invocations that are bottlenecks and don't use /MP. |
22 | | [CAToolsetPerfDataCollector](CAToolsetPerfDataCollector/README.md) | Prints summary of Code Analysis time relative to overall execution time. Optionally prints the summary for each source file. |
23 | | FunctionBottlenecks | Prints a list of functions that are code generation bottlenecks within their CL or Link invocation. |
24 | | LongCodeGenFinder | Lists the functions that take more than 500 milliseconds to generate in your entire build. |
25 | | RecursiveTemplateInspector | Identifies costly recursive template instantiations. |
26 | | TopHeaders | Determines which headers you might want to precompile. |
27 | | LongModuleFinder | Identifies costly module interface IFC creation. Requires trace with code built using MSVC version 16.10 or later and using SDK version Microsoft.Cpp.BuildInsights 1.2.0 or later. |
28 | | LongHeaderUnitFinder | Identifies costly header unit IFC creation. Requires trace with code built using MSVC version 16.10 or later and using SDK version Microsoft.Cpp.BuildInsights 1.2.0 or later. |
29 | | LongPrecompiledHeaderFinder | Identifies costly precompiled header (PCH) IFC creation. Requires trace with code built using MSVC version 16.10 or later and using SDK version Microsoft.Cpp.BuildInsights 1.2.0 or later. |
30 |
31 | ## Prerequisites
32 |
33 | In order to build and run the samples in this repository, you need:
34 |
35 | - Visual Studio 2022 and above (requires platform toolset version v143).
36 | - BuildInsights SDK version 1.4.2 or later
37 | - Windows 10 and above. Windows 11 is recommended.
38 |
39 | CAToolsetPerfDataCollector requires compiler and Code Analysis toolsets available in Visual Studio 2022 17.11 and later.
40 |
41 | ## Build steps
42 |
43 | 1. Clone the repository on your machine.
44 | 1. Open the Visual Studio solution file. Each sample is a separate project within the solution.
45 | 1. All samples rely on the C++ Build Insights SDK NuGet package. Restore NuGet packages and accept the license for the SDK.
46 | 1. Build the desired configuration for the samples that interest you. Available platforms are x86 and x64, and available configurations are *Debug* and *Release*.
47 | 1. Samples will be built in their own directory following this formula: `{RepositoryRoot}\out\{SampleName}`.
48 |
49 | ## Running the samples
50 |
51 | 1. The samples require *CppBuildInsights.dll* and *KernelTraceControl.dll* to run. These files are available in the C++ Build Insights NuGet package. When building samples, these files are automatically copied next to them in their respective output directory. If you are going to move a sample around on your machine, please be sure to move these DLL's along with it.
52 | 1. Collect a trace of the build you want to analyze with the sample. You can do this using two methods:
53 | 1. Use vcperf:
54 | 1. Open an elevated x64 Native Tools Command Prompt.
55 | 1. Run the following command: `vcperf /start MySessionName`
56 | - It can be used with /noadmin option to run without elevation. Running vcperf without option or input displays supported options.
57 | 1. Build your project. You do not need to use the same command prompt for building.
58 | 1. Run the following command: `vcperf /stopnoanalyze MySessionName outputTraceFile.etl`
59 | 1. Programmatically: see the [C++ Build Insights SDK](https://docs.microsoft.com/cpp/build-insights/reference/sdk/overview?view=vs-2019) documentation for details.
60 | 1. Invoke the sample, passing your trace as the first parameter.
61 |
62 | [CAToolsetPerfDataCollector](CAToolsetPerfDataCollector/README.md) has options to output results in different formats. Run the application without parameter or option to print the help on the options. Please find details about this sample in the [README.md](CAToolsetPerfDataCollector/README.md) for it.
63 |
64 |
65 | ## Contributing
66 |
67 | This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit [https://cla.opensource.microsoft.com](https://cla.opensource.microsoft.com).
68 |
69 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
70 |
71 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
72 |
--------------------------------------------------------------------------------
/CAToolsetPerfDataCollector/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - C++
5 | products:
6 | - CodeAnalysisPerfDataCollector
7 | description: ""
8 | urlFragment: "CAToolsetPerfDataCollector"
9 | ---
10 |
11 | # Code Analysis Performance Data Collector
12 |
13 | 
14 |
15 | This sample BuildInsights SDK application reads one or more Event Trace Log (ETW) files and prints summary of Code Analysis (CA) time relative to the overall execution time. It can also print execution time of each sub-process for each source file.
16 |
17 | ## Prerequisites
18 |
19 | This sample BuildInsights SDK application requires MSVC compiler and MSVC CA toolsets that are available in Visual Studio 2022 17.11 or later. It also requires BuildInsights SDK version 1.4.2 or later.
20 |
21 | ## Overview
22 |
23 | We have added ETW events to MSVC compiler and MSVC CA toolsets to measure execution times of various steps during CA. These events allow us to correlate performance of CA with the rest of the build process – for example, “CA step X took y-percent of overall compilation time”.
24 |
25 | The ability to collect and analyze CA performance data will allow users to measure CA performance for various configurations - such as different sets of rules enabled for CA, enabling CA during build, etc. - to find out the most efficient CA configurations during various phases of product development cycle.
26 |
27 | ## Running Code Analysis Performance Data Collector
28 |
29 | This application can process one or more ETW log files (*.etl files) at once to produce a combined summary report. This application can also optionally output the performance data per translation unit in CSV format.
30 |
31 | - Summary Report
32 |
33 | It is a summary report for the overall performance of CA, providing relative time spent in CA steps at various phases of the compilation process. This is the default output format that provides a quick overview of CA performance.
34 |
35 | - Per Translation Unit data records in CSV Format
36 |
37 | This is a set of rows with performance numbers (in unit of milliseconds) - each row corresponding to each of the Translation units that are compiled and analyzed – in CSV (comma-separated-values) format. This allows users to process the data further and create various reports using tools like MS Excel.
38 |
39 | Running the application without any option or input will provide help on the options it supports:
40 |
41 | ```
42 | c:\bisamples\out\x64\Debug\CodeAnalysisPerfDataCollector> CodeAnalysisPerfDataCollector.exe
43 |
44 | Usage: "CodeAnalysisPerfDataCollector" [-v[erbose]] [-f[ormat]:Summary|CSV|Both]]
45 | -v[erbose] : Print verbose output. Optional.
46 | -f[ormat]: : Output format (Summary, CSV, or Both). Optional. Defaults to Summary.
47 | : Paths to one or more ETW trace files, separated by space. Required.
48 | Option names and values are case-insensitive.
49 | ```
50 |
51 | By default it will print CA performance summary report. If "-f:CSV" option is specified, it will print per translation unit performance data in CSV format for each and every translation unit that is built and analyzed. If "-f:both" option is specified, it will print both CA performance summary report and per translation unit performance data.
52 |
53 | ## Example Outputs
54 |
55 | ### CA Performance Summary Report
56 | This is a example output of CA performance data summary report. Please note that the actual execution times and their relative percentage numbers will vary project by project, as well as CA configurations.
57 |
58 | Percentage number for each child is relative to its immediate parent. So, the sum of the percentage numbers for all of the siblings should always equal 100%.
59 |
60 | ```
61 | Number of TUs successfully analyzed: 3289
62 | Number of TUs excluded (files not analyzed or had analysis error): 1893
63 | Total Execution Time (milliseconds):
64 | Front End Pass, BackEnd Pass, Code Analysis Pass, AST Creation, AST Clients, Function Analysis, FPA Function Analysis, EspX CFG Build, EspX Function Analysis, EspX Path-sensitive Analysis
65 | 6139105, 1184276, 57333281, 382762, 48323001, 46771695, 4680989, 3837409, 36653783, 34256891
66 | Compiler Passes [percentages are "percentage of parent" ("percentage of total")]:
67 | Front End Pass = 9.49%
68 | Back End Pass = 1.83%
69 | Code Analysis Pass = 88.67%
70 | Compilation + Miscellaneous = 15.05% (13.34%)
71 | AST Creation = 0.67% (0.59%)
72 | All AST Clients = 84.28% (74.74%)
73 | Miscellaneous = 3.21% (2.40%)
74 | Function Analysis = 96.79% (72.34%)
75 | Miscellaneous = 3.42% (2.47%)
76 | PREfast's Function Path Analysis = 10.01% (7.24%)
77 | EspX CFG Building = 8.20% (5.94%)
78 | EspX All Analysis = 78.37% (56.69%)
79 | Path-sensitive Analysis = 93.46% (52.98%)
80 | Data-flow Analysis + Miscellaneous = 6.54% (3.71%)
81 | Number of TUs with long Code Analysis Pass compared to Front End Pass:
82 | 600% or more: 1837 (55.85%)
83 | 300% or more: 945 (28.73%)
84 | 150% or more: 418 (12.71%)
85 | Less than 150%: 89 (2.71%)
86 | ```
87 |
88 | ### Per translation unit Performance Data in CSV Format
89 |
90 | Here is an example of the per translation unit performance data output. First row is the column header, and the rest are per translation unit performance data - i.e., execution times of each step in milliseconds.
91 |
92 | This can be imported into tools like MS Excel to create various reports.
93 |
94 | ```csv
95 | File Path, Front End Pass, BackEnd Pass, Code Analysis Pass, AST Creation, AST Clients, Function Analysis, FPA Function Analysis, EspX CFG Build, EspX Function Analysis, EspX Path-sensitive Analysis
96 | d:\test\file1.cpp, 253976, 111859, 5077991, 14019, 249835, 229841, 84557, 0, 0, 0
97 | d:\test\file2.cpp, 0, 0, 108231, 56, 467, 312, 123, 0, 0, 0
98 | ```
99 |
--------------------------------------------------------------------------------
/FunctionBottlenecks/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | using namespace Microsoft::Cpp::BuildInsights;
10 | using namespace Activities;
11 | using namespace SimpleEvents;
12 |
13 | class FunctionBottlenecks : public IAnalyzer
14 | {
15 | struct IdentifiedFunction
16 | {
17 | std::string Name;
18 | std::chrono::milliseconds Duration;
19 | double Percent;
20 | unsigned ForceInlineeSize;
21 |
22 | bool operator<(const IdentifiedFunction& other) const {
23 | return Duration > other.Duration;
24 | }
25 | };
26 |
27 | public:
28 | FunctionBottlenecks():
29 | pass_{0},
30 | cachedInvocationDurations_{},
31 | identifiedFunctions_{},
32 | forceInlineSizeCache_{}
33 | {}
34 |
35 | AnalysisControl OnBeginAnalysisPass() override
36 | {
37 | ++pass_;
38 | return AnalysisControl::CONTINUE;
39 | }
40 |
41 | AnalysisControl OnStopActivity(const EventStack& eventStack)
42 | override
43 | {
44 | switch (pass_)
45 | {
46 | case 1:
47 | MatchEventStackInMemberFunction(eventStack, this,
48 | &FunctionBottlenecks::OnStopInvocation);
49 | break;
50 |
51 | case 2:
52 | MatchEventStackInMemberFunction(eventStack, this,
53 | &FunctionBottlenecks::OnStopFunction);
54 | break;
55 |
56 | default:
57 | break;
58 | }
59 |
60 | return AnalysisControl::CONTINUE;
61 | }
62 |
63 | AnalysisControl OnSimpleEvent(const EventStack& eventStack)
64 | {
65 | if (pass_ > 1) {
66 | return AnalysisControl::CONTINUE;
67 | }
68 |
69 | MatchEventStackInMemberFunction(eventStack, this,
70 | &FunctionBottlenecks::ProcessForceInlinee);
71 |
72 | return AnalysisControl::CONTINUE;
73 | }
74 |
75 | void OnStopInvocation(Invocation invocation)
76 | {
77 | using namespace std::chrono;
78 |
79 | // Ignore very short invocations
80 | if (invocation.Duration() < std::chrono::seconds(1)) {
81 | return;
82 | }
83 |
84 | cachedInvocationDurations_[invocation.EventInstanceId()] =
85 | duration_cast(invocation.Duration());
86 | }
87 |
88 | void OnStopFunction(Invocation invocation, Function func)
89 | {
90 | using namespace std::chrono;
91 |
92 | auto itInvocation = cachedInvocationDurations_.find(
93 | invocation.EventInstanceId());
94 |
95 | if (itInvocation == cachedInvocationDurations_.end()) {
96 | return;
97 | }
98 |
99 | auto itForceInlineSize = forceInlineSizeCache_.find(
100 | func.EventInstanceId());
101 |
102 | unsigned forceInlineSize =
103 | itForceInlineSize == forceInlineSizeCache_.end() ?
104 | 0 : itForceInlineSize->second;
105 |
106 | milliseconds functionMilliseconds =
107 | duration_cast(func.Duration());
108 |
109 | double functionTime = static_cast(
110 | functionMilliseconds.count());
111 |
112 | double invocationTime = static_cast(
113 | itInvocation->second.count());
114 |
115 | double percent = functionTime / invocationTime;
116 |
117 | if (percent > 0.05 && func.Duration() >= seconds(1))
118 | {
119 | identifiedFunctions_[func.EventInstanceId()]=
120 | { func.Name(), functionMilliseconds, percent,
121 | forceInlineSize };
122 | }
123 | }
124 |
125 | void ProcessForceInlinee(Function func, ForceInlinee inlinee)
126 | {
127 | forceInlineSizeCache_[func.EventInstanceId()] +=
128 | inlinee.Size();
129 | }
130 |
131 | AnalysisControl OnEndAnalysis() override
132 | {
133 | std::vector sortedFunctions;
134 |
135 | for (auto& p : identifiedFunctions_) {
136 | sortedFunctions.push_back(p.second);
137 | }
138 |
139 | std::sort(sortedFunctions.begin(), sortedFunctions.end());
140 |
141 | for (auto& func : sortedFunctions)
142 | {
143 | bool forceInlineHeavy = func.ForceInlineeSize >= 10000;
144 |
145 | std::string forceInlineIndicator = forceInlineHeavy ?
146 | ", *" : "";
147 |
148 | int percent = static_cast(func.Percent * 100);
149 |
150 | std::string percentString = "(" +
151 | std::to_string(percent) + "%" +
152 | forceInlineIndicator + ")";
153 |
154 | std::cout << std::setw(9) << std::right <<
155 | func.Duration.count();
156 | std::cout << " ms ";
157 | std::cout << std::setw(9) << std::left <<
158 | percentString;
159 | std::cout << " " << func.Name << std::endl;
160 | }
161 |
162 | return AnalysisControl::CONTINUE;
163 | }
164 |
165 | private:
166 | unsigned pass_;
167 |
168 | std::unordered_map cachedInvocationDurations_;
170 |
171 | std::unordered_map identifiedFunctions_;
173 |
174 | std::unordered_map forceInlineSizeCache_;
176 | };
177 |
178 | int main(int argc, char* argv[])
179 | {
180 | if (argc <= 1) return -1;
181 |
182 | std::cout.imbue(std::locale(""));
183 |
184 | FunctionBottlenecks fb;
185 |
186 | auto group = MakeStaticAnalyzerGroup(&fb);
187 |
188 | // argv[1] should contain the path to a trace file
189 | int numberOfPasses = 2;
190 | return Analyze(argv[1], numberOfPasses, group);
191 | }
--------------------------------------------------------------------------------
/CAToolsetPerfDataCollector/PerfDataCollector.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include