NuGet product used: msbuild /restore
VS version: VS 2017 RC4
I have solution with 123 project, ~10 of them are new csproj, most of others are old csproj with project.json.
Currently msbuild /t:restore takes 15 minutes.
Before conversion with xproj and Nuget 3.5 command nuget restore  for same solution on same environment took only 2 minutes.
@iskiselev are you able to share this solution? Does this include downloading packages or is this for a noop restore?
I have seen some slow downs with csproj PackageReference also, but not to that extent. With xproj there was no evaluation needed, all references including projects were in a static json file. With csproj now all of this has to be evaluated through msbuild which unfortunately takes longer than project.json.
Also it is important to point out that to find out if a project has PackageReferences restore has to evaluate it fully. Previously with project.json a simple file scan could determine this.
Still 15 minutes seems way too long, so I'm very interested in getting a repro of this.
From my own testing on projects such as Roslyn which has 155 projects the restore time is around 25 seconds.
@emgarten, we probably may share it if NDA will be signed. Would you like me to check it with my managers?
@iskiselev we can try a few other things first.
@iskiselev - are you able to help answer @iskiselev's questions.
I'll try to provide answers to @emgarten questions today.
I've done bunch of tests. I've done it on my local machine, so time results a little bit different (it was slower on our build server). I'll provide step-by step description.
.nuget\NuGet.exe restore MySolution.sln -MsBuildPath "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin". NuGet.exe is one of the latest 4.0 RC (4.0.0.2275). I used it, as calling msbuild will not resotore dependecies from project.config. Work time: 6:32."C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\MSBuild" /t:Clean MySolution.sln. Work time: 22 seconds"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\MSBuild" /t:Restore  MySolution.sln /flp:Verbosity=detailed;logfile=log.txt. Work time: 6:30. Unfortunately, msbuild doesn't write time stats with detailed log."C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\MSBuild" /t:Restore  MySolution.sln /flp:Verbosity=diag;logfile=logDiag.txt. Work time: 11:30. Here is collected statics:Target Performance Summary:
        0 ms  ValidateToolsVersions                      1 calls
        2 ms  CheckForImplicitPackageReferenceOverridesBeforeRestore  36 calls
       10 ms  _LoadRestoreGraphEntryPoints               1 calls
       13 ms  _FilterRestoreGraphProjectInputItems       1 calls
       25 ms  ValidateSolutionConfiguration              1 calls
      107 ms  _GetRestoreTargetFrameworksOutput         19 calls
      125 ms  _SplitProjectReferencesByFileExistence   176 calls
      176 ms  _GetRestoreProjectStyle                  334 calls
      287 ms  _GenerateRestoreProjectSpec              158 calls
      590 ms  ValidateProjects                           1 calls
      789 ms  _GenerateRestoreProjectReferencePaths    176 calls
      799 ms  _GetProjectJsonPath                      334 calls
     1273 ms  _GenerateRestoreGraphWalkPerFramework    176 calls
    24329 ms  _GetAllRestoreProjectReferences          158 calls
    28485 ms  _GenerateRestoreSpecs                    157 calls
    28619 ms  _GenerateDotnetCliToolReferenceSpecs     157 calls
    30988 ms  _GenerateRestoreDependencies             158 calls
    46836 ms  Restore                                    1 calls
    89187 ms  _GenerateRestoreGraphWalk                158 calls
    89360 ms  _GenerateRestoreGraphProjectEntry        157 calls
    561227 ms  _GetChildRestoreProjects                 158 calls
    643760 ms  _GenerateRestoreGraph                      1 calls
Task Performance Summary:
       70 ms  GetRestoreProjectFrameworks               19 calls
       96 ms  GetRestorePackageReferencesTask           35 calls
      255 ms  GetRestoreDotnetCliToolsTask             157 calls
      381 ms  ConvertToAbsolutePath                    193 calls
      415 ms  Message                                  318 calls
      473 ms  GetRestoreProjectJsonPathTask            282 calls
      940 ms  GetRestoreProjectReferencesTask          176 calls
    22944 ms  RestoreTask                                1 calls
    23887 ms  RemoveDuplicates                           1 calls
    1169222 ms  MsBuild                                  511 calls
