diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 001141204e..d769369982 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,8 @@ +#### Unreleased 5.0.0-rc004 +* PERFORMANCE: Limit the number of concurrent requests to 7 (https://github.com/fsprojects/Paket/pull/2362) +* PERFORMANCE: Report how often the pre-loading feature worked (https://github.com/fsprojects/Paket/pull/2362) +* PERFORMANCE: Request queue can now re-prioritize on-demand (https://github.com/fsprojects/Paket/pull/2362) + #### 5.0.0-rc003 - 09.06.2017 * Internals: Started proper dotnetcore integration (disabled by default, can be enabled via setting `PAKET_DISABLE_RUNTIME_RESOLUTION` to `false`): * Paket now properly understands runtime and reference assemblies diff --git a/integrationtests/scenarios/i001427-content-none/before/paket.dependencies b/integrationtests/scenarios/i001427-content-none/before/paket.dependencies index 1e0adf6e94..c6961998eb 100644 --- a/integrationtests/scenarios/i001427-content-none/before/paket.dependencies +++ b/integrationtests/scenarios/i001427-content-none/before/paket.dependencies @@ -1,4 +1,5 @@ source https://www.nuget.org/api/v2/ framework >= net45 -nuget Costura.Fody ~> 1.3.3.0 content:none \ No newline at end of file +nuget Costura.Fody ~> 1.3.3.0 content:none +nuget Fody ~> 2.0.10 content:none \ No newline at end of file diff --git a/integrationtests/scenarios/i001427-content-once-remove/before/paket.dependencies b/integrationtests/scenarios/i001427-content-once-remove/before/paket.dependencies index 0e1441f5ac..5cfb3df2ef 100644 --- a/integrationtests/scenarios/i001427-content-once-remove/before/paket.dependencies +++ b/integrationtests/scenarios/i001427-content-once-remove/before/paket.dependencies @@ -1,4 +1,5 @@ source https://www.nuget.org/api/v2/ framework >= net45 -nuget Costura.Fody ~> 1.3.3.0 content: once \ No newline at end of file +nuget Costura.Fody ~> 1.3.3.0 content: once +nuget Fody ~> 2.0.10 content: once \ No newline at end of file diff --git a/integrationtests/scenarios/i001427-content-once-stable/before/paket.dependencies b/integrationtests/scenarios/i001427-content-once-stable/before/paket.dependencies index 0e1441f5ac..5cfb3df2ef 100644 --- a/integrationtests/scenarios/i001427-content-once-stable/before/paket.dependencies +++ b/integrationtests/scenarios/i001427-content-once-stable/before/paket.dependencies @@ -1,4 +1,5 @@ source https://www.nuget.org/api/v2/ framework >= net45 -nuget Costura.Fody ~> 1.3.3.0 content: once \ No newline at end of file +nuget Costura.Fody ~> 1.3.3.0 content: once +nuget Fody ~> 2.0.10 content: once \ No newline at end of file diff --git a/integrationtests/scenarios/i001427-content-once/before/paket.dependencies b/integrationtests/scenarios/i001427-content-once/before/paket.dependencies index 0e1441f5ac..5cfb3df2ef 100644 --- a/integrationtests/scenarios/i001427-content-once/before/paket.dependencies +++ b/integrationtests/scenarios/i001427-content-once/before/paket.dependencies @@ -1,4 +1,5 @@ source https://www.nuget.org/api/v2/ framework >= net45 -nuget Costura.Fody ~> 1.3.3.0 content: once \ No newline at end of file +nuget Costura.Fody ~> 1.3.3.0 content: once +nuget Fody ~> 2.0.10 content: once \ No newline at end of file diff --git a/integrationtests/scenarios/i001427-content-true/before/paket.dependencies b/integrationtests/scenarios/i001427-content-true/before/paket.dependencies index 35c092c72c..c98b4b82ca 100644 --- a/integrationtests/scenarios/i001427-content-true/before/paket.dependencies +++ b/integrationtests/scenarios/i001427-content-true/before/paket.dependencies @@ -1,4 +1,5 @@ source https://www.nuget.org/api/v2/ framework >= net45 -nuget Costura.Fody ~> 1.3.3.0 \ No newline at end of file +nuget Costura.Fody ~> 1.3.3.0 +nuget Fody ~> 2.0.10 \ No newline at end of file diff --git a/integrationtests/scenarios/i001427-ref-content-once/before/paket.dependencies b/integrationtests/scenarios/i001427-ref-content-once/before/paket.dependencies index 35c092c72c..c98b4b82ca 100644 --- a/integrationtests/scenarios/i001427-ref-content-once/before/paket.dependencies +++ b/integrationtests/scenarios/i001427-ref-content-once/before/paket.dependencies @@ -1,4 +1,5 @@ source https://www.nuget.org/api/v2/ framework >= net45 -nuget Costura.Fody ~> 1.3.3.0 \ No newline at end of file +nuget Costura.Fody ~> 1.3.3.0 +nuget Fody ~> 2.0.10 \ No newline at end of file diff --git a/integrationtests/scenarios/i001522-copy-content/before/paket.dependencies b/integrationtests/scenarios/i001522-copy-content/before/paket.dependencies index c7cc0d13e8..45170d2bd6 100644 --- a/integrationtests/scenarios/i001522-copy-content/before/paket.dependencies +++ b/integrationtests/scenarios/i001522-copy-content/before/paket.dependencies @@ -1,4 +1,5 @@ source https://www.nuget.org/api/v2/ framework >= net45 -nuget Costura.Fody ~> 1.3.3.0 content: once, copy_content_to_output_dir: always \ No newline at end of file +nuget Costura.Fody ~> 1.3.3.0 content: once, copy_content_to_output_dir: always +nuget Fody ~> 2.0.10 content: once, copy_content_to_output_dir: always \ No newline at end of file diff --git a/src/Paket.Core/Common/Profile.fs b/src/Paket.Core/Common/Profile.fs index 64b343e356..aeed39654f 100644 --- a/src/Paket.Core/Common/Profile.fs +++ b/src/Paket.Core/Common/Profile.fs @@ -10,6 +10,7 @@ type BlockReason = type Category = | ResolverAlgorithm | ResolverAlgorithmBlocked of BlockReason + | ResolverAlgorithmNotBlocked of BlockReason | NuGetRequest | NuGetDownload | FileIO @@ -18,6 +19,9 @@ type Event = { Category: Category; Duration : TimeSpan } let events = System.Collections.Concurrent.ConcurrentBag() +let trackEvent cat = + events.Add({ Category = cat; Duration = TimeSpan() }) + let startCategory cat = let cw = Stopwatch.StartNew() let mutable wasDisposed = false diff --git a/src/Paket.Core/Dependencies/NuGetV2.fs b/src/Paket.Core/Dependencies/NuGetV2.fs index 3e5a1b8da0..594aab4c44 100644 --- a/src/Paket.Core/Dependencies/NuGetV2.fs +++ b/src/Paket.Core/Dependencies/NuGetV2.fs @@ -18,6 +18,7 @@ open Paket.Xml open Paket.PackageSources open Paket.Requirements open FSharp.Polyfill +open System.Runtime.ExceptionServices let rec private followODataLink auth url = async { @@ -268,7 +269,7 @@ let getDetailsFromNuGetViaOData auth nugetURL (packageName:PackageName) (version try let! result = getDetailsFromNuGetViaODataFast auth nugetURL packageName version if urlSimilarToTfsOrVsts nugetURL && result |> NuGet.NuGetPackageCache.getDependencies |> List.isEmpty then - // TODO: There is a bug in VSTS, so we can't trust this protocol. Remvoe when VSTS is fixed + // TODO: There is a bug in VSTS, so we can't trust this protocol. Remove when VSTS is fixed // TODO: TFS has the same bug return! queryPackagesProtocol packageName else @@ -651,7 +652,7 @@ let rec private getPackageDetails alternativeProjectRoot root force (sources:Pac nugetSource.Url packageName version - return Some(source,result) } + return Choice1Of2(source,result) } let tryV3 source nugetSource force = async { if nugetSource.Url.Contains("myget.org") || nugetSource.Url.Contains("nuget.org") || nugetSource.Url.Contains("visualstudio.com") || nugetSource.Url.Contains("/nuget/v3/") then @@ -664,25 +665,25 @@ let rec private getPackageDetails alternativeProjectRoot root force (sources:Pac url packageName version - return Some(source,result) + return Choice1Of2(source,result) | _ -> let! result = NuGetV3.GetPackageDetails force nugetSource packageName version - return Some(source,result) + return Choice1Of2(source,result) else let! result = NuGetV3.GetPackageDetails force nugetSource packageName version - return Some(source,result) } + return Choice1Of2(source,result) } let getPackageDetails force = // helper to work through the list sequentially - let rec trySelectFirst workLeft = + let rec trySelectFirst errors workLeft = async { match workLeft with | work :: rest -> let! r = work match r with - | Some result -> return Some result - | None -> return! trySelectFirst rest - | [] -> return None + | Choice1Of2 result -> return Choice1Of2 result + | Choice2Of2 error -> return! trySelectFirst (error::errors) rest + | [] -> return Choice2Of2 errors } sources |> List.sortBy (fun source -> @@ -720,33 +721,39 @@ let rec private getPackageDetails alternativeProjectRoot root force (sources:Pac | LocalNuGet(path,Some _) -> let! result = getDetailsFromLocalNuGetPackage true alternativeProjectRoot root path packageName version - return Some(source,result) + return Choice1Of2(source,result) | LocalNuGet(path,None) -> let! result = getDetailsFromLocalNuGetPackage false alternativeProjectRoot root path packageName version - return Some(source,result) + return Choice1Of2(source,result) with e -> if verbose then verbosefn "Source '%O' exception: %O" source e - return None }) - |> trySelectFirst + let capture = ExceptionDispatchInfo.Capture e + return Choice2Of2 capture }) + |> trySelectFirst [] let! maybePackageDetails = getPackageDetails force let! source,nugetObject = async { + let fallback () = + match sources |> List.map (fun (s:PackageSource) -> s.ToString()) with + | [source] -> + failwithf "Couldn't get package details for package %O %O on %O." packageName version source + | [] -> + failwithf "Couldn't get package details for package %O %O, because no sources were specified." packageName version + | sources -> + failwithf "Couldn't get package details for package %O %O on any of %A." packageName version sources + match maybePackageDetails with - | None -> - let! m = getPackageDetails true - match m with - | None -> - match sources |> List.map (fun (s:PackageSource) -> s.ToString()) with - | [source] -> - return failwithf "Couldn't get package details for package %O %O on %O." packageName version source - | [] -> - return failwithf "Couldn't get package details for package %O %O, because no sources were specified." packageName version - | sources -> - return failwithf "Couldn't get package details for package %O %O on any of %A." packageName version sources - | Some packageDetails -> return packageDetails - | Some packageDetails -> return packageDetails + | Choice2Of2 ([]) -> return fallback() + | Choice2Of2 (h::restError) -> + for error in restError do + if not verbose then + // Otherwise the error was already mentioned above + traceWarnfn "Ignoring: %s" error.SourceException.Message + h.Throw() + return fallback() + | Choice1Of2 packageDetails -> return packageDetails } let encodeURL (url:string) = diff --git a/src/Paket.Core/Dependencies/Nuget.fs b/src/Paket.Core/Dependencies/Nuget.fs index c38814cac3..2c003b8949 100644 --- a/src/Paket.Core/Dependencies/Nuget.fs +++ b/src/Paket.Core/Dependencies/Nuget.fs @@ -106,25 +106,29 @@ let getDetailsFromCacheOr force nugetURL (packageName:PackageName) (version:SemV async { if not force && cacheFile.Exists then let json = File.ReadAllText(cacheFile.FullName) - try - let cachedObject = JsonConvert.DeserializeObject json + let cacheResult = + try + let cachedObject = JsonConvert.DeserializeObject json - if (PackageName cachedObject.PackageName <> packageName) || - (cachedObject.Version <> version.Normalize()) - then - traceVerbose (sprintf "Invalidating Cache '%s:%s' <> '%s:%s'" cachedObject.PackageName cachedObject.Version packageName.Name (version.Normalize())) + if (PackageName cachedObject.PackageName <> packageName) || + (cachedObject.Version <> version.Normalize()) + then + traceVerbose (sprintf "Invalidating Cache '%s:%s' <> '%s:%s'" cachedObject.PackageName cachedObject.Version packageName.Name (version.Normalize())) + cacheFile.Delete() + None + else + Some cachedObject + with + | exn -> cacheFile.Delete() - return! get() - else - return cachedObject - with - | exn -> - cacheFile.Delete() - if verbose then - traceWarnfn "Error while loading cache: %O" exn - else - traceWarnfn "Error while loading cache: %s" exn.Message - return! get() + if verbose then + traceWarnfn "Error while loading cache: %O" exn + else + traceWarnfn "Error while loading cache: %s" exn.Message + None + match cacheResult with + | Some res -> return res + | None -> return! get() else return! get() } \ No newline at end of file diff --git a/src/Paket.Core/Dependencies/PackageResolver.fs b/src/Paket.Core/Dependencies/PackageResolver.fs index 19f0d7f6f7..fde796759a 100644 --- a/src/Paket.Core/Dependencies/PackageResolver.fs +++ b/src/Paket.Core/Dependencies/PackageResolver.fs @@ -9,6 +9,8 @@ open System.Collections.Generic open System open System.Diagnostics open Paket.PackageSources +open System.Threading.Tasks +open System.Threading type DependencySet = Set @@ -642,35 +644,153 @@ type private Stage = | Outer of currentConflict : (ConflictState * ResolverStep * PackageRequirement) * priorConflictSteps : (ConflictState * ResolverStep * PackageRequirement * seq * StepFlags) list | Inner of currentConflict : (ConflictState * ResolverStep * PackageRequirement) * priorConflictSteps : (ConflictState * ResolverStep * PackageRequirement * seq * StepFlags) list +type WorkPriority = + | BackgroundWork = 10 + | BlockingWork = 1 + +type RequestWork = + private + { StartWork : CancellationToken -> System.Threading.Tasks.Task + mutable Priority : WorkPriority } + +type WorkHandle<'a> = private { Work : RequestWork; TaskSource : TaskCompletionSource<'a> } +and ResolverRequestQueue = + private { DynamicQueue : ResizeArray; Lock : obj; WaitingWorker : ResizeArray> } + // callback in a lock is bad practice.. + member private x.With callback = + lock x.Lock (fun () -> + callback x.DynamicQueue x.WaitingWorker + ) + member x.AddWork w = + x.With (fun queue workers -> + if workers.Count > 0 then + let worker = workers.[0] + workers.RemoveAt(0) + worker.SetResult (Some w) + else + queue.Add(w) + ) + member x.GetWork (ct:CancellationToken) = + let tcs = new TaskCompletionSource<_>() + let registration = ct.Register(fun () -> tcs.TrySetResult None |> ignore) + tcs.Task.ContinueWith (fun (t:Task) -> + registration.Dispose()) |> ignore + x.With (fun queue workers -> + if queue.Count = 0 then + workers.Add(tcs) + else + let (index, work) = queue |> Seq.mapi (fun i w -> i,w) |> Seq.minBy (fun (i,w) -> w.Priority) + queue.RemoveAt index + tcs.TrySetResult (Some work) |> ignore + tcs.Task + ) + +module ResolverRequestQueue = + open System.Threading + + let Create() = { DynamicQueue = new ResizeArray(); Lock = new obj(); WaitingWorker = new ResizeArray<_>() } + let addWork prio (f: CancellationToken -> System.Threading.Tasks.Task<'a>) ({ DynamicQueue = queue } as q) = + let tcs = new TaskCompletionSource<_>() + let work = + { StartWork = (fun tok -> + let t = + try + f tok + with e -> + //Task.FromException (e) + let tcs = new TaskCompletionSource<_>() + tcs.SetException e + tcs.Task + + t.ContinueWith(fun (t:System.Threading.Tasks.Task<'a>) -> + if t.IsCanceled then + tcs.SetException(new TaskCanceledException(t)) + elif t.IsFaulted then + tcs.SetException(t.Exception) + else tcs.SetResult (t.Result))) + Priority = prio } + q.AddWork work + { Work = work; TaskSource = tcs } + let startProcessing (ct:CancellationToken) ({ DynamicQueue = queue } as q) = + async { + while not ct.IsCancellationRequested do + let! work = q.GetWork(ct) |> Async.AwaitTask + match work with + | Some work -> + do! work.StartWork(ct).ContinueWith(fun (t:System.Threading.Tasks.Task) -> ()) |> Async.AwaitTask + | None -> () + } + |> Async.StartAsTask + +type WorkHandle<'a> with + member x.Reprioritize prio = + let { Work = work } = x + work.Priority <- prio + member x.Task = + let { TaskSource = task } = x + task.Task + /// Resolves all direct and transitive dependencies let Resolve (getVersionsRaw, getPreferredVersionsRaw, getPackageDetailsRaw, groupName:GroupName, globalStrategyForDirectDependencies, globalStrategyForTransitives, globalFrameworkRestrictions, (rootDependencies:PackageRequirement Set), updateMode : UpdateMode) = tracefn "Resolving packages for group %O:" groupName use d = Profile.startCategory Profile.Category.ResolverAlgorithm - - let startedGetPackageDetailsRequests = System.Collections.Concurrent.ConcurrentDictionary<_,System.Threading.Tasks.Task<_>>() + use cts = new CancellationTokenSource() + let workerQueue = ResolverRequestQueue.Create() + let workers = + // start maximal 7 requests at the same time. + [ 0 .. 7 ] + |> List.map (fun _ -> ResolverRequestQueue.startProcessing cts.Token workerQueue) + + let getAndReport (sources:PackageSource list) blockReason (workHandle:WorkHandle<_>) = + try + if workHandle.Task.IsCompleted then + Profile.trackEvent (Profile.Category.ResolverAlgorithmNotBlocked blockReason) + workHandle.Task.Result + else + workHandle.Reprioritize WorkPriority.BlockingWork + use d = Profile.startCategory (Profile.Category.ResolverAlgorithmBlocked blockReason) + let isFinished = workHandle.Task.Wait(30000) + if not isFinished then + // TODO: Fix/Refactor to only show unfinished sources, but this needs more information flow... + raise <| + new TimeoutException( + "Waited 30 seconds for a request to finish (maybe a bug in the paket request scheduler).\n" + + " Check the following sources:\n" + + " - " + System.String.Join("\n - ", sources |> Seq.map (fun s -> s.Url)) + ) + let result = workHandle.Task.Result + d.Dispose() + result + with :? AggregateException as a when a.InnerExceptions.Count = 1 -> + let flat = a.Flatten() + if flat.InnerExceptions.Count = 1 then + System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(flat.InnerExceptions.[0]).Throw() + reraise() + + let startedGetPackageDetailsRequests = System.Collections.Concurrent.ConcurrentDictionary<_,WorkHandle<_>>() let startRequestGetPackageDetails sources groupName packageName semVer = let key = (sources, packageName, semVer) startedGetPackageDetailsRequests.GetOrAdd (key, fun _ -> - (getPackageDetailsRaw sources groupName packageName semVer : Async) - |> Async.StartAsTask) + workerQueue + |> ResolverRequestQueue.addWork WorkPriority.BackgroundWork (fun ct -> + (getPackageDetailsRaw sources groupName packageName semVer : Async) + |> Async.StartAsTask)) let getPackageDetailsBlock sources groupName packageName semVer = - use d = Profile.startCategory (Profile.Category.ResolverAlgorithmBlocked Profile.BlockReason.PackageDetails) - let result = (startRequestGetPackageDetails sources groupName packageName semVer).GetAwaiter().GetResult() - d.Dispose() - result - + let workHandle = startRequestGetPackageDetails sources groupName packageName semVer + getAndReport sources Profile.BlockReason.PackageDetails workHandle - let startedGetVersionsRequests = System.Collections.Concurrent.ConcurrentDictionary<_,System.Threading.Tasks.Task<_>>() + let startedGetVersionsRequests = System.Collections.Concurrent.ConcurrentDictionary<_,WorkHandle<_>>() let startRequestGetVersions sources groupName packageName = let key = (sources, packageName) startedGetVersionsRequests.GetOrAdd (key, fun _ -> - getVersionsRaw sources groupName packageName - |> Async.StartAsTask) + workerQueue + |> ResolverRequestQueue.addWork WorkPriority.BackgroundWork (fun ct -> + getVersionsRaw sources groupName packageName + |> Async.StartAsTask)) let getVersionsBlock sources resolverStrategy groupName packageName = - use d = Profile.startCategory (Profile.Category.ResolverAlgorithmBlocked Profile.BlockReason.GetVersion) - let versions = (startRequestGetVersions sources groupName packageName).GetAwaiter().GetResult() |> Seq.toList - d.Dispose() + let workHandle = startRequestGetVersions sources groupName packageName + let versions = getAndReport sources Profile.BlockReason.GetVersion workHandle |> Seq.toList let sorted = match resolverStrategy with | ResolverStrategy.Max -> List.sortDescending versions @@ -705,9 +825,10 @@ let Resolve (getVersionsRaw, getPreferredVersionsRaw, getPackageDetailsRaw, grou if flags.ForceBreak then false else if conflictState.Status.IsDone then false else if Seq.isEmpty conflictState.VersionsToExplore then - match conflictState.Status with - | Resolution.Ok _ -> () - | _ -> (tracefn " Failed to satisfy %O" currentRequirement) + // TODO: maybe this is the wrong place to report this... + //match conflictState.Status with + //| Resolution.Ok _ -> () + //| _ -> (tracefn " Failed to satisfy %O" currentRequirement) false else flags.FirstTrial || Set.isEmpty conflictState.Conflicts @@ -885,11 +1006,11 @@ let Resolve (getVersionsRaw, getPreferredVersionsRaw, getPackageDetailsRaw, grou // Start pre-loading infos about dependencies. for (pack,verReq,restr) in exploredPackage.Dependencies do async { - let! versions = startRequestGetVersions currentRequirement.Sources groupName pack |> Async.AwaitTask + let! versions = (startRequestGetVersions currentRequirement.Sources groupName pack).Task |> Async.AwaitTask // Preload the first version in range of this requirement match versions |> Seq.map fst |> Seq.tryFind (verReq.IsInRange) with | Some verToPreload -> - let! details = startRequestGetPackageDetails currentRequirement.Sources groupName pack verToPreload |> Async.AwaitTask + let! details = (startRequestGetPackageDetails currentRequirement.Sources groupName pack verToPreload).Task |> Async.AwaitTask () | None -> () return () @@ -970,41 +1091,47 @@ let Resolve (getVersionsRaw, getPreferredVersionsRaw, getPackageDetailsRaw, grou } let inline calculate () = step (Step((currentConflict,startingStep,currentRequirement),[])) stackpack Seq.empty flags + + try #if DEBUG - let mutable results = None - let mutable error = None - // Increase stack size, because we have no tail-call-elimination - let thread = new System.Threading.Thread((fun () -> - try - results <- Some (calculate()) - with e -> - // Prevent the application from crashing - error <- Some (System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture e) - ), 1024 * 1024 * 100) - thread.Name <- sprintf "Paket Resolver Thread (Debug) - %O" (System.Guid.NewGuid()) - thread.Start() - thread.Join() - match error with - | Some e -> e.Throw() - | _ -> () - let stepResult = - match results with - | Some s -> s - | None -> failwithf "Expected to get results from the resolver thread :/." + let mutable results = None + let mutable error = None + // Increase stack size, because we have no tail-call-elimination + let thread = new System.Threading.Thread((fun () -> + try + results <- Some (calculate()) + with e -> + // Prevent the application from crashing + error <- Some (System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture e) + ), 1024 * 1024 * 100) + thread.Name <- sprintf "Paket Resolver Thread (Debug) - %O" (System.Guid.NewGuid()) + thread.Start() + thread.Join() + match error with + | Some e -> e.Throw() + | _ -> () + let stepResult = + match results with + | Some s -> s + | None -> failwithf "Expected to get results from the resolver thread :/." #else - let stepResult = calculate() + let stepResult = calculate() #endif - match stepResult with - | { Status = Resolution.Conflict _ } as conflict -> - if conflict.TryRelaxed then - stackpack.KnownConflicts.Clear() - stackpack.ConflictHistory.Clear() - (step (Step((conflict - ,{startingStep with Relax=true} - ,currentRequirement),[])) - stackpack Seq.empty flags).Status - else - conflict.Status - | x -> x.Status - + match stepResult with + | { Status = Resolution.Conflict _ } as conflict -> + if conflict.TryRelaxed then + stackpack.KnownConflicts.Clear() + stackpack.ConflictHistory.Clear() + (step (Step((conflict + ,{startingStep with Relax=true} + ,currentRequirement),[])) + stackpack Seq.empty flags).Status + else + conflict.Status + | x -> x.Status + finally + // some cleanup + cts.Cancel() + for w in workers do + w.Wait() diff --git a/src/Paket/Program.fs b/src/Paket/Program.fs index fdf5363878..ac04e2d268 100644 --- a/src/Paket/Program.fs +++ b/src/Paket/Program.fs @@ -64,26 +64,27 @@ let processWithValidation silent validateF commandF (result : ParseResults<'T>) match cat with | Profile.Category.ResolverAlgorithm -> 1 | Profile.Category.ResolverAlgorithmBlocked b -> 2 - | Profile.Category.FileIO -> 3 - | Profile.Category.NuGetDownload -> 4 - | Profile.Category.NuGetRequest -> 5 - | Profile.Category.Other -> 6) + | Profile.Category.ResolverAlgorithmNotBlocked b -> 3 + | Profile.Category.FileIO -> 4 + | Profile.Category.NuGetDownload -> 5 + | Profile.Category.NuGetRequest -> 6 + | Profile.Category.Other -> 7) |> List.iter (fun (cat, num, elapsed) -> + let reason b = + match b with + | Profile.BlockReason.PackageDetails -> "retrieving package details" + | Profile.BlockReason.GetVersion -> "retrieving package versions" match cat with | Profile.Category.ResolverAlgorithm -> tracefn " - Resolver: %s (%d runs)" (Utils.TimeSpanToReadableString elapsed) num let realTime = resolver - blocked tracefn " - Runtime: %s" (Utils.TimeSpanToReadableString realTime) - let blockNum = blockedRaw |> Seq.sumBy (fun (_, num, _) -> num) - let blockPaket4 = TimeSpan.FromMilliseconds(500.0 * float blockNum) - tracefn " - Runtime Paket 4 (estimated ~500ms respose*): %s" (Utils.TimeSpanToReadableString (realTime + blockPaket4)) - tracefn " * See http://stats.pingdom.com/aqicaf2upspo/1265300 for average response times." | Profile.Category.ResolverAlgorithmBlocked b -> - let reason = - match b with - | Profile.BlockReason.PackageDetails -> "retrieving package details" - | Profile.BlockReason.GetVersion -> "retrieving package versions" + let reason = reason b tracefn " - Blocked (%s): %s (%d times)" reason (Utils.TimeSpanToReadableString elapsed) num + | Profile.Category.ResolverAlgorithmNotBlocked b -> + let reason = reason b + tracefn " - Not Blocked (%s): %d times" reason num | Profile.Category.FileIO -> tracefn " - Disk IO: %s" (Utils.TimeSpanToReadableString elapsed) | Profile.Category.NuGetDownload ->