RE: Array operations and pinning

On 02 November 2005 11:15, Rene de Visser wrote:
Where is the documentation on how pinning works in the GHC garbage collector (from a GHC users point of view).
I have copied the following code from array/IO.hs and am thinking that it is assuming that the array is pinned? What triggers the pinning?
Actually this code does not assume that any memory is pinned. It is ok to pass the underlying ByteArr# directly to C, as long as the C call is annotated "unsafe", which means that GC cannot happen while the call is running. If you want to pass ByteArr# to a "safe" C call, then you have to allocate the ByteArr# using newPinnedByteArray#. This is the only way to get a pinned object in GHC, and the only kind of pinned object that is supported is a MutByteArr# or ByteArr# (this is to simplify the GC; it doesn't need to traverse pinned objects because they don't contain any pointers, all it needs to do is remember that the memory block they occupy is still alive). Note that all this is GHC-specific; the right high-level interface to allocating pinned memory is mallocForeignPtr.
On a second note. Why is the type signiture so constricted. The code below works on any IOUArray (which is very usefull, not just on Int Word8). Naturally this assumes the particular in memory array layout that GHC uses on a particular platform, so would not be compatible (probably) with other Haskell compilers.
I think the type is right - it makes it clear that the representation being written to the file is an array of bytes. You can use castIOUArray, although that isn't ideal (it doesn't change the bounds). We should do something better here. Cheers, Simon

I suggest that the code in GHC.Arr be changed from
error "Error in array index"
to
error "Error in array index" ++ show b ++ show i
so that the bounds and offending index is shown. This is easy to do as the
information is already available, and would in most cases be of great help
to the user in guessing which code was causing the error.
Background:
I have some stochastic estimation code which after a few hours running
produces this error.
I then recompiled with full profiling and did
C:\Haskell\dev>main +RTS -xc
main +RTS -xc

Rene de Visser wrote:
I suggest that the code in GHC.Arr be changed ... to error "Error in array index" ++ show b ++ show i
This would introduce Show constraints for (!) everywhere which probably is undesirable as it would break code. I had to trace a similar error recently and I ended up writing a module that imports Data.Array and re-exports everything except (!) which I replaced with a version like the one above. Slightly unrelated, it is generally a good idea not to import system libraries (e. g. Data.*) in too many places because the application program should define its own abstractions (which can then be implemented using the pre-defined abstractions from Data.* but this should be hidden). Unnecessary exposure of implementation details is called "primitive obsession" by the OO design folks, see e. g. http://foozle.berkeley.edu/projects/streek/agile/bad-smells-in-code.html#Pri... You might object that if everyone writes his own types for everything, then there can be no generally useful libraries (since they don't know the types) but of course there can - relying on a well-defined set of interfaces (type classes) that user-defined types can implement. Best regards, -- -- Johannes Waldmann -- Tel/Fax (0341) 3076 6479/80 -- ---- http://www.imn.htwk-leipzig.de/~waldmann/ -------

Hello Rene, Sunday, November 06, 2005, 10:35:48 PM, you wrote: RdV> I suggest that the code in GHC.Arr be changed from RdV> error "Error in array index" RdV> to RdV> error "Error in array index" ++ show b ++ show i one time i complained the close problem SPJ answered me: | also it will be cool to have ability to add such annotations to my own | functions, smthg like: | | head (x:xs) = x | head [] = superError "head []" | | which will print: "Error: head [] in Module.hs:155" A difficulty is that the caller of 'head' might itself be called from somewhere else: foo (xs, ys) = head xs It's not much help to know that head failed when called from foo; you want to know where foo is called from. In short, you really want the whole call stack. But trimmed in the recursive case... It's all very like cost-centre stacks, which is why GHC provides the -xc option when you are profiling. I think that give you what you want --- but you have to compile your program profiled. Another take on this is that you want an implicit parameter head :: (%loc :: Location) => [a] -> a so that 'head' can report %loc when it fails. Now you'd need to give rules to say where %loc is bound. It'd be a pretty magic kind of implicit parameter. Or should it be a stack of locations? I'm not belittling the underlying problem, which is real. But there do seem to be many possible design choices without an obvious optimium. If someone can boil out a principled and simple solution, it'd be a good contribution. Simon -- Best regards, Bulat mailto:bulatz@HotPOP.com

