- Mini garbage collector: When using Haskell types as data type for Judy Maps, if no translation to/from Value (defined by Refeable class) is available it uses a default one, which relies on StablePtrs. Using this is a safe way to prevent data from being freed by GHC, but we must free them explicitly, and there's the problem: as sometimes we have the same value in two different keys, and GHC may assign the same StablePtr to them (sometimes it won't and because of this StablePtrs can't be used as keys), we can't just call freeStablePtr when some key is deleted from a Judy Map, because the StablePtr could be being used by other key.
The chosen solution by now is using a global auxiliary garbage collector (using a simple Judy map as backend) that deals with creation and freeing of StablePtrs, it mantains a refcount of each one and only free when it reaches zero. To avoid calling GC when not necessary, Refeable class has a needGC member, that is checked to see if GC functions need to be called. For example, when Int is used as value type, no GC is needed as it just convert Int -> Value directly. Also used a NOINLINE trick to make the GC unique and global. - Bugs and odd problems: The HSIter problem when using a lot of memory before was a forget-to-initializate mistake, and is solved (and tested). Another bug that disappeared is an faulty binary that were generated when defining a generic instance for Refeable type, the workaround (not necessary anymore) were create a Dummy class that had all types instantiated and use this Dummy class for context to the Refeable instantiation (not easy to explain).
- API: all map types use a single interface defined by MapM class (inspired by Collections API), also all them have a Freeze equivalent, that can be used outside the IO monad. No Data.HashTable-like interface yet, it seems to be unnecessary as MapM has very similar interface, but is do-able (considering that hash function and equality function will be ignored). The only problem I think is that there's no easy way to simulate having more than one value inside the same type, but don't think it's necessary.
- Benchmarks: First, tried a test program called CheckDup, which checks for duplicates in files and the results were positive for Judy Map types. Also it seems I did something wrong in using ByteString, probably unnecessary conversions between BS and String, need to check, but for String-only Judy is between 4 and 5 times faster. I couldn't measure memory very precisely, but Judy runs were also more cheaper.
Then I tried RBR bioinformatics software, it time was being mainly bounded by use of Data.Map. One of the tests runs in 1m41s and top memory usage (which is hit in about 1m) is 488MB. Using Judy.Map2 (backended by JudyL in C) in the same situation (sometimes only a word isn't enough for key data, but in this case it is, also AFAIK in most cases, but I'm checking with RBR's developer), it takes only 32s and 110MB of memory.
Following this bioinformatics thread, I tried translating GHC simplest K-Nucleotide (which took 35s here) to use Judy, resulting in a 13s run. Memory (was watching top(1) output) usage was cheaper for Judy version. The other versions (#2 and #3) didn't worked in my machine (maybe because I'm in AMD64?). Judy version of entry is available in tests directory. - Testing: did some funny syntax for testing and turned the output to a Test::Harness::TAP format (from perl), so make test can make use of Test::Harness. Not very Haskell, but nice. Still need to check monad support of QuickCheck as all tests are very IO dependant.
- Next steps: Patch for Pugs Array and Hash. Spike some Array-like stuff, implementing something using MArray interface. Check if DiffArray works with that. Look at Bulat's Unbounded array stuff to see if I could gather something, Judy role in Array camp is to be the good sparse array implementation. Refine MapM so it get "releseable".
2006-07-30
Recap
Let's use this to do a "long recap for myself":
Subscribe to:
Posts (Atom)