-
Notifications
You must be signed in to change notification settings - Fork 60
add PrimArray, Arr class #64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
After reading #63 , i think it's probable a good idea to keep pinning status in reszied array, ideas? |
OK, all build errors are fixed. There should be no problem with older GHC now. |
Small life tip: if you change your
Then on github, your commits will be attributed to your user instead of being attributed to "handong", who is unknown to github. |
I've put up a PR against your branch fixing minor documentation typos: winterland1989#1 |
fix minor typos in documentation
Thanks! |
I dislike the current Also, for very different reasons, I do not like the overlapping instance for I would prefer that fast versions of equality and of comparison be provided as functions but that they not be used to attempt to optimize the |
Description : Bounded checked boxed and unboxed arrays | ||
Copyright : (c) Winter, 2017 | ||
License : BSD3 | ||
Maintainer : libraries@haskell.org, drkoster@qq.com |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
who's dr koster?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's my email.
Data/Primitive/Array/Checked.hs
Outdated
check :: String -> Bool -> a -> a | ||
check _ True x = x | ||
check errMsg False _ = throw (IndexOutOfBounds $ "Data.Array.Checked." ++ errMsg) | ||
{-# INLINE check #-} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for this module, does INLINE pragmas make sense? theres definitely no fusion going on , and to quote @thoughtpolice on the topic, if ghc isn't marking them inlinable when they're small enough, thats a ghc bug ..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure because I really need this function inlined to reduce the overhead of bound check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, i meant the inlines everywhere, valid forthis one i guess ;)
Data/Primitive/Array/Class.hs
Outdated
-- | A typeclass to unify box & unboxed, mutable & immutable array operations. | ||
-- | ||
-- Most of these functions simply wrap their primitive counterpart. If there are no primitive ones, | ||
-- the method is polyfilled using other operations to get the same semantics. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i dont like the word polyfilled, can we use something like "emulated"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also should this interface also support (when applicable) arrays of unlifted pointer values via ArrayArray?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This interface support ArrayArray , though the newArr
for ArrayArray is more unsafe, I should add more doc about this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docs added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@winterland1989 my point about the term poly filled still stands right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@winterland1989 can we change polyfilled to emulated with?
Data/Primitive/Array/Class.hs
Outdated
-- One exception is that 'shrinkMutableArr' only performs resizing on 'PrimArray' because | ||
-- the RTS only supports shrinking byte arrays. On other array types, 'shrinkMutableArr' will do nothing. | ||
-- | ||
class Arr (marr :: * -> * -> *) (arr :: * -> * ) a | arr -> marr, marr -> arr where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My immediate concern when seeing this interface is that this doesn't allow the same interface to work For ArrayArray too! Then we can't have a nice interface for arrays of unlifted values!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you give a reason why that's the case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm thinking we could have, at least on recent ghc, something like
marr :: * -> TYPE r -> *
, and arr :: TYPE r -> *
, which is like having representation genericity, but in a static / allowed way
@@ -137,6 +141,22 @@ instance PrimUnlifted (MV.MutVar s a) where | |||
toArrayArray# (MV.MutVar mv#) = unsafeCoerce# mv# | |||
fromArrayArray# aa# = MV.MutVar (unsafeCoerce# aa#) | |||
|
|||
instance PrimUnlifted (MVar a) where | |||
toArrayArray# (MVar mv#) = unsafeCoerce# mv# |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait what. This doesn't seem safe .. could you explain this mapping to me?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and all the associated other unsafe coerces too ..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To my understanding, ArrayArray#
can hold any values whose type is of kind TYPE UnliftedRep
. This seems safe to me, but it would be nice to have that confirmed by someone else. @bgamari Can you comment on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think it's safe too, and I'm using this instance in my libuv binding without problems. The newly added instances are really not differ from MutVar , they are unlifted boxed pointers just like ArrayArray.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bgamari , though i'm pretty sure this works, I think we need your confirm here too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm not sure i'm comfortable with this code... this is pretty ... dangerous to use, more so than most
https://ghc.haskell.org/trac/ghc/wiki/Commentary/Rts/Storage/HeapObjects documents some of the representation info, i'm not sure if we can in good consciousness expose that in an modulre that doesn't have Unsafe in the name...
i guess i'm also wondering what we'd use those for?
in some ways it sort of feels like this is a less safe version of the api that the structs lib accomplishes, though @ekmett and @glguy can probably opine on this piece perhaps
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you look at my ArrayArray#
wrapping stuff, you'll see the same thing. The primop API is that ArrayArray#
stores values of type ArrayArray#
, and you unsafeCoerce
between that and the type you actually want. I agree it's not a great API, but it's what we have right now.
In the future, maybe there will be an array type that is polymorphic over unlifted types that could be more safe at the primop level. But right now the API I wrote is the safe wrapper around the unsafe API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current definition of |
@andrewthad I'm agreed that the equal instances is surprising if someone provide a different eq instance for the element. It will not work unless it bit wise equal like all the current primitive type. I will make the change. As for the shrinking interface, I don't it is a trouble because ghc never guarantee a shrinking on primitive array is successful, it should be used to optimize GC of an array: when you are building array with double allocating strategy, you may end with an array with unused element in the tail. You don't want next GC copy them so you want to shrinking the closure size. But if that is not feasible, we should return the closure as it is, rather than allocate new one and copy. In short words, it's different from I think we can open a issue to ask ghc developers to add shrink for other array types, but this interface should stay IMO. |
I opened a ghc ticket for asking shrink primops for other array type here: https://ghc.haskell.org/trac/ghc/ticket/14124 But again, i'm defending that current |
@andrewthad I think i need to be convinced this do have a problem before change AFAICT, |
@andrewthad why cant the class support both lifted and unlifted element arrays for the boxed flavors? granted, this is supposed to be helper tools for higher level libraries :) |
@cartazio Ah, now I see what you're talking about. Yeah, I think that would be an alright small place to try that out. |
@andrewthad indeed, and it doesnt' hurt that it would also be even more generic than just that, i think? @winterland1989 @andrewthad i almost feel like this code review would be easier if we just did a long email thread back and forth with explicit diffs off a commit on master? idk. |
Speaking of levity polymorphism, I kind of wonder off and on how much of this package will be rendered obsolete by it. Wrapping all the primitive array/reference types becomes less necessary, because the boxed, unlifted kind gains most of the advantages of I guess the byte array wrapper still makes sense, and some convenience classes for working with unlifted things can live here. But it might radically alter the package (at least, after we get to a point where versions of GHC without levity polymorphism are considered unworthy of supporting). |
inline Eq rules instead of using CPP
@cartazio I can make a patch mail to And i still can understand your concern with newly added In fact the absence of |
Hrmmm. Are we talking about MVar / or MVar#?
I guess I'm just confused cause I'm learning something new. Care to point
me to the way you'd use this?
…On Thu, Aug 17, 2017 at 10:59 PM winterland ***@***.***> wrote:
@cartazio <https://github.com/cartazio> I can make a patch mail to
***@***.***, but this patch is rather large and contains
several commits, do i have to rebase then? I think github's code review
tools is quite nice, but if you prefer email, i can generate one.
And i still can understand your concern with newly added PrimUnlifted
instances, they works just like how old MutVar works, i need this because
in one of my project i use an array of MVar, i want to cut the memory
overhead.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#64 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAAQwvIhnKGnK800w8CsB4DznRSMkFJyks5sZP4jgaJpZM4O3IIf>
.
|
I'm talking In short words: I need an array of |
ok, so the unsafe coerce shouldn't be needed in ghc 8.2 right because you
can just unbox the mvar's directly into the correct kind, right?
…On Fri, Aug 18, 2017 at 11:41 AM, winterland ***@***.***> wrote:
I'm talking UnliftedArray (MVar a) which actually store MVar# s. the use
case is here: https://github.com/winterland1989/stdio/blob/
master/System/IO/UV/Manager.hs#L67
In short words: I need an array of MVar to block the thread doing
read/write. and after read/write finish i unblock them by index.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#64 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAAQwvNetXyX_vZa8Q0a3e23Sz0P1PYTks5sZbCPgaJpZM4O3IIf>
.
|
@cartazio the unsafe coerce is still needed in GHC 8.2. To do what you're describing, we would need a primitive like this:
Such a function could replace |
@cartazio It's irrelevant to levity polymorphism , the trick's idea is that |
@cartazio I wrote a blog post about the unlifted array stuff: http://winterland.me/2017/08/18/an%20unified%20array%20interface/ . I hope that can clear your concern about my extension to BTW, this patch is ready, please consider merging if no other problems. |
Awesome. I'll do a final go over later today / tomorrow
…On Tue, Aug 22, 2017 at 11:00 AM winterland ***@***.***> wrote:
@cartazio <https://github.com/cartazio> I wrote a blog post about the
unlifted array stuff:
http://winterland.me/2017/08/18/an%20unified%20array%20interface/ . I
hope that can clear your concern about my extension to PrimUnlifted.
BTW, this patch is ready, please consider merging if no other problems.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#64 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAAQwkV9Y03lrK8VC73l9_3Mc6SqSn2Pks5sauz7gaJpZM4O3IIf>
.
|
@@ -18,5 +19,6 @@ void hsprimitive_memset_Float (HsFloat *, ptrdiff_t, size_t, HsFloat); | |||
void hsprimitive_memset_Double (HsDouble *, ptrdiff_t, size_t, HsDouble); | |||
void hsprimitive_memset_Char (HsChar *, ptrdiff_t, size_t, HsChar); | |||
|
|||
int hsprimitive_is_byte_array_pinned(void* p); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The question of why we aren't simply using the primop deserves a comment.
c_is_byte_array_pinned :: ByteArray# -> CInt | ||
|
||
foreign import ccall unsafe "hsprimitive_is_byte_array_pinned" | ||
c_is_mutable_byte_array_pinned :: MutableByteArray# s -> CInt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should really use the primop whenever possible. Afterall, the C version may break with future GHC releases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you're right. I've add CPPs to use primops where possible.
Sorry, I've been a bit distracted lately. I'm going to look through this a bit closer in preparation for merging (also see what conflicts need to be solved; probably nothing major, so I can maybe do it myself, without needing you to rebase). |
@dolio Thanks, if need anything please let me know. |
-- Most of these functions simply wrap their primitive counterpart. If there are no primitive ones, | ||
-- the method is emulated using other operations to get the same semantics. | ||
-- | ||
class Arr (marr :: * -> * -> *) (arr :: * -> * ) a | arr -> marr, marr -> arr where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why everything is lumped in one class. I think it makes more sense to have three:
class MutArr (marr :: * -> * -> *) a where
newArr :: ...
newArrWith :: ...
readArr :: ...
writeArr :: ...
setArr :: ...
copyMutableArr :: ...
moveArr :: ...
cloneMutableArr :: ...
sameMutableArr :: ...
sizeofMutableArr :: ...
shrinkMutableArr :: ...
resizeMutableArr :: ...
class ImmutArr (arr :: * -> *) a where
indexArr# :: arr a -> Int -> (# a #)
-- Leave indexArr and indexArrM out of the class as they can easily be implemented
-- as functions given indexArr#; going the other way is a good bit harder for humans
-- and optimizers.
-- cloneArr strikes me as a bit fishy. What's its story?
cloneArr :: ...
sameArr :: ...
sizeofArr :: ...
class (ImmutArr arr a, MutArr marr a) => Arr marr arr a | arr -> marr, marr -> arr where
freezeArr :: ...
unsafeFreezeArr :: ...
thawArr :: ...
unsafeThawArr :: ...
copyArr :: ...
LT -> | ||
let !d = s2 - s1 | ||
!s2l = s2 + l | ||
go !i | i >= s2l = return () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use when
or unless
to avoid writing out return ()
branches.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very much apart from everything else, this pull request is very large. Lots of new functionality. I suspect it might be better to break it up. One of the big potential advantages of adding a class for basic array access is that we might be able to share a lot of code between Array
and SmallArray
, so their many instances can look like
instance Functor SmallArray where
fmap = fmapArray
where fmapArray
looks something like
fmapArray :: (ImmutableArray ary a, Arr mary ary b) => (a -> b) -> ary a -> ary b
|
||
{-# RULES "eqPrimArray/Addr" eqPrimArray = memcmpPrimArray (undefined :: Addr) #-} | ||
{-# RULES "eqPrimArray/Ptr" eqPrimArray = memcmpPrimArray (undefined :: Ptr a) #-} | ||
{-# RULES "eqPrimArray/FunPtr" eqPrimArray = memcmpPrimArray (undefined :: FunPtr a) #-} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ugh... Wouldn't it be better to use a class for eqPrimArray
? Rules are fragile, and require user involvement, and so on. It's not great. Separately, passing undefined
is rather old-fashioned. Use a proxy type instead.
i need to revisit this PR and review it properly |
Currently, #106 implements just the
Some of these have been addressed by recent PRs. I suspect that, at this point, it may be best to break pieces off of this PR into other PRs. This is especially important for typeclass that unifies the interface to arrays, since there's some bikeshedding possible there. |
After reading this over, I much prefer the API defined in Maybe others can chime in here. |
Also, the PrimArray changes have already happened. I'm referring specifically to the |
The |
This is the
PrimArray
patch as @bgamari requested, This patch also offer polymorphricArr
class which unify boxed and unboxed array interface. Please review carefully because there may be bugs ; )I haven't consider much compatibility issue when i'm doing this, so please add whateverI have addedCPP
needed to make it work on older GHCs.CPP
s and CI is happy now.I'm planning to make another patch which bringI believe fusion belongs to high level vector package now, so this is the full patch already, please review and merge(if there's no objections) ASAP.foldr/build
fusion to these arrays, please don't cut a new release before that is done.