From d277b075c8d3784896ff4d252a137fd7f5905990 Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Fri, 30 Nov 2012 00:53:04 +0100 Subject: [PATCH] Optimise recursive Query filters Currently, the And and Or filters use very nice code, e.g. in case of OrFilter: any id <$> mapM evaluateFilter flts However, looking at the memory profiles shows that application of any/id to monadic values via '<$>' does not work nicely, losing the 'early' success property. This results in too much memory being used for thunks in monadic sequencing. Rather than trying to add more strictness (not sure exactly how, TBH), switching these to explicit recursion solves the problem, since we take the 'early' exit problem in our hands and we are explicit about it. Memory usage in case of big (e.g. 1000 'Or' elements) is reduced significantly, and thus also the runtime. Signed-off-by: Iustin Pop <iustin@google.com> Reviewed-by: Michele Tartara <mtartara@google.com> --- htools/Ganeti/Query/Filter.hs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/htools/Ganeti/Query/Filter.hs b/htools/Ganeti/Query/Filter.hs index d5e56f708..94f65c9a0 100644 --- a/htools/Ganeti/Query/Filter.hs +++ b/htools/Ganeti/Query/Filter.hs @@ -144,14 +144,28 @@ containsFilter (NumericValue val) lst = do -- | Verifies if a given item passes a filter. The runtime context -- might be missing, in which case most of the filters will consider -- this as passing the filter. +-- +-- Note: we use explicit recursion to reduce unneeded memory use; +-- 'any' and 'all' do not play nice with monadic values, resulting in +-- either too much memory use or in too many thunks being created. evaluateFilter :: ConfigData -> Maybe b -> a -> Filter (FieldGetter a b) -> ErrorResult Bool evaluateFilter _ _ _ EmptyFilter = Ok True -evaluateFilter c mb a (AndFilter flts) = - all id <$> mapM (evaluateFilter c mb a) flts -evaluateFilter c mb a (OrFilter flts) = - any id <$> mapM (evaluateFilter c mb a) flts +evaluateFilter c mb a (AndFilter flts) = helper flts + where helper [] = Ok True + helper (f:fs) = do + v <- evaluateFilter c mb a f + if v + then helper fs + else Ok False +evaluateFilter c mb a (OrFilter flts) = helper flts + where helper [] = Ok False + helper (f:fs) = do + v <- evaluateFilter c mb a f + if v + then Ok True + else helper fs evaluateFilter c mb a (NotFilter flt) = not <$> evaluateFilter c mb a flt evaluateFilter c mb a (TrueFilter getter) = -- GitLab