For comparison, I checked out same project before conversion to VS 2017, and run twice .nuget\NuGet.exe restore MySolution.sln command. Here I used nuget 3.5.0.1737. First run took 1:15, second ended in just 30 seconds.
@iskiselev thanks for the detailed feedback!
The number of calls made looks roughly correct here. It seems to be spending a lot of time getting the project references. Is there anything unique about your solution with regards to that? Do the projects contain a large number of project references?
@emgarten, probably you are correct. We started converted our core 12 projects to xproj some time ago, and as there was no support for transitive references before VS 2017 for xproj, most of other (~100) projects has reference to that 12 projects, in addition to normal 3-10 references that they actually need. So, I'd say that most of old csproj with prohect.json contains around 15-25 project references.
I'll try to remove that was added only for transitive, and check if it will improve speed, but I won't be able to do it fast - probably in one or two weeks.
I'll try generating some test solutions with a lot of project to project references to try this out. Keep me posted on what you once you update this also.
I have cleaned-up most unnecessary  transitive p2p references. It works fasted now.
First run nuget restore on clean check-out: 2:45 (my computer), 5:58 (build server)
Second run: 2:13 (my computer).
It still works 2-3 times slower than NuGet 3.5 on our solution, but probably it is acceptable time.
@iskiselev thanks for the times, I'm glad to hear that helped!
I have some ideas on how perf can be improved for solutions with a lot of p2p references. I'll keep this issue to track that work.
I was able to repro this using a solution of 127 projects that have 2 target frameworks each and project references to every possible child project.
The current targets file takes 15 minutes (similar to the original issue) to collect all restore inputs from the solution. It looks like this can be improve by finding the full set of projects first and then reading each directly instead of relying on MSBuild caching.
nuget restore used to be 3% of our total build, after this change, msbuild /t:restore is now 27% of our up-to-date build run time.
The fix for this will be in 4.1.0 (Visual Studio 15.1)
My results for this with 127 interlinked projects:
Before: 900s
After: 21s
I still have this problem. 62 projects are restored in 90 seconds. Machine is fast enough (Core [email protected], SSD).
Tested on NuGet 4.1, 4.2, 4.3 beta. Result the same.
It will be nice to have 20 second for the restore operation.
This is very annoying to wait packages restore 2+ minutes every time after solution opening.
I was forced to perform hack to break VS restore functionality:
In the file: c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\Microsoft\VisualStudio\Managed\Microsoft.Managed.DesignTime.targets
<!-- NuGet Restore Properties -->
<!--    COMMEND THIS
    <PropertyPageSchema Include="$(ManagedXamlResourcesDirectory)NuGetRestore.xaml">
      <Context>ProjectSubscriptionService</Context>
    </PropertyPageSchema>-->
And do packages restore manually by command.
@dmitriyse you mentioned opening a solution, this issue was fixed for command line restore. It sounds like you seeing slow perf with visual studio automatic package restore which hasn't been fixed yet. Take a look at these issues for more details:
https://github.com/NuGet/Home/issues/4307
https://github.com/dotnet/project-system/issues/1600
Also, you can disable auto restore under the NuGet options in Visual Studio. Disable both the automatic package restore options. Then to restore you can right click on the solution node and select restore.
@emgarten Thank you for tip with disabling two checkboxes.
I solved my problem by removing <RuntimeIdentifiers> from all projects.
Now I have 62 projects ~ 35 seconds.
I found that when I put in the project section:
<RuntimeIdentifiers>win7-xxx;ubunty.yyy-yy</RuntimeIdentifiers>
packages are restored 3x times longer.
I think this is real performance BUG. Probably it should be posted in another issue.
Also I think 62 projects ~ 35 seconds is still too much.
Read solution file, then read 62 csproj files, then read brief info from nuget.spec files from the packages cache (.nuget/
For example in my case 62 projects finally references 506 different packages (according to project.assets.file).
Most helpful comment
For example in my case 62 projects finally references 506 different packages (according to project.assets.file).