├── 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 | ![License](https://img.shields.io/badge/license-MIT-green.svg) 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 | ![License](https://img.shields.io/badge/license-MIT-green.svg) 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 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | // Please refer to main.cpp file for terms / acronyms used in this file. 12 | 13 | using namespace Microsoft::Cpp::BuildInsights; 14 | using namespace Activities; 15 | using namespace SimpleEvents; 16 | using namespace std::chrono; 17 | 18 | struct PathId 19 | { 20 | int id; 21 | const std::wstring* path; 22 | 23 | constexpr auto operator<=>(const PathId& b) const { return *path <=> *b.path; }; 24 | }; 25 | 26 | struct PerfData 27 | { 28 | // Notes on FrontEndPass, CodeAnalysisPass, and BackEndPass: 29 | // - FrontEndPass can be omitted if /analyze:only is used. In that case, the CodeAnalysisPass is the only pass. 30 | // - CodeAnalysisPass is a special FrontEndPass for Code Analysis when /analyze option is used, and includes actual analysis of code. 31 | // - BackEndPass can be omitted if /c and/or /analyze:only is used. 32 | microseconds FEPass; // FrontEnd pass 33 | microseconds BEPass; // BackEnd pass 34 | microseconds CAPass; // CodeAnalysis pass 35 | microseconds ASTCreation; // AST creation for Code Analysis 36 | microseconds ASTClients; // COM clients for Code Analysis, including PREfast 37 | microseconds CAFunction; // PREfast's Code Analysis of functions, including analysis of function by all of its plug-ins 38 | microseconds FPAFunction; // PREfast's path-sensitive Code Analysis of functions (FPA = Function Path Analysis) 39 | microseconds EspXCfgBuild; // CFG Building for functions to be used by EspXEngine and its extensions 40 | microseconds EspXAllChecks; // Analysis of functions by EspXEngine and its extensions 41 | microseconds EspXPathSensitiveChecks; // Path-sensitive analysis of functions by EspXEngine and its extensions 42 | 43 | // This header is used to print the performance data to the console. 44 | // It should be updated if the PerfData struct is updated. 45 | // Note that this header does not include the file path, which should be printed separately if needed. 46 | static constexpr std::wstring_view PerfDataHeader = 47 | L"Front End Pass, BackEnd Pass, Code Analysis Pass, " 48 | L"AST Creation, AST Clients, " // Children of CodeAnalysis Pass 49 | L"Function Analysis, " // Child of AST Clients 50 | L"FPA Function Analysis, EspX CFG Build, EspX Function Analysis, " // Children of Function Analysis 51 | L"EspX Path-sensitive Analysis"; // Child of EspX Function Analysis 52 | }; 53 | 54 | class PerfDataCollector : public IAnalyzer 55 | { 56 | private: 57 | std::unordered_map filePaths{}; // List of file paths 58 | std::map perfDataPerTu{}; // Performance data per TU 59 | 60 | // Find the PathId for the given file path. 61 | // If the file path is not found, a new PathId is created. 62 | PathId& FindFilePathId(std::wstring path) 63 | { 64 | static int id = 0; 65 | auto result = filePaths.try_emplace(path, PathId{}); 66 | if (result.second) 67 | { 68 | result.first->second.id = id++; 69 | result.first->second.path = &result.first->first; 70 | } 71 | return result.first->second; 72 | } 73 | 74 | // Gets duration of the specified compiler pass (should be one of FE, BE, and CA pass), 75 | // finds or adds performance data for the file path, and adds the duration to the specified field 76 | // of the performance data. 77 | template 78 | void GetPassDuration(TPass pass) 79 | { 80 | static_assert(std::is_base_of_v, "TPass must be derived from CompilerPass"); 81 | 82 | const auto tuPathId = FindFilePathId(pass.InputSourcePath()); 83 | 84 | if (verbose_) 85 | { 86 | std::wcout << L"[" << *tuPathId.path << L"](" << pass.EventName() << L") = " 87 | << std::chrono::duration_cast(pass.Duration()).count() << L"(microsec)" << std::endl; 88 | } 89 | 90 | auto& data = perfDataPerTu[tuPathId]; 91 | data.*RecField += std::chrono::duration_cast(pass.Duration()); 92 | } 93 | 94 | // Gets duration of the specified CA activity (should be a descendent of CA Pass), 95 | // finds performance data for the file path, and adds the duration to the specified field 96 | // of the performance data. 97 | template 98 | void GetCodeAnalysisEventDuration(CodeAnalysisPass pass, TEvent event) 99 | { 100 | static_assert(std::is_base_of_v, "TEvent must be derived from Activity"); 101 | 102 | const auto tuPathId = FindFilePathId(pass.InputSourcePath()); 103 | 104 | if (verbose_) 105 | { 106 | std::wcout << L"[" << *tuPathId.path << L"](" << event.EventName() << L") = " 107 | << std::chrono::duration_cast(event.Duration()).count() << L"(microsec)" << std::endl; 108 | } 109 | 110 | auto& data = perfDataPerTu[tuPathId]; 111 | data.*RecField += std::chrono::duration_cast(event.Duration()); 112 | } 113 | 114 | bool verbose_; 115 | 116 | public: 117 | 118 | PerfDataCollector(bool verbose) 119 | : verbose_(verbose) 120 | { 121 | } 122 | 123 | // Called by the analysis driver every time an activity stop event is seen in the trace. 124 | AnalysisControl OnStopActivity(const EventStack& eventStack) override; 125 | 126 | // Prints the per-TU performance data in CSV format. 127 | void PrintRecords(); 128 | 129 | // Print the summary of the performance data. 130 | void PrintSummary(); 131 | }; 132 | 133 | -------------------------------------------------------------------------------- /RecursiveTemplateInspector/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace Microsoft::Cpp::BuildInsights; 11 | using namespace Activities; 12 | using namespace SimpleEvents; 13 | 14 | class RecursiveTemplateInspector : public IAnalyzer 15 | { 16 | struct TemplateSpecializationInfo 17 | { 18 | std::chrono::nanoseconds TotalInstantiationTime; 19 | size_t InstantiationCount; 20 | size_t MaxDepth; 21 | std::string RootSpecializationName; 22 | std::wstring File; 23 | 24 | std::unordered_set VisitedInstantiations; 25 | 26 | bool operator<(const TemplateSpecializationInfo& other) const { 27 | return TotalInstantiationTime > other.TotalInstantiationTime; 28 | } 29 | }; 30 | 31 | public: 32 | RecursiveTemplateInspector(int specializationCountToDump): 33 | specializationCountToDump_{ 34 | specializationCountToDump > 0 ? specializationCountToDump : 5 } 35 | { 36 | } 37 | 38 | AnalysisControl OnStopActivity(const EventStack& eventStack) 39 | override 40 | { 41 | MatchEventStackInMemberFunction(eventStack, this, 42 | &RecursiveTemplateInspector::OnTemplateRecursionTreeBranch); 43 | 44 | return AnalysisControl::CONTINUE; 45 | } 46 | 47 | AnalysisControl OnSimpleEvent(const EventStack& eventStack) 48 | override 49 | { 50 | MatchEventStackInMemberFunction(eventStack, this, 51 | &RecursiveTemplateInspector::OnSymbolName); 52 | 53 | return AnalysisControl::CONTINUE; 54 | } 55 | 56 | void OnTemplateRecursionTreeBranch(FrontEndPass fe, 57 | TemplateInstantiationGroup recursionTreeBranch) 58 | { 59 | const TemplateInstantiation& root = recursionTreeBranch[0]; 60 | const TemplateInstantiation& current = recursionTreeBranch.Back(); 61 | 62 | auto& info = rootSpecializations_[root.SpecializationSymbolKey()]; 63 | 64 | auto& visitedSet = info.VisitedInstantiations; 65 | 66 | if (visitedSet.find(current.EventInstanceId()) == visitedSet.end()) 67 | { 68 | // We have a new unvisited branch. Update the max depth of the 69 | // recursion tree. 70 | 71 | info.MaxDepth = std::max(info.MaxDepth, recursionTreeBranch.Size()); 72 | 73 | for (size_t idx = recursionTreeBranch.Size(); idx-- > 0;) 74 | { 75 | const TemplateInstantiation& ti = recursionTreeBranch[idx]; 76 | 77 | auto p = visitedSet.insert(ti.EventInstanceId()); 78 | 79 | bool wasVisited = !p.second; 80 | 81 | if (wasVisited) 82 | { 83 | // Stop once we reach a visited template instantiation, 84 | // because its parents will also have been visited. 85 | break; 86 | } 87 | 88 | ++info.InstantiationCount; 89 | } 90 | } 91 | 92 | if (recursionTreeBranch.Size() != 1) { 93 | return; 94 | } 95 | 96 | // The end of a hierarchy's instantiation corresponds to the stop 97 | // event of the root specialization's instantiation. When we reach 98 | // that point, we update the total instantiation time of the hierarchy. 99 | 100 | info.TotalInstantiationTime = root.Duration(); 101 | 102 | info.File = fe.InputSourcePath() ? fe.InputSourcePath() : 103 | fe.OutputObjectPath(); 104 | 105 | visitedSet.clear(); 106 | } 107 | 108 | void OnSymbolName(SymbolName symbolName) 109 | { 110 | auto it = rootSpecializations_.find(symbolName.Key()); 111 | 112 | if (it == rootSpecializations_.end()) { 113 | return; 114 | } 115 | 116 | it->second.RootSpecializationName = symbolName.Name(); 117 | } 118 | 119 | AnalysisControl OnEndAnalysis() override 120 | { 121 | using namespace std::chrono; 122 | 123 | auto topSpecializations = GetTopInstantiations(); 124 | 125 | if (specializationCountToDump_ == 1) { 126 | std::cout << "Top template instantiation hierarchy:"; 127 | } 128 | else { 129 | std::cout << "Top " << specializationCountToDump_ << 130 | " template instantiation " << "hierarchies"; 131 | } 132 | 133 | std::cout << std::endl << std::endl; 134 | 135 | for (auto& info : topSpecializations) 136 | { 137 | std::wcout << "File: " << 138 | info.File << std::endl; 139 | std::cout << "Duration: " << 140 | duration_cast( 141 | info.TotalInstantiationTime).count() << 142 | " ms" << std::endl; 143 | std::cout << "Max Depth: " << 144 | info.MaxDepth << std::endl; 145 | std::cout << "Instantiations: " << 146 | info.InstantiationCount << std::endl; 147 | std::cout << "Root Name: " << 148 | info.RootSpecializationName << std::endl << std::endl; 149 | } 150 | 151 | return AnalysisControl::CONTINUE; 152 | } 153 | 154 | private: 155 | std::multiset GetTopInstantiations() 156 | { 157 | std::multiset topSpecializations; 158 | 159 | for (auto& p : rootSpecializations_) 160 | { 161 | if (topSpecializations.size() < specializationCountToDump_) { 162 | topSpecializations.insert(p.second); 163 | } 164 | else 165 | { 166 | auto itLast = --topSpecializations.end(); 167 | 168 | if (p.second.TotalInstantiationTime >= 169 | itLast->TotalInstantiationTime) 170 | { 171 | topSpecializations.erase(itLast); 172 | topSpecializations.insert(p.second); 173 | } 174 | } 175 | } 176 | 177 | return topSpecializations; 178 | } 179 | 180 | // A hash table that stores information about template instantiations 181 | // that are at the root of a recursive instantiation hierarchy. 182 | std::unordered_map rootSpecializations_; 183 | 184 | int specializationCountToDump_; 185 | }; 186 | 187 | int main(int argc, char* argv[]) 188 | { 189 | if (argc <= 1) return -1; 190 | 191 | int specializationCountToDump = 0; 192 | 193 | if (argc >= 3) { 194 | specializationCountToDump = std::atoi(argv[2]); 195 | } 196 | 197 | RecursiveTemplateInspector rti{specializationCountToDump}; 198 | 199 | auto group = MakeStaticAnalyzerGroup(&rti); 200 | 201 | // argv[1] should contain the path to a trace file 202 | int numberOfPasses = 1; 203 | return Analyze(argv[1], numberOfPasses, group); 204 | } -------------------------------------------------------------------------------- /CAToolsetPerfDataCollector/main.cpp: -------------------------------------------------------------------------------- 1 | #include "PerfDataCollector.h" 2 | #include 3 | #include 4 | 5 | // In this project, we use the following terms / acronyms throughout the project: 6 | // - FE: Front End 7 | // - BE: Back End 8 | // - CA: Code Analysis 9 | // - AST: Abstract Syntax Tree 10 | // - CFG: Control Flow Graph 11 | // - PREfast: Main driver of Code Analysis 12 | // - PREfast Plug-ins: Clients of PREfast that can process / analyze ASTs 13 | // - PREfast FPA: PREfast's built in checker that performs path-sensitive analysis 14 | // - EspXEngine: Main PREfast plug-in that drives other checker extensions 15 | // - EspXEngine Extensions: Clients of EspXEngine that can process / analyze CFGs 16 | // - EspXEngine Path-sensitive Checks: EspXEngine's built-in or extensions that perform perform path-sensitive analysis 17 | 18 | enum class OutputFormat 19 | { 20 | Summary, // Summary only. Default format 21 | CSV, // CSV output of per-TU performance data 22 | Both // Both Summary and CSV. Summary will be printed first. 23 | }; 24 | 25 | struct Options 26 | { 27 | bool verbose{}; // Verbose output 28 | OutputFormat outputFormat{}; // Output format, defaults to OptputFormat::Summary 29 | std::vector traceFilePaths{}; // Paths to the trace files to process 30 | 31 | void PrintUsage(const char* programName) 32 | { 33 | std::filesystem::path path{ programName }; 34 | std::wcout << L"Usage: " << path.replace_extension().filename() 35 | << L" [-v[erbose]] [-f[ormat]:Summary|CSV|Both]] \n" 36 | << L" -v[erbose] : Print verbose output. Optional.\n" 37 | << L" -f[ormat]: : Output format (Summary, CSV, or Both). Optional. Defaults to Summary.\n" 38 | << L" : Paths to one or more ETW trace files, separated by space. Required.\n" 39 | << L"Option names and values are case-insensitive." << std::endl; 40 | } 41 | 42 | // Returns zero if the program should continue, non-zero if it should exit. 43 | int ParseCommandLine(int argc, char* argv[]) 44 | { 45 | if (argc < 2) 46 | { 47 | PrintUsage(argv[0]); 48 | return -1; 49 | } 50 | 51 | auto filePathArgIndex = 1; 52 | 53 | for (int i = 1; i < argc; ++i) 54 | { 55 | const auto arg = argv[i]; 56 | if (strlen(arg) < 2 || !(arg[0] == '-' || arg[0] == '/')) 57 | { 58 | continue; 59 | } 60 | 61 | if (_stricmp(&arg[1], "v") == 0 || _stricmp(&arg[1], "verbose") == 0) 62 | { 63 | verbose = true; 64 | ++filePathArgIndex; 65 | } 66 | else if (_strnicmp(&arg[1], "f:", 2) == 0 || _strnicmp(&arg[1], "format:", 7) == 0) 67 | { 68 | auto formatArgOffset = 3; 69 | if (arg[2] == 'o' || arg[2] == 'O') 70 | formatArgOffset += 5; 71 | if (strlen(&arg[formatArgOffset]) == 0) 72 | { 73 | std::wcerr << L"Output format is not specified." << std::endl; 74 | return -1; 75 | } 76 | 77 | // Get output format 78 | if (_stricmp(&arg[formatArgOffset], "summary") == 0) 79 | { 80 | outputFormat = OutputFormat::Summary; 81 | } 82 | else if (_stricmp(&arg[formatArgOffset], "csv") == 0) 83 | { 84 | outputFormat = OutputFormat::CSV; 85 | } 86 | else if (_stricmp(&arg[formatArgOffset], "both") == 0) 87 | { 88 | outputFormat = OutputFormat::Both; 89 | } 90 | else 91 | { 92 | std::wcerr << L"Unknown output format: " << &arg[formatArgOffset] << std::endl; 93 | return -1; 94 | } 95 | ++filePathArgIndex; 96 | } 97 | else if (_stricmp(&arg[1], "h") == 0 || _stricmp(&arg[1], "help") == 0) 98 | { 99 | PrintUsage(argv[0]); 100 | return 0; 101 | } 102 | else 103 | { 104 | std::wcerr << L"Unknown option: " << arg << std::endl; 105 | return -1; 106 | } 107 | } 108 | 109 | if (argc <= filePathArgIndex) 110 | { 111 | PrintUsage(argv[0]); 112 | return -1; 113 | } 114 | 115 | for (int i = filePathArgIndex; i < argc; ++i) 116 | { 117 | auto filePath = argv[i]; 118 | 119 | // Check the path to the trace file 120 | if (!std::filesystem::exists(filePath)) 121 | { 122 | std::wcerr << L"File not found: " << filePath << std::endl; 123 | return -1; 124 | } 125 | 126 | traceFilePaths.push_back(filePath); 127 | } 128 | 129 | return 0; 130 | } 131 | }; 132 | 133 | int main(int argc, char *argv[]) 134 | { 135 | Options options; 136 | if (const auto result = options.ParseCommandLine(argc, argv); result != 0) 137 | return result; 138 | 139 | PerfDataCollector perfDataCollector(options.verbose); 140 | 141 | auto analyzers = MakeStaticAnalyzerGroup(&perfDataCollector); 142 | 143 | assert(!options.traceFilePaths.empty()); 144 | for (auto traceFilePath : options.traceFilePaths) 145 | { 146 | std::wcout << L"Analyzing " << traceFilePath << L"..." << std::endl; 147 | 148 | constexpr int NumberOfPasses = 1; 149 | const auto result = Analyze(traceFilePath, NumberOfPasses, analyzers); 150 | if (result != RESULT_CODE_SUCCESS) 151 | { 152 | std::wcerr << L"Failed to analyze the trace file \"" << traceFilePath << L"\": "; 153 | 154 | switch (result) 155 | { 156 | case RESULT_CODE_FAILURE_DROPPED_EVENTS: 157 | std::wcerr << L"Log is missing some important events." << std::endl; 158 | break; 159 | case RESULT_CODE_FAILURE_INVALID_INPUT_LOG_FILE: 160 | std::wcerr << L"Input log file is invalid." << std::endl; 161 | break; 162 | case RESULT_CODE_FAILURE_NO_CONTEXT_INFO_AVAILABLE: 163 | std::wcerr << L"Failed to get context information from the trace file." << std::endl; 164 | break; 165 | default: 166 | std::wcerr << L"Error Code = " << static_cast(result) << std::endl; 167 | break; 168 | } 169 | 170 | return -1; 171 | } 172 | } 173 | 174 | // Print Summary, CSV, or both as requested. 175 | switch (options.outputFormat) 176 | { 177 | case OutputFormat::Summary: 178 | perfDataCollector.PrintSummary(); 179 | break; 180 | case OutputFormat::CSV: 181 | perfDataCollector.PrintRecords(); 182 | break; 183 | case OutputFormat::Both: 184 | perfDataCollector.PrintSummary(); 185 | std::wcout << L"\n\n"; 186 | perfDataCollector.PrintRecords(); 187 | break; 188 | default: 189 | break; // Should not be reached 190 | } 191 | 192 | return 0; 193 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | 352 | # vscode settings 353 | .vscode/ 354 | -------------------------------------------------------------------------------- /Samples.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29806.167 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LongCodeGenFinder", "LongCodeGenFinder\LongCodeGenFinder.vcxproj", "{0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BottleneckCompileFinder", "BottleneckCompileFinder\BottleneckCompileFinder.vcxproj", "{771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RecursiveTemplateInspector", "RecursiveTemplateInspector\RecursiveTemplateInspector.vcxproj", "{2F8A1B93-522E-449E-A7E2-2AFC0910DF48}" 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TopHeaders", "TopHeaders\TopHeaders.vcxproj", "{A99D36F8-E953-4C59-AD45-93597900CAFF}" 13 | EndProject 14 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FunctionBottlenecks", "FunctionBottlenecks\FunctionBottlenecks.vcxproj", "{F002C795-7D92-4146-8A7C-BBEB946F4309}" 15 | EndProject 16 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LongModuleFinder", "LongModuleFinder\LongModuleFinder.vcxproj", "{1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}" 17 | EndProject 18 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LongPrecompiledHeaderFinder", "LongPrecompiledHeaderFinder\LongPrecompiledHeaderFinder.vcxproj", "{691B8829-AE90-4E85-B809-45D714F66CC0}" 19 | EndProject 20 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LongHeaderUnitFinder", "LongHeaderUnitFinder\LongHeaderUnitFinder.vcxproj", "{F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}" 21 | EndProject 22 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CAToolsetPerfDataCollector", "CAToolsetPerfDataCollector\CAToolsetPerfDataCollector.vcxproj", "{E58C0F2E-6D89-44B2-8E65-C5A60B52A295}" 23 | EndProject 24 | Global 25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 26 | Debug|x64 = Debug|x64 27 | Debug|x86 = Debug|x86 28 | Release|x64 = Release|x64 29 | Release|x86 = Release|x86 30 | EndGlobalSection 31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 32 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Debug|x64.ActiveCfg = Debug|x64 33 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Debug|x64.Build.0 = Debug|x64 34 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Debug|x86.ActiveCfg = Debug|Win32 35 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Debug|x86.Build.0 = Debug|Win32 36 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Release|x64.ActiveCfg = Release|x64 37 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Release|x64.Build.0 = Release|x64 38 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Release|x86.ActiveCfg = Release|Win32 39 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Release|x86.Build.0 = Release|Win32 40 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Debug|x64.ActiveCfg = Debug|x64 41 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Debug|x64.Build.0 = Debug|x64 42 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Debug|x86.ActiveCfg = Debug|Win32 43 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Debug|x86.Build.0 = Debug|Win32 44 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Release|x64.ActiveCfg = Release|x64 45 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Release|x64.Build.0 = Release|x64 46 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Release|x86.ActiveCfg = Release|Win32 47 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Release|x86.Build.0 = Release|Win32 48 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Debug|x64.ActiveCfg = Debug|x64 49 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Debug|x64.Build.0 = Debug|x64 50 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Debug|x86.ActiveCfg = Debug|Win32 51 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Debug|x86.Build.0 = Debug|Win32 52 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Release|x64.ActiveCfg = Release|x64 53 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Release|x64.Build.0 = Release|x64 54 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Release|x86.ActiveCfg = Release|Win32 55 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Release|x86.Build.0 = Release|Win32 56 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Debug|x64.ActiveCfg = Debug|x64 57 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Debug|x64.Build.0 = Debug|x64 58 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Debug|x86.ActiveCfg = Debug|Win32 59 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Debug|x86.Build.0 = Debug|Win32 60 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Release|x64.ActiveCfg = Release|x64 61 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Release|x64.Build.0 = Release|x64 62 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Release|x86.ActiveCfg = Release|Win32 63 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Release|x86.Build.0 = Release|Win32 64 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Debug|x64.ActiveCfg = Debug|x64 65 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Debug|x64.Build.0 = Debug|x64 66 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Debug|x86.ActiveCfg = Debug|Win32 67 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Debug|x86.Build.0 = Debug|Win32 68 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Release|x64.ActiveCfg = Release|x64 69 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Release|x64.Build.0 = Release|x64 70 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Release|x86.ActiveCfg = Release|Win32 71 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Release|x86.Build.0 = Release|Win32 72 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Debug|x64.ActiveCfg = Debug|x64 73 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Debug|x64.Build.0 = Debug|x64 74 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Debug|x86.ActiveCfg = Debug|Win32 75 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Debug|x86.Build.0 = Debug|Win32 76 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Release|x64.ActiveCfg = Release|x64 77 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Release|x64.Build.0 = Release|x64 78 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Release|x86.ActiveCfg = Release|Win32 79 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Release|x86.Build.0 = Release|Win32 80 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Debug|x64.ActiveCfg = Debug|x64 81 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Debug|x64.Build.0 = Debug|x64 82 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Debug|x86.ActiveCfg = Debug|Win32 83 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Debug|x86.Build.0 = Debug|Win32 84 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Release|x64.ActiveCfg = Release|x64 85 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Release|x64.Build.0 = Release|x64 86 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Release|x86.ActiveCfg = Release|Win32 87 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Release|x86.Build.0 = Release|Win32 88 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Debug|x64.ActiveCfg = Debug|x64 89 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Debug|x64.Build.0 = Debug|x64 90 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Debug|x86.ActiveCfg = Debug|Win32 91 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Debug|x86.Build.0 = Debug|Win32 92 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Release|x64.ActiveCfg = Release|x64 93 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Release|x64.Build.0 = Release|x64 94 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Release|x86.ActiveCfg = Release|Win32 95 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Release|x86.Build.0 = Release|Win32 96 | {E58C0F2E-6D89-44B2-8E65-C5A60B52A295}.Debug|x64.ActiveCfg = Debug|x64 97 | {E58C0F2E-6D89-44B2-8E65-C5A60B52A295}.Debug|x64.Build.0 = Debug|x64 98 | {E58C0F2E-6D89-44B2-8E65-C5A60B52A295}.Debug|x86.ActiveCfg = Debug|Win32 99 | {E58C0F2E-6D89-44B2-8E65-C5A60B52A295}.Debug|x86.Build.0 = Debug|Win32 100 | {E58C0F2E-6D89-44B2-8E65-C5A60B52A295}.Release|x64.ActiveCfg = Release|x64 101 | {E58C0F2E-6D89-44B2-8E65-C5A60B52A295}.Release|x64.Build.0 = Release|x64 102 | {E58C0F2E-6D89-44B2-8E65-C5A60B52A295}.Release|x86.ActiveCfg = Release|Win32 103 | {E58C0F2E-6D89-44B2-8E65-C5A60B52A295}.Release|x86.Build.0 = Release|Win32 104 | EndGlobalSection 105 | GlobalSection(SolutionProperties) = preSolution 106 | HideSolutionNode = FALSE 107 | EndGlobalSection 108 | GlobalSection(ExtensibilityGlobals) = postSolution 109 | SolutionGuid = {24E22F67-89F7-404A-99B5-BBD9D945B0CD} 110 | EndGlobalSection 111 | EndGlobal 112 | -------------------------------------------------------------------------------- /TopHeaders/TopHeaders.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {A99D36F8-E953-4C59-AD45-93597900CAFF} 24 | TopHeaders 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v143 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v143 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v143 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v143 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | false 74 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 75 | 76 | 77 | true 78 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 79 | 80 | 81 | true 82 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 83 | 84 | 85 | false 86 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 87 | 88 | 89 | 90 | Level3 91 | true 92 | true 93 | true 94 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 95 | true 96 | 97 | 98 | Console 99 | true 100 | true 101 | true 102 | 103 | 104 | 105 | 106 | Level3 107 | true 108 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 109 | true 110 | 111 | 112 | Console 113 | true 114 | 115 | 116 | 117 | 118 | Level3 119 | true 120 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | true 122 | 123 | 124 | Console 125 | true 126 | 127 | 128 | 129 | 130 | Level3 131 | true 132 | true 133 | true 134 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 135 | true 136 | 137 | 138 | Console 139 | true 140 | true 141 | true 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /RecursiveTemplateInspector/RecursiveTemplateInspector.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48} 24 | RecursiveTemplateInspector 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v143 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v143 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v143 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v143 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | false 74 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 75 | 76 | 77 | true 78 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 79 | 80 | 81 | true 82 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 83 | 84 | 85 | false 86 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 87 | 88 | 89 | 90 | Level3 91 | true 92 | true 93 | true 94 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 95 | true 96 | 97 | 98 | Console 99 | true 100 | true 101 | true 102 | 103 | 104 | 105 | 106 | Level3 107 | true 108 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 109 | true 110 | 111 | 112 | Console 113 | true 114 | 115 | 116 | 117 | 118 | Level3 119 | true 120 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | true 122 | 123 | 124 | Console 125 | true 126 | 127 | 128 | 129 | 130 | Level3 131 | true 132 | true 133 | true 134 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 135 | true 136 | 137 | 138 | Console 139 | true 140 | true 141 | true 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /LongModuleFinder/LongModuleFinder.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {1149112d-c4e7-4cc7-b9c7-2aed3a159f8e} 24 | LongModuleFinder 25 | 10.0 26 | LongModuleFinder 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 76 | 77 | 78 | true 79 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 80 | 81 | 82 | false 83 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 84 | 85 | 86 | false 87 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 88 | 89 | 90 | 91 | Level3 92 | true 93 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 95 | 96 | 97 | Console 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | true 118 | true 119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | true 126 | true 127 | 128 | 129 | 130 | 131 | Level3 132 | true 133 | true 134 | true 135 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 136 | true 137 | 138 | 139 | Console 140 | true 141 | true 142 | true 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /LongCodeGenFinder/LongCodeGenFinder.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1} 24 | LongCodeGenFinder 25 | 10.0 26 | LongCodeGenFinder 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 76 | 77 | 78 | true 79 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 80 | 81 | 82 | false 83 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 84 | 85 | 86 | false 87 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 88 | 89 | 90 | 91 | Level3 92 | true 93 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 95 | 96 | 97 | Console 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | true 118 | true 119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | true 126 | true 127 | 128 | 129 | 130 | 131 | Level3 132 | true 133 | true 134 | true 135 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 136 | true 137 | 138 | 139 | Console 140 | true 141 | true 142 | true 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /FunctionBottlenecks/FunctionBottlenecks.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {F002C795-7D92-4146-8A7C-BBEB946F4309} 24 | FunctionBottlenecks 25 | 10.0 26 | FunctionBottlenecks 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 76 | 77 | 78 | true 79 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 80 | 81 | 82 | false 83 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 84 | 85 | 86 | false 87 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 88 | 89 | 90 | 91 | Level3 92 | true 93 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 95 | 96 | 97 | Console 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | true 118 | true 119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | true 126 | true 127 | 128 | 129 | 130 | 131 | Level3 132 | true 133 | true 134 | true 135 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 136 | true 137 | 138 | 139 | Console 140 | true 141 | true 142 | true 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /LongHeaderUnitFinder/LongHeaderUnitFinder.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {f16c04c7-7f1b-4d43-b9c3-156d27d0cd5b} 24 | LongHeaderUnitFinder 25 | 10.0 26 | LongHeaderUnitFinder 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 76 | 77 | 78 | true 79 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 80 | 81 | 82 | false 83 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 84 | 85 | 86 | false 87 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 88 | 89 | 90 | 91 | Level3 92 | true 93 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 95 | 96 | 97 | Console 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | true 118 | true 119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | true 126 | true 127 | 128 | 129 | 130 | 131 | Level3 132 | true 133 | true 134 | true 135 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 136 | true 137 | 138 | 139 | Console 140 | true 141 | true 142 | true 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /BottleneckCompileFinder/BottleneckCompileFinder.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D} 24 | BottleneckCompileFinder 25 | 10.0 26 | BottleneckCompileFinder 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 76 | 77 | 78 | true 79 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 80 | 81 | 82 | false 83 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 84 | 85 | 86 | false 87 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 88 | 89 | 90 | 91 | Level3 92 | true 93 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 95 | 96 | 97 | Console 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | true 118 | true 119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | true 126 | true 127 | 128 | 129 | 130 | 131 | Level3 132 | true 133 | true 134 | true 135 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 136 | true 137 | 138 | 139 | Console 140 | true 141 | true 142 | true 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /LongPrecompiledHeaderFinder/LongPrecompiledHeaderFinder.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {691b8829-ae90-4e85-b809-45d714f66cc0} 24 | LongPrecompiledHeaderFinder 25 | 10.0 26 | LongPrecompiledHeaderFinder 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 76 | 77 | 78 | true 79 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 80 | 81 | 82 | false 83 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 84 | 85 | 86 | false 87 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 88 | 89 | 90 | 91 | Level3 92 | true 93 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 95 | 96 | 97 | Console 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | true 118 | true 119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | true 126 | true 127 | 128 | 129 | 130 | 131 | Level3 132 | true 133 | true 134 | true 135 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 136 | true 137 | 138 | 139 | Console 140 | true 141 | true 142 | true 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /CAToolsetPerfDataCollector/CAToolsetPerfDataCollector.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {E58C0F2E-6D89-44B2-8E65-C5A60B52A295} 24 | CAToolsetPerfDataCollector 25 | 10.0 26 | CodeAnalysisPerfDataCollector 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 76 | 77 | 78 | true 79 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 80 | 81 | 82 | false 83 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 84 | 85 | 86 | false 87 | $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ 88 | 89 | 90 | 91 | Level3 92 | true 93 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 95 | stdcpp20 96 | 97 | 98 | Console 99 | true 100 | 101 | 102 | 103 | 104 | Level3 105 | true 106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | true 108 | stdcpp20 109 | 110 | 111 | Console 112 | true 113 | comsuppw.lib;%(AdditionalDependencies) 114 | 115 | 116 | 117 | 118 | Level3 119 | true 120 | true 121 | true 122 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 123 | true 124 | stdcpp20 125 | 126 | 127 | Console 128 | true 129 | true 130 | true 131 | 132 | 133 | 134 | 135 | Level3 136 | true 137 | true 138 | true 139 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 140 | true 141 | stdcpp20 142 | 143 | 144 | Console 145 | true 146 | true 147 | true 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /CAToolsetPerfDataCollector/PerfDataCollector.cpp: -------------------------------------------------------------------------------- 1 | #include "PerfDataCollector.h" 2 | #include 3 | 4 | // Please refer to main.cpp file for terms / acronyms used in this file. 5 | 6 | AnalysisControl PerfDataCollector::OnStopActivity(const EventStack& eventStack) 7 | { 8 | // 9 | // Overall C1, C1/analyze, C1 Passes 10 | // 11 | 12 | // FE Pass 13 | MatchEventStackInMemberFunction(eventStack, this, 14 | &PerfDataCollector::GetPassDuration); 15 | // CA Pass 16 | MatchEventStackInMemberFunction(eventStack, this, 17 | &PerfDataCollector::GetPassDuration); 18 | // BE Pass 19 | MatchEventStackInMemberFunction(eventStack, this, 20 | &PerfDataCollector::GetPassDuration); 21 | 22 | // 23 | // Activities in FE during CA Pass 24 | // 25 | 26 | // AST Creation 27 | MatchEventStackInMemberFunction(eventStack, this, 28 | &PerfDataCollector::GetCodeAnalysisEventDuration); 29 | // AST Clients, e.g., PREfast 30 | MatchEventStackInMemberFunction(eventStack, this, 31 | &PerfDataCollector::GetCodeAnalysisEventDuration); 32 | 33 | // 34 | // Activities in PREfast during CA Pass 35 | // 36 | 37 | // CA PREfast's Function Analysis (including its own plug-ins, EspXEngine, and EspXEngine extensions) 38 | MatchEventStackInMemberFunction(eventStack, this, 39 | &PerfDataCollector::GetCodeAnalysisEventDuration); 40 | // PREfast's FPA Function Analysis (FPA = Function Path Analysis) 41 | MatchEventStackInMemberFunction(eventStack, this, 42 | &PerfDataCollector::GetCodeAnalysisEventDuration); 43 | // EspXEngine's CFG Building 44 | MatchEventStackInMemberFunction(eventStack, this, 45 | &PerfDataCollector::GetCodeAnalysisEventDuration); 46 | // EspXEngine's All Checks (BufferCheck and extensions, whichever are enabled) 47 | MatchEventStackInMemberFunction(eventStack, this, 48 | &PerfDataCollector::GetCodeAnalysisEventDuration); 49 | // EspXEngine's PathSensitiveChecks (BufferCheck and some of the extensions, whichever are enabled) 50 | MatchEventStackInMemberFunction(eventStack, this, 51 | &PerfDataCollector::GetCodeAnalysisEventDuration); 52 | 53 | // Tell the analysis driver to proceed to the next event 54 | return AnalysisControl::CONTINUE; 55 | } 56 | 57 | // Prints the per-TU performance data in CSV format. The first column is the file path. 58 | // The rest of the columns are the performance data in microseconds. 59 | void PerfDataCollector::PrintRecords() 60 | { 61 | constexpr auto allZero = PerfData{}; 62 | 63 | // Print Header 64 | std::wcout << L"File Path, " << PerfData::PerfDataHeader << std::endl; 65 | 66 | for (const auto& [pathId, data] : perfDataPerTu) 67 | { 68 | // If CA Pass is less than FE Pass, it is for files that are not target of Code Analysis, 69 | // or CA Pass is not captured properly - e.g., due to errors only occurring during CA Pass. 70 | // or exceptions during Code Analysis. 71 | // Ignore the record by reporting everything as 0. We still want the TU to be listed. 72 | const auto& d = (data.CAPass < data.FEPass) ? allZero : data; 73 | 74 | std::wcout 75 | << *pathId.path << L", " << d.FEPass.count() << L", " << d.BEPass.count() << L", " << d.CAPass.count() << L", " 76 | << d.ASTCreation.count() << L", " << d.ASTClients.count() << L", " << d.CAFunction.count() << L", " 77 | << d.FPAFunction.count() << L", " << d.EspXCfgBuild.count() << L", " << d.EspXAllChecks.count() << L", " 78 | << d.EspXPathSensitiveChecks.count() << std::endl; 79 | } 80 | } 81 | 82 | // Utility to restore the state of std::wcout 83 | struct WcoutStateRestorer 84 | { 85 | ~WcoutStateRestorer() 86 | { 87 | std::wcout.precision(precision_); 88 | std::wcout.flags(flags_); 89 | } 90 | private: 91 | std::ios_base::fmtflags flags_{ std::wcout.flags() }; 92 | std::streamsize precision_{ std::wcout.precision() }; 93 | }; 94 | 95 | // Represents an indentation printing. Use Indenter to manage indentation level per scope. 96 | template 97 | struct Indent 98 | { 99 | void operator++() { buffer_.append(IndentSize, L' '); } 100 | void operator--() { buffer_.resize(buffer_.size() - IndentSize); } 101 | friend std::wostream& operator<<(std::wostream& out, const Indent& indent) { out << indent.buffer_; return out; } 102 | private: 103 | std::wstring buffer_{ }; 104 | }; 105 | 106 | // Use this to automatically manage indentation level per scope for an instance of Indent. 107 | // For example: 108 | // Indent<2> indent; 109 | // { 110 | // Indenter _{ indent }; 111 | // std::wcout << indent << L"Indented by 2 spaces" << std::endl; 112 | // { 113 | // Indenter _{ indent }; 114 | // std::wcout << indent << L"Indented by 4 spaces" << std::endl; 115 | // } 116 | // std::wcout << indent << L"Indented by 2 spaces" << std::endl; 117 | // } 118 | template 119 | struct Indenter 120 | { 121 | Indenter(Indent& indent) : indent_{ indent } { ++indent_; } 122 | ~Indenter() { --indent_; } 123 | private: 124 | Indent& indent_; 125 | }; 126 | 127 | // Print the summary of the performance data. 128 | // Prints the total execution time for each of the compiler passes and activities in CA Pass. 129 | // Then prints the percentage of each activity. Activities are displayed as children of 130 | // their parent activity. For example, AST Creation and AST Clients are displayed under CA Pass. 131 | // Activities' performance numbers are percentages over their immediate parent activity. 132 | // So, sum of percentages of all siblings should equal to 100%. 133 | // Also prints the number of TUs with CA Pass greater than FE Pass by over 600%, 300%, or 150%. 134 | void PerfDataCollector::PrintSummary() 135 | { 136 | struct Total 137 | { 138 | milliseconds FEPass; // FrontEnd pass 139 | milliseconds CAPass; // CodeAnalysis pass 140 | milliseconds BEPass; // BackEnd pass 141 | milliseconds ASTCreation; // AST creation for Code Analysis 142 | milliseconds ASTClients; // COM clients for Code Analysis, including PREfast 143 | milliseconds CAFunction; // PREfast's Code Analysis of functions, including analysis of function by all of its plug-ins 144 | milliseconds FPAFunction; // PREfast's path-sensitive Code Analysis of functions (FPA = Function Path Analysis) 145 | milliseconds EspXCfgBuild; // CFG Building for functions to be used by EspXEngine and its extensions 146 | milliseconds EspXAllChecks; // Analysis of functions by EspXEngine and its extensions 147 | milliseconds EspXPathSensitiveChecks; // Path-sensitive analysis of functions by EspXEngine and its extensions 148 | } total{}; 149 | 150 | size_t ignoredTUs{}; 151 | size_t TUsWithCAPassGE600Percent{}; 152 | size_t TUsWithCAPassGE300Percent{}; 153 | size_t TUsWithCAPassGE150Percent{}; 154 | 155 | for (const auto& [pathId, data] : perfDataPerTu) 156 | { 157 | // If CA Pass is less than FE Pass, it usually means one of the followings: 158 | // - File type is not something CA analyzes, e.g., an IDL file, etc. 159 | // - CA pass encountered compilation error that only occurs in CA pass 160 | // - CA pass encountered exceptions in early stage, before it spent enough time. 161 | // Ignore the record. 162 | if (data.FEPass > microseconds::zero() && data.CAPass < data.FEPass) 163 | { 164 | ++ignoredTUs; 165 | continue; 166 | } 167 | 168 | total.FEPass += std::chrono::duration_cast(data.FEPass); 169 | total.BEPass += std::chrono::duration_cast(data.BEPass); 170 | total.CAPass += std::chrono::duration_cast(data.CAPass); 171 | total.ASTCreation += std::chrono::duration_cast(data.ASTCreation); 172 | total.ASTClients += std::chrono::duration_cast(data.ASTClients); 173 | total.CAFunction += std::chrono::duration_cast(data.CAFunction); 174 | total.FPAFunction += std::chrono::duration_cast(data.FPAFunction); 175 | total.EspXCfgBuild += std::chrono::duration_cast(data.EspXCfgBuild); 176 | total.EspXAllChecks += std::chrono::duration_cast(data.EspXAllChecks); 177 | total.EspXPathSensitiveChecks += std::chrono::duration_cast(data.EspXPathSensitiveChecks); 178 | 179 | // 180 | // Count important records 181 | // 182 | 183 | // TUs with CA Pass greater than FE Pass by over 600%, 300%, or 150% and more. 184 | if (data.FEPass > microseconds::zero()) 185 | { 186 | const auto ratio = data.CAPass.count() / static_cast(data.FEPass.count()); 187 | if (ratio >= 6.0) 188 | ++TUsWithCAPassGE600Percent; 189 | else if (ratio >= 3.0) 190 | ++TUsWithCAPassGE300Percent; 191 | else if (ratio >= 1.5) 192 | ++TUsWithCAPassGE150Percent; 193 | } 194 | } 195 | 196 | // Output indentation 197 | Indent<2> indent; 198 | 199 | const Indenter _{ indent }; 200 | 201 | // The number of TUs compiled 202 | const auto successfulTUs = perfDataPerTu.size() - ignoredTUs; 203 | std::wcout << L"Number of TUs successfully analyzed: " << successfulTUs << L"\n"; 204 | // The number of TUs ignored due to CA Pass less than FE Pass 205 | if (ignoredTUs > 0) 206 | std::wcout << L"Number of TUs excluded (files not analyzed or had analysis error): " << ignoredTUs << L"\n"; 207 | 208 | // Total Execution Time (milliseconds): 209 | std::wcout << L"Total Execution Time (milliseconds):" << L"\n" 210 | << indent << PerfData::PerfDataHeader << L"\n" 211 | << indent << total.FEPass.count() << L", " << total.BEPass.count() << L", " << total.CAPass.count() << L", " 212 | << total.ASTCreation.count() << L", " << total.ASTClients.count() << L", " << total.CAFunction.count() << L", " 213 | << total.FPAFunction.count() << L", " << total.EspXCfgBuild.count() << L", " << total.EspXAllChecks.count() << L", " 214 | << total.EspXPathSensitiveChecks.count() << std::endl; 215 | 216 | WcoutStateRestorer restorer; 217 | std::wcout << std::fixed << std::setprecision(2); 218 | 219 | // Total pass = FE Pass + CA Pass + BE Pass 220 | const auto totalPass = total.FEPass + total.CAPass + total.BEPass; 221 | if (totalPass == milliseconds::zero()) // Very unlikely, but just in case. 222 | return; 223 | 224 | // Duration of each compiler pass in all compiler passes 225 | const auto totalPassTime = static_cast(totalPass.count()); 226 | std::wcout 227 | << L"Compiler Passes [percentages are \"percentage of parent\" (\"percentage of total\")]:\n" 228 | << indent << L"Front End Pass = " << (total.FEPass.count() / totalPassTime) * 100 << L"%\n" 229 | << indent << L"Back End Pass = " << (total.BEPass.count() / totalPassTime) * 100 << L"%\n" 230 | << indent << L"Code Analysis Pass = " << (total.CAPass.count() / totalPassTime) * 100 << L"%\n"; 231 | if (total.CAPass > milliseconds::zero()) 232 | { 233 | // Duration of each CA Pass activity in CA Pass 234 | const Indenter _{ indent }; 235 | const auto totalCAPassTime = static_cast(total.CAPass.count()); 236 | const auto compilationPlusMisc = (total.CAPass - total.ASTCreation - total.ASTClients).count(); 237 | const auto astCreation = total.ASTCreation.count(); 238 | const auto astClients = total.ASTClients.count(); 239 | std::wcout 240 | << indent << L"Compilation + Miscellaneous = " << (compilationPlusMisc / totalCAPassTime) * 100 241 | << L"% (" << (compilationPlusMisc / totalPassTime) * 100 << L"%)\n" 242 | << indent << L"AST Creation = " << (astCreation / totalCAPassTime) * 100 243 | << L"% (" << (astCreation / totalPassTime) * 100 << L"%)\n" 244 | << indent << L"All AST Clients = " << (astClients / totalCAPassTime) * 100 245 | << L"% (" << (astClients / totalPassTime) * 100 << L"%)\n"; 246 | if (total.ASTClients > milliseconds::zero()) 247 | { 248 | // Duration of activities in PREfast 249 | const Indenter _{ indent }; 250 | const auto allAstClientsTime = static_cast(astClients); 251 | const auto functionAnalysis = total.CAFunction.count(); 252 | const auto misc = astClients - functionAnalysis; 253 | std::wcout 254 | << indent << L"Miscellaneous = " << (misc / allAstClientsTime) * 100 255 | << L"% (" << (misc / totalPassTime) * 100 << L"%)\n" 256 | << indent << L"Function Analysis = " << (functionAnalysis / allAstClientsTime) * 100 257 | << L"% (" << (functionAnalysis / totalPassTime) * 100 << L"%)\n"; 258 | if (total.CAFunction > milliseconds::zero()) 259 | { 260 | // Duration of each component's function analysis in PREfast 261 | const Indenter _{ indent }; 262 | const auto functionAnalysisTime = static_cast(functionAnalysis); 263 | const auto fpaAnalysis = total.FPAFunction.count(); 264 | const auto espxCfgBuilding = total.EspXCfgBuild.count(); 265 | const auto espxAllAnalysis = total.EspXAllChecks.count(); 266 | const auto misc = functionAnalysis - (fpaAnalysis + espxCfgBuilding + espxAllAnalysis); 267 | std::wcout 268 | << indent << L"Miscellaneous = " << (misc / functionAnalysisTime) * 100 269 | << L"% (" << (misc / totalPassTime) * 100 << L"%)\n" 270 | << indent << L"PREfast's Function Path Analysis = " << (fpaAnalysis / functionAnalysisTime) * 100 271 | << L"% (" << (fpaAnalysis / totalPassTime) * 100 << L"%)\n" 272 | << indent << L"EspX CFG Building = " << (espxCfgBuilding / functionAnalysisTime) * 100 273 | << L"% (" << (espxCfgBuilding / totalPassTime) * 100 << L"%)\n" 274 | << indent << L"EspX All Analysis = " << (espxAllAnalysis / functionAnalysisTime) * 100 275 | << L"% (" << (espxAllAnalysis / totalPassTime) * 100 << L"%)\n"; 276 | if (total.EspXAllChecks > milliseconds::zero()) 277 | { 278 | // Duration of path-sensitive vs data-flow function analysis in EspXEngine 279 | const Indenter _{ indent }; 280 | const auto espxFunctionAnalysisTime = static_cast(espxAllAnalysis); 281 | const auto espxPathSensitiveAnalysis = total.EspXPathSensitiveChecks.count(); 282 | const auto espxDfaPlusMisc = espxAllAnalysis - espxPathSensitiveAnalysis; 283 | std::wcout 284 | << indent << L"Path-sensitive Analysis = " << (espxPathSensitiveAnalysis / espxFunctionAnalysisTime) * 100 285 | << L"% (" << (espxPathSensitiveAnalysis / totalPassTime) * 100 << L"%)\n" 286 | << indent << L"Data-flow Analysis + Miscellaneous = " << (espxDfaPlusMisc / espxFunctionAnalysisTime) * 100 287 | << L"% (" << (espxDfaPlusMisc / totalPassTime) * 100 << L"%)\n"; 288 | } 289 | } 290 | } 291 | } 292 | 293 | // Print the number of TUs with CA Pass greater than FE Pass 294 | if (TUsWithCAPassGE600Percent > 0 || TUsWithCAPassGE300Percent > 0 || TUsWithCAPassGE150Percent > 0) 295 | { 296 | const double successfulTUCount = static_cast(successfulTUs); 297 | const auto TUsWithCAPassLT150Percent = 298 | successfulTUs - (TUsWithCAPassGE600Percent + TUsWithCAPassGE300Percent + TUsWithCAPassGE150Percent); 299 | std::wcout << L"Number of TUs with long Code Analysis Pass compared to Front End Pass:\n"; 300 | std::wcout << indent << L"600% or more: " << TUsWithCAPassGE600Percent 301 | << L" (" << (TUsWithCAPassGE600Percent / successfulTUCount) * 100 << "%)\n"; 302 | std::wcout << indent << L"300% or more: " << TUsWithCAPassGE300Percent 303 | << L" (" << (TUsWithCAPassGE300Percent / successfulTUCount) * 100 << "%)\n"; 304 | std::wcout << indent << L"150% or more: " << TUsWithCAPassGE150Percent 305 | << L" (" << (TUsWithCAPassGE150Percent / successfulTUCount) * 100 << "%)\n"; 306 | std::wcout << indent << L"Less than 150%: " << TUsWithCAPassLT150Percent 307 | << L" (" << (TUsWithCAPassLT150Percent / successfulTUCount) * 100 << "%)\n"; 308 | } 309 | 310 | std::wcout.flush(); 311 | } --------------------------------------------------------------------------------