├── .gitignore ├── BottleneckCompileFinder ├── BottleneckCompileFinder.vcxproj ├── BottleneckCompileFinder.vcxproj.filters ├── main.cpp └── packages.config ├── CODE_OF_CONDUCT.md ├── FunctionBottlenecks ├── FunctionBottlenecks.vcxproj ├── FunctionBottlenecks.vcxproj.filters ├── main.cpp └── packages.config ├── LICENSE ├── LongCodeGenFinder ├── LongCodeGenFinder.vcxproj ├── LongCodeGenFinder.vcxproj.filters ├── main.cpp └── packages.config ├── LongHeaderUnitFinder ├── LongHeaderUnitFinder.vcxproj ├── LongHeaderUnitFinder.vcxproj.filters ├── main.cpp └── packages.config ├── LongModuleFinder ├── LongModuleFinder.vcxproj ├── LongModuleFinder.vcxproj.filters ├── main.cpp └── packages.config ├── LongPrecompiledHeaderFinder ├── LongPrecompiledHeaderFinder.vcxproj ├── LongPrecompiledHeaderFinder.vcxproj.filters ├── main.cpp └── packages.config ├── README.md ├── RecursiveTemplateInspector ├── RecursiveTemplateInspector.vcxproj ├── RecursiveTemplateInspector.vcxproj.filters ├── main.cpp └── packages.config ├── SECURITY.md ├── Samples.sln └── TopHeaders ├── TopHeaders.vcxproj ├── TopHeaders.vcxproj.filters ├── main.cpp └── packages.config /.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 | -------------------------------------------------------------------------------- /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 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 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.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/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 | } -------------------------------------------------------------------------------- /BottleneckCompileFinder/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 | -------------------------------------------------------------------------------- /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 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 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.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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /FunctionBottlenecks/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /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/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 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 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.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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /LongCodeGenFinder/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 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.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/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 | } -------------------------------------------------------------------------------- /LongHeaderUnitFinder/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /LongModuleFinder/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 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.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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /LongPrecompiledHeaderFinder/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | | FunctionBottlenecks | Prints a list of functions that are code generation bottlenecks within their CL or Link invocation. | 23 | | LongCodeGenFinder | Lists the functions that take more than 500 milliseconds to generate in your entire build. | 24 | | RecursiveTemplateInspector | Identifies costly recursive template instantiations. | 25 | | TopHeaders | Determines which headers you might want to precompile. | 26 | | 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. | 27 | | 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. | 28 | | 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. | 29 | 30 | ## Prerequisites 31 | 32 | In order to build and run the samples in this repository, you need: 33 | 34 | - Visual Studio 2017 and above. 35 | - Windows 8 and above. 36 | 37 | ## Build steps 38 | 39 | 1. Clone the repository on your machine. 40 | 1. Open the Visual Studio solution file. Each sample is a separate project within the solution. 41 | 1. All samples rely on the C++ Build Insights SDK NuGet package. Restore NuGet packages and accept the license for the SDK. 42 | 1. Build the desired configuration for the samples that interest you. Available platforms are x86 and x64, and available configurations are *Debug* and *Release*. 43 | 1. Samples will be built in their own directory following this formula: `{RepositoryRoot}\out\{SampleName}`. 44 | 45 | ## Running the samples 46 | 47 | 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. 48 | 1. Collect a trace of the build you want to analyze with the sample. You can do this using two methods: 49 | 1. Use vcperf: 50 | 1. Open an elevated x64 Native Tools Command Prompt for VS 2019. 51 | 1. Run the following command: `vcperf /start MySessionName` 52 | 1. Build your project. You do not need to use the same command prompt for building. 53 | 1. Run the following command: `vcperf /stopnoanalyze MySessionName outputTraceFile.etl` 54 | 1. Programmatically: see the [C++ Build Insights SDK](https://docs.microsoft.com/cpp/build-insights/reference/sdk/overview?view=vs-2019) documentation for details. 55 | 1. Invoke the sample, passing your trace as the first parameter. 56 | 57 | ## Contributing 58 | 59 | 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). 60 | 61 | 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. 62 | 63 | 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. 64 | -------------------------------------------------------------------------------- /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 | v142 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v142 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v142 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v142 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.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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /RecursiveTemplateInspector/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | Global 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 24 | Debug|x64 = Debug|x64 25 | Debug|x86 = Debug|x86 26 | Release|x64 = Release|x64 27 | Release|x86 = Release|x86 28 | EndGlobalSection 29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 30 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Debug|x64.ActiveCfg = Debug|x64 31 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Debug|x64.Build.0 = Debug|x64 32 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Debug|x86.ActiveCfg = Debug|Win32 33 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Debug|x86.Build.0 = Debug|Win32 34 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Release|x64.ActiveCfg = Release|x64 35 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Release|x64.Build.0 = Release|x64 36 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Release|x86.ActiveCfg = Release|Win32 37 | {0C9761DD-6792-4F43-8DEF-C0D697DDDFA1}.Release|x86.Build.0 = Release|Win32 38 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Debug|x64.ActiveCfg = Debug|x64 39 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Debug|x64.Build.0 = Debug|x64 40 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Debug|x86.ActiveCfg = Debug|Win32 41 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Debug|x86.Build.0 = Debug|Win32 42 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Release|x64.ActiveCfg = Release|x64 43 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Release|x64.Build.0 = Release|x64 44 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Release|x86.ActiveCfg = Release|Win32 45 | {771D60A2-EDC9-4CA1-BA93-F2B53CBC357D}.Release|x86.Build.0 = Release|Win32 46 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Debug|x64.ActiveCfg = Debug|x64 47 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Debug|x64.Build.0 = Debug|x64 48 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Debug|x86.ActiveCfg = Debug|Win32 49 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Debug|x86.Build.0 = Debug|Win32 50 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Release|x64.ActiveCfg = Release|x64 51 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Release|x64.Build.0 = Release|x64 52 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Release|x86.ActiveCfg = Release|Win32 53 | {2F8A1B93-522E-449E-A7E2-2AFC0910DF48}.Release|x86.Build.0 = Release|Win32 54 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Debug|x64.ActiveCfg = Debug|x64 55 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Debug|x64.Build.0 = Debug|x64 56 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Debug|x86.ActiveCfg = Debug|Win32 57 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Debug|x86.Build.0 = Debug|Win32 58 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Release|x64.ActiveCfg = Release|x64 59 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Release|x64.Build.0 = Release|x64 60 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Release|x86.ActiveCfg = Release|Win32 61 | {A99D36F8-E953-4C59-AD45-93597900CAFF}.Release|x86.Build.0 = Release|Win32 62 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Debug|x64.ActiveCfg = Debug|x64 63 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Debug|x64.Build.0 = Debug|x64 64 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Debug|x86.ActiveCfg = Debug|Win32 65 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Debug|x86.Build.0 = Debug|Win32 66 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Release|x64.ActiveCfg = Release|x64 67 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Release|x64.Build.0 = Release|x64 68 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Release|x86.ActiveCfg = Release|Win32 69 | {F002C795-7D92-4146-8A7C-BBEB946F4309}.Release|x86.Build.0 = Release|Win32 70 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Debug|x64.ActiveCfg = Debug|x64 71 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Debug|x64.Build.0 = Debug|x64 72 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Debug|x86.ActiveCfg = Debug|Win32 73 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Debug|x86.Build.0 = Debug|Win32 74 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Release|x64.ActiveCfg = Release|x64 75 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Release|x64.Build.0 = Release|x64 76 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Release|x86.ActiveCfg = Release|Win32 77 | {1149112D-C4E7-4CC7-B9C7-2AED3A159F8E}.Release|x86.Build.0 = Release|Win32 78 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Debug|x64.ActiveCfg = Debug|x64 79 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Debug|x64.Build.0 = Debug|x64 80 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Debug|x86.ActiveCfg = Debug|Win32 81 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Debug|x86.Build.0 = Debug|Win32 82 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Release|x64.ActiveCfg = Release|x64 83 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Release|x64.Build.0 = Release|x64 84 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Release|x86.ActiveCfg = Release|Win32 85 | {691B8829-AE90-4E85-B809-45D714F66CC0}.Release|x86.Build.0 = Release|Win32 86 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Debug|x64.ActiveCfg = Debug|x64 87 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Debug|x64.Build.0 = Debug|x64 88 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Debug|x86.ActiveCfg = Debug|Win32 89 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Debug|x86.Build.0 = Debug|Win32 90 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Release|x64.ActiveCfg = Release|x64 91 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Release|x64.Build.0 = Release|x64 92 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Release|x86.ActiveCfg = Release|Win32 93 | {F16C04C7-7F1B-4D43-B9C3-156D27D0CD5B}.Release|x86.Build.0 = Release|Win32 94 | EndGlobalSection 95 | GlobalSection(SolutionProperties) = preSolution 96 | HideSolutionNode = FALSE 97 | EndGlobalSection 98 | GlobalSection(ExtensibilityGlobals) = postSolution 99 | SolutionGuid = {24E22F67-89F7-404A-99B5-BBD9D945B0CD} 100 | EndGlobalSection 101 | EndGlobal 102 | -------------------------------------------------------------------------------- /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 | v142 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v142 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v142 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v142 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /TopHeaders/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --------------------------------------------------------------------------------