jhc has a SRCLOC_ANNOTATE pragma to solve just this problem here is the relevant part of the docs: * SRCLOC_ANNOTATE pragma. This is a generalization of GHCs assert magic. A function which is given an SRCLOC_ANNOTATE pragma will be replaced with an alternate version that takes the functions use site as an argument. This allows error messages to be in terms of where said function was used. The alternate function is named [function]_srcloc_ann__ and must be in the same module as the original function. Jhc does no checking to ensure both functions have the same effect, it is up to the user to ensure that. An example is
head :: [a] -> a head (x:xs) = x head [] = error "head - empty list"
{-# SRCLOC_ANNOTATE head #-}
head_srcloc_ann__ :: String -> [a] -> a head_srcloc_ann__ pos (x:xs) = x head_srcloc_ann__ pos [] = error $ pos ++ ": head - empty list"
-- Now, a call to head on an empty list will produce an error message like -- "Main.hs:23: head - empty list"
much nicer than implicit parameters IMHO and it is up to the writer of the library to decide how far up they care to propagate srclocs from so the compiler need not make an arbitrary decision. (and it is pretty dead-simple to implement) John -- John Meacham - ⑆repetae.net⑆john⑈

Bulat Ziganshin
RdV> I suggest that the code in GHC.Arr be changed from RdV> error "Error in array index" RdV> to RdV> error "Error in array index" ++ show b ++ show i
| also it will be cool to have ability to add such annotations to my own | functions, smthg like: | | head (x:xs) = x | head [] = superError "head []" | | which will print: "Error: head [] in Module.hs:155"
Of course, there is the old stand-by C pre-processor trick: #define superError(s) error (s++"\nin file "++__FILE__ \ ++" at line "++__LINE__) Whilst we are wishing for language features, I wonder if anyone else would be interested in being able to export/import such cpp macros using the normal Haskell module mechanism? At the moment, it is ugly that you need to either #include or #define your macros separately in every module where you use them. But if the cpp phase were integrated more tightly into the compiler, it could be possible to treat macros almost like ordinary function definitions. Regards, Malcolm

On Tue, Nov 08, 2005 at 02:43:47PM +0000, Malcolm Wallace wrote:
Of course, there is the old stand-by C pre-processor trick:
#define superError(s) error (s++"\nin file "++__FILE__ \ ++" at line "++__LINE__)
There is a nice trick I saw in darcs' code to make this even more Haskellish: #define superError (\s -> error (s++"\nin file "++ __FILE__ \ ++" at line "++ show (__LINE__ :: Int))) so you can simply write: superError "message" Best regards Tomasz

Tomasz Zielonka wrote:
On Tue, Nov 08, 2005 at 02:43:47PM +0000, Malcolm Wallace wrote:
Of course, there is the old stand-by C pre-processor trick:
#define superError(s) error (s++"\nin file "++__FILE__ \ ++" at line "++__LINE__)
There is a nice trick I saw in darcs' code to make this even more Haskellish:
#define superError (\s -> error (s++"\nin file "++ __FILE__ \ ++" at line "++ show (__LINE__ :: Int)))
so you can simply write:
superError "message"
Don't you also need to define "head" as a CPP macro (otherwise you'll just get the location of "head", and I'm sure you know where to find that already)? #define head (\xs -> case xs of { (x:_) -> x ; _ -> superError "head: empty list"}) Unfortunately, I don't think CPP will play nicely with operators like ! :-( There really should be a better way to do this, "head: empty list", "read: no parse" etc is high on my list of Haskell annoyances. -k
participants (8)
-
Bulat Ziganshin
-
Johannes Waldmann
-
John Meacham
-
Ketil Malde
-
Malcolm Wallace
-
Rene de Visser
-
Simon Marlow
-
Tomasz Zielonka