[GHC] #9353: prefetch primops are not currently useful

GHC ghc-devs at haskell.org
Wed Jul 23 19:27:51 UTC 2014


#9353: prefetch primops are not currently useful
-------------------------------------+-------------------------------------
              Reporter:              |            Owner:
  MikeIzbicki                        |           Status:  new
                  Type:  bug         |        Milestone:
              Priority:  normal      |          Version:  7.8.2
             Component:  Compiler    |         Keywords:
            Resolution:              |     Architecture:  Unknown/Multiple
      Operating System:              |       Difficulty:  Unknown
  Unknown/Multiple                   |       Blocked By:
       Type of failure:              |  Related Tickets:
  None/Unknown                       |
             Test Case:              |
              Blocking:              |
Differential Revisions:              |
-------------------------------------+-------------------------------------
Description changed by MikeIzbicki:

Old description:

> I wanted to use GHC's new prefetch primops to speed up a cover tree data
> structure I've been working on.  The current implementation, however, is
> insufficient.  The pure primops do not work at all.  I propose an
> alternative using a seq-like syntax.
>
> -------
> **The problem**
>
> Consider the function:
>
> {{{
> prefetchAddr3# :: Addr# -> Int# -> Addr#
> }}}
>
> It is used like:
>
> {{{
> -- addr# :: Addr#
>
> let prefetchAddr# = prefetchAddr3# addr# 0
>
> ... do some stuff not involving addr#
>
> doRealWork prefetchAddr#
>
> }}}
>
> The problem is that we want the prefetch operation to get inserted at the
> let statement before "do some stuff...", but it doesn't get inserted
> there.  It gets inserted directly before the call to doRealWork.  This
> doesn't give the prefetch enough time to actually put the memory in
> cache, and so we still get a cache miss.  I made several attempts to get
> around this, but they all failed due to dead code elimination.
>
> The `prefetchMutableByteArray#` functions solve this problem by
> incorporating an explicit state parameter.  This forces the compiler to
> insert the prefetch operation at the location it is actually called in
> the code.  This function, however, can only be used within the ST and IO
> monads, so it is of limited use.
>
> ------
> ** The solution**
>
> The solution is to restructure the pure primops to use a seq-like format.
> For example, the prefetchAddr3# function above would become:
>
> {{{
> prefetchAddr3# :: Addr# -> a -> a
> }}}
>
> Then we would call the function like:
>
> {{{
> prefetchAddr3# addr# someOtherOp
>
> ... do some stuff not involving addr#
>
> doRealWork prefetchAddr#
> }}}
>
> This would correctly insert the prefetch instruction at the location it
> appears in the haskell code.  In particular, the prefetch will occur
> whenever the second parameter is evaluated.
>
> This format has the advantage that it can work in non-monadic code.  In
> my cover tree structure, I've implemented searching the tree as a `fold`
> operation.  Every time the fold branches, only one of the branches is
> guaranteed to be in the cache.  So I get a cache miss when I go down the
> other branches.  I want to use the prefetch primop to prefetch the next
> branch the fold will go down.  The fold function is pure, and I don't
> want to have to wedge it into the ST monad just for prefetching.

New description:

 I wanted to use GHC's new prefetch primops to speed up a cover tree data
 structure I've been working on.  The current implementation, however, is
 insufficient.  The pure primops do not work at all.  I propose an
 alternative using a seq-like syntax.

 -------
 **The problem**

 Consider the function:

 {{{
 prefetchAddr3# :: Addr# -> Int# -> Addr#
 }}}

 It is used like:

 {{{
 -- addr# :: Addr#

 let prefetchAddr# = prefetchAddr3# addr# 0

 ... do some stuff not involving addr#

 doRealWork prefetchAddr#

 }}}

 The problem is that we want the prefetch operation to get inserted at the
 let statement before "do some stuff...", but it doesn't get inserted
 there.  It gets inserted directly before the call to doRealWork.  This
 doesn't give the prefetch enough time to actually put the memory in cache,
 and so we still get a cache miss.  I made several attempts to get around
 this, but they all failed due to dead code elimination.

 The `prefetchMutableByteArray#` functions solve this problem by
 incorporating an explicit state parameter.  This forces the compiler to
 insert the prefetch operation at the location it is actually called in the
 code.  This function, however, can only be used within the ST and IO
 monads, so it is of limited use.

 ------
 ** The solution**

 The solution is to restructure the pure primops to use a seq-like format.
 For example, the prefetchAddr3# function above would become:

 {{{
 prefetchAddr3# :: Addr# -> Int# -> a -> a
 }}}

 Then we would call the function like:

 {{{
 prefetchAddr3# addr# someOtherOp

 ... do some stuff not involving addr#

 doRealWork prefetchAddr#
 }}}

 This would correctly insert the prefetch instruction at the location it
 appears in the haskell code.  In particular, the prefetch will occur
 whenever the second parameter is evaluated.

 This format has the advantage that it can work in non-monadic code.  In my
 cover tree structure, I've implemented searching the tree as a `fold`
 operation.  Every time the fold branches, only one of the branches is
 guaranteed to be in the cache.  So I get a cache miss when I go down the
 other branches.  I want to use the prefetch primop to prefetch the next
 branch the fold will go down.  The fold function is pure, and I don't want
 to have to wedge it into the ST monad just for prefetching.

--

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9353#comment:1>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list