unstreamM etc destroys performance; expose unstreamPrimM & document most-performant method
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 38/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bastante claro
- Estado de actividad
- Estancado
- Stack tecnológico
- haskell
- Área
- performance
Línea de trabajo
Comienza en el código fuente de Vector.Generic, alrededor de unstreamPrimM y de la implementación expuesta de unstreamM, y después inspecciona utilidades como VG.mapM que se construyen sobre unstreamM. Compara los ejemplos evaluados mediante benchmarks en el issue y determina el alcance mínimo de API y documentación necesario para exponer la ruta de alto rendimiento o proporcionar equivalentes basados en PrimMonad. La tarea estará terminada cuando el método de alto rendimiento previsto esté disponible y documentado con ejemplos representativos.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
I was messing around with squeezing performance out of this library.
-- utility function used in the rest of the code
fillOrderPart :: (Monad m, Ord a, Num a) => a -> StateT a m a
fillOrderPart c = state $ \r -> let x = min c r in (c - x, r - x)
fillOrder1V :: (Data.Vector.Generic.Vector v i, Ord i, Num i) => v i -> i -> (v i, i)
fillOrder1V = runState . Data.Vector.Generic.mapM fillOrderPart
{-
benchmarking static/vector-unboxed/fillOrder1
time 53.16 μs (53.02 μs .. 53.31 μs)
benchmarking static/vector-storable/fillOrder1
time 52.89 μs (52.59 μs .. 53.22 μs)
-}
fillOrder1VM :: (Data.Vector.Generic.Vector v i, Ord i, Num i) => v i -> i -> (v i, i)
fillOrder1VM book order = runST $ flip runStateT order $ do
book' <- VG.thaw book
VGM.mapM_ fillOrderPart book'
VG.unsafeFreeze book'
{-
benchmarking static/vector-unboxed-copy-mut/fillOrder1
time 11.20 μs (11.19 μs .. 11.21 μs)
benchmarking static/vector-storable-copy-mut/fillOrder1
time 11.51 μs (11.46 μs .. 11.55 μs)
-}
fillOrder1VB2 :: (Data.Vector.Generic.Vector v i, Ord i, Num i) => v i -> i -> (v i, i)
fillOrder1VB2 book order =
-- FIXME: unstreamM performs horribly to list construction, sadly
runState (VG.unstreamM $ VFB.mapM fillOrderPart (VG.stream book)) order
{-
benchmarking static/vector-unboxed-bundle-unstreamM/fillOrder1
time 26.30 μs (26.24 μs .. 26.35 μs)
benchmarking static/vector-storable-bundle-unstreamM/fillOrder1
time 46.10 μs (45.85 μs .. 46.26 μs)
-}
-- bug in vector; defined but not exported. we re-defined it for our use here
unstreamPrimM :: (PrimMonad m, VG.Vector v a) => VFB.MBundle m u a -> m (v a)
{-# INLINE [1] unstreamPrimM #-}
unstreamPrimM s = VGM.munstream s >>= VG.unsafeFreeze
fillOrder1VB :: (Data.Vector.Generic.Vector v i, Ord i, Num i) => v i -> i -> (v i, i)
fillOrder1VB book order =
runST $ flip runStateT order $ unstreamPrimM $ VFB.mapM fillOrderPart $ VG.stream book
{-
benchmarking static/vector-unboxed-bundle/fillOrder1
time 1.426 μs (1.421 μs .. 1.432 μs)
benchmarking static/vector-storable-bundle/fillOrder1
time 855.9 ns (852.2 ns .. 859.3 ns)
-}
By contrast, here is the equivalent rust code:
fn fill_order(book: &mut Vec<u64>, order: u64) -> u64 {
let mut r = order;
for c in book.iter_mut() {
let x = r.min(*c);
r -= x;
*c -= x;
}
r
}
// fill_order time: [868.87 ns 870.21 ns 871.76 ns]
As you can see, the properly-written fusion version performs as well as rust. This was a very pleasant surprise for me. HOWEVER - the correct way is not documented anywhere!!! In particular, the convenience function unstreamPrimM is for some reason defined in the source code of Vector.Generic, used no-where else, not exported nor advertised, yet is absolutely vital for reaching this nirvana of performance.
By contrast, unstreamM is what's exposed in the API and destroys the performance so it performs even worse than the manual imperative mutable version. Even worse, all the utility functions are written in terms of unstreamM, e.g. VG.mapM, etc etc. Yes this means they have a convenient Monad m => constraint, but any non-haskell-expert that cares about performance would benchmark it and write off the library as "Haskell is slow". Providing mirror utilities that have a PrimMonad m => constraint that use unstreamPrimM instead of unstreamM, as well as a few examples, would help this effort.
For reference, the above took me about half a day. Not everybody exploring Haskell has that sort of time or patience.
- Lenguaje dominante
- Haskell
- Estrellas
- 403
- Forks
- 146
- Merge medio
- 1 d 22 h
- PR fusionados (30 d)
- 3
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de haskell/vector
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 68/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 50/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 45/100
-
`Size` can be a newtype.Abierto
Dificultad 5/5 Más de una semana Aptitud para principiantes 35/100
-
Dificultad 3/5 1-2 días Aptitud para principiantes 55/100
Todos los issues de haskell/vector
Issues similares
-
status: needs triage type: enhancement
Dificultad 1/5 Menos de una hora Aptitud para principiantes 90/100
haskell/haskell-language-server#5128 ·
Los mantenedores suelen responder en 1 día
-
enhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
alunduil/siren-json.hs#246 ·
Los mantenedores suelen responder en 1 día
-
question
Dificultad 1/5 Menos de una hora Aptitud para principiantes 75/100
NixOS/SC-election-2026#44 · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
Recognise more linters: yamllint, hlint, luacheck, sqlfluff, buf, tflint, swiftformat --lintAbiertoenhancement good first issue hacktoberfest runner
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
-
docs: install-manifest download links use main instead of master (404)Quizá libre de nuevo Un pull request para esta issue se cerró sin fusionarse. Abierto
Dificultad 2/5 Menos de una hora Aptitud para principiantes 78/100
hasura/graphql-engine#10884 ·