
On Sun, 2012-02-19 at 21:06 +0100, Bas van Dijk wrote:
On 19 February 2012 18:11, Maxime Henrion
wrote: I'm guilty of not having preserved the "rnf :: a -> ()" function as the class function though, it's a wrapper around "deepseq" in my code. I just didn't see the point of having a class function with such a signature versus having a function just like "seq :: a -> b -> b". In retrospect, that might have been a bad idea, and maybe I should switch to have an "rnf :: a -> ()" class function to make switching even easier?
I'm not sure but maybe a method like "rnf :: a -> ()" is easier to optimize.
Also in my experience (with generics support in aeson and cereal) it's a very good idea (performance-wise) to INLINE your methods like I did in my previous message. Of course the only way to know for sure is the create some (criterion) benchmarks.
Well I wrote some dumb criterion benchmarks that run deepseq over increasingly bigger lists of numbers, and it appears that using rnf as the member function of the DeepSeq class indeed makes a _huge_ difference. According to criterion, the performance of the old generic-deepseq code was 6 to 7 times worse than that of the deepseq package. After switching the class function to rnf, it got on par, if not better than the deepseq package. I'm saying "if not", because I've observed contradicting results from criterion, when I ran benchmarks for both packages at once, and when I ran those separately. When running both at once, generic-deepseq is slower than deepseq, except for the test with the bigger list (see report-both.html). When ran separately, generic-deepseq is consistantly faster (see report-deepseq.html and report-gdeepseq.html). The criterion benchmark can be found on the bitbucket repo at http://mu.org/~mux/report-deepseq.html. I have released a 2.0.0.0 version of this package on hackage with this change and a few more instances for base types. Cheers, Maxime Henrion