Remove spawn_blocking from version map (#1966)

I previously add `spawn_blocking` to the version map construction as it
had become a bottleneck
(https://github.com/astral-sh/uv/pull/1163/files#diff-704ceeaedada99f90369eac535713ec82e19550bff166cd44745d7277ecae527R116).
With the zero copy deserialization, this has become so fast we don't
need to move it to the thread pool anymore. I've also checked
`DataWithCachePolicy` but it seems to still take a significant amount of
time. Span visualization:

Resolving jupyter warm:

![image](692b03da-61c5-4f96-b413-199c14aa47c4)

Resolving jupyter cold:

![image](a6893155-d327-40c9-a83a-7c537b7c99c4)

![image](213556a3-a331-42db-aaf5-bdef5e0205dd)

I've also updated the instrumentation a little.

We don't seem cpu bound for the cold cache (top) and refresh case
(bottom) from jupyter:

![image](cb976add-3d30-465a-a470-8490b7b6caea)

![image](d7ecb745-dd2d-4f91-939c-2e46b7c812dd)
This commit is contained in:
konsti 2024-02-26 10:44:24 +01:00 committed by GitHub
parent c80d5c6ffb
commit 70dad51cd9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 62 additions and 57 deletions

View file

@ -1,6 +1,4 @@
use std::future::Future;
use std::ops::Deref;
use std::sync::Arc;
use anyhow::Result;
use chrono::{DateTime, Utc};
@ -62,11 +60,6 @@ pub trait ResolverProvider: Send + Sync {
pub struct DefaultResolverProvider<'a, Context: BuildContext + Send + Sync> {
/// The [`DistributionDatabase`] used to build source distributions.
fetcher: DistributionDatabase<'a, Context>,
/// Allow moving the parameters to `VersionMap::from_metadata` to a different thread.
inner: Arc<DefaultResolverProviderInner>,
}
pub struct DefaultResolverProviderInner {
/// The [`RegistryClient`] used to query the index.
client: RegistryClient,
/// These are the entries from `--find-links` that act as overrides for index responses.
@ -77,14 +70,6 @@ pub struct DefaultResolverProviderInner {
no_binary: NoBinary,
}
impl<'a, Context: BuildContext + Send + Sync> Deref for DefaultResolverProvider<'a, Context> {
type Target = DefaultResolverProviderInner;
fn deref(&self) -> &Self::Target {
self.inner.as_ref()
}
}
impl<'a, Context: BuildContext + Send + Sync> DefaultResolverProvider<'a, Context> {
/// Reads the flat index entries and builds the provider.
#[allow(clippy::too_many_arguments)]
@ -99,14 +84,12 @@ impl<'a, Context: BuildContext + Send + Sync> DefaultResolverProvider<'a, Contex
) -> Self {
Self {
fetcher,
inner: Arc::new(DefaultResolverProviderInner {
client: client.clone(),
flat_index: flat_index.clone(),
tags: tags.clone(),
python_requirement,
exclude_newer,
no_binary: no_binary.clone(),
}),
client: client.clone(),
flat_index: flat_index.clone(),
tags: tags.clone(),
python_requirement,
exclude_newer,
no_binary: no_binary.clone(),
}
}
}
@ -124,24 +107,16 @@ impl<'a, Context: BuildContext + Send + Sync> ResolverProvider
// If the "Simple API" request was successful, convert to `VersionMap` on the Tokio
// threadpool, since it can be slow.
match result {
Ok((index, metadata)) => {
let self_send = self.inner.clone();
let package_name_owned = package_name.clone();
Ok(tokio::task::spawn_blocking(move || {
VersionsResponse::Found(VersionMap::from_metadata(
metadata,
&package_name_owned,
&index,
&self_send.tags,
&self_send.python_requirement,
self_send.exclude_newer.as_ref(),
self_send.flat_index.get(&package_name_owned).cloned(),
&self_send.no_binary,
))
})
.await
.expect("Tokio executor failed, was there a panic?"))
}
Ok((index, metadata)) => Ok(VersionsResponse::Found(VersionMap::from_metadata(
metadata,
package_name,
&index,
&self.tags,
&self.python_requirement,
self.exclude_newer.as_ref(),
self.flat_index.get(package_name).cloned(),
&self.no_binary,
))),
Err(err) => match err.into_kind() {
uv_client::ErrorKind::PackageNotFound(_) => {
if let Some(flat_index) = self.flat_index.get(package_name).cloned() {