Scavenging SRTs in scavenge_one

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Scavenging SRTs in scavenge_one

Ben Gamari-3
Hi Simon,

I'm a bit confused by scavenge_one; namely it doesn't scavenge SRTs. It
appears that it is primarily used for remembered set entries but it's
not at all clear why this means that we can safely ignore SRTs (e.g. in
the FUN and THUNK cases).

Can you shed some light on this?

Cheers,

- Ben

_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

signature.asc (497 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Scavenging SRTs in scavenge_one

Ömer Sinan Ağacan
I have an idea but it doesn't explain everything;

SRTs are used to collect CAFs, and CAFs are always added to the oldest
generation's mut_list when allocated [1].

When we're scavenging a mut_list we know we're not doing a major GC, and
because mut_list of oldest generation has all the newly allocated CAFs, which
will be scavenged anyway, no need to scavenge SRTs for those.

Also, static objects are always evacuated to the oldest gen [2], so any CAFs
that are alive but not in the mut_list of the oldest gen will stay alive after
a non-major GC, again no need to scavenge SRTs to keep these alive.

This also explains why it's OK to not collect static objects (and not treat
them as roots) in non-major GCs.

However this doesn't explain

- Why it's OK to scavenge large objects with scavenge_one().

- Why we scavenge SRTs in non-major collections in other places (e.g.
  scavenge_block()).

Simon, could you say a few words about this?

[1]: https://github.com/ghc/ghc/blob/master/rts/sm/Storage.c#L445-L449
[2]: https://github.com/ghc/ghc/blob/master/rts/sm/Scav.c#L1761-L1763

Ömer

2018-03-28 17:49 GMT+03:00 Ben Gamari <[hidden email]>:

> Hi Simon,
>
> I'm a bit confused by scavenge_one; namely it doesn't scavenge SRTs. It
> appears that it is primarily used for remembered set entries but it's
> not at all clear why this means that we can safely ignore SRTs (e.g. in
> the FUN and THUNK cases).
>
> Can you shed some light on this?
>
> Cheers,
>
> - Ben
>
> _______________________________________________
> ghc-devs mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Scavenging SRTs in scavenge_one

Simon Marlow-7
Your explanation is basically right. scavenge_one() is only used for a non-major collection, where we aren't traversing SRTs. Admittedly this is a subtle point that could almost certainly be documented better, I probably just overlooked it.

More inline:

On 1 May 2018 at 10:26, Ömer Sinan Ağacan <[hidden email]> wrote:
I have an idea but it doesn't explain everything;

SRTs are used to collect CAFs, and CAFs are always added to the oldest
generation's mut_list when allocated [1].

When we're scavenging a mut_list we know we're not doing a major GC, and
because mut_list of oldest generation has all the newly allocated CAFs, which
will be scavenged anyway, no need to scavenge SRTs for those.

Also, static objects are always evacuated to the oldest gen [2], so any CAFs
that are alive but not in the mut_list of the oldest gen will stay alive after
a non-major GC, again no need to scavenge SRTs to keep these alive.

This also explains why it's OK to not collect static objects (and not treat
them as roots) in non-major GCs.

However this doesn't explain

- Why it's OK to scavenge large objects with scavenge_one().

I don't understand - perhaps you could elaborate on why you think it might not be OK? Large objects are treated exactly the same as small objects with respect to their lifetimes.
 
- Why we scavenge SRTs in non-major collections in other places (e.g.
  scavenge_block()).

If you look at scavenge_fun_srt() and co, you'll see that they return immediately if !major_gc.
 
Simon, could you say a few words about this?

Was that enough words? I have more if necessary :)

Cheers
Simon

 

[1]: https://github.com/ghc/ghc/blob/master/rts/sm/Storage.c#L445-L449
[2]: https://github.com/ghc/ghc/blob/master/rts/sm/Scav.c#L1761-L1763

Ömer

2018-03-28 17:49 GMT+03:00 Ben Gamari <[hidden email]>:
> Hi Simon,
>
> I'm a bit confused by scavenge_one; namely it doesn't scavenge SRTs. It
> appears that it is primarily used for remembered set entries but it's
> not at all clear why this means that we can safely ignore SRTs (e.g. in
> the FUN and THUNK cases).
>
> Can you shed some light on this?
>
> Cheers,
>
> - Ben
>
> _______________________________________________
> ghc-devs mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Scavenging SRTs in scavenge_one

Ömer Sinan Ağacan
Thanks Simon, this is really helpful.

> If you look at scavenge_fun_srt() and co, you'll see that they return
> immediately if !major_gc.

Thanks for pointing this out -- I didn't realize it's returning early when
!major_gc and this caused a lot of confusion. Now everything makes sense.

I'll add a note for scavenging SRTs and refer to it in relevant code and submit
a diff.

Ömer

2018-05-01 22:10 GMT+03:00 Simon Marlow <[hidden email]>:

> Your explanation is basically right. scavenge_one() is only used for a
> non-major collection, where we aren't traversing SRTs. Admittedly this is a
> subtle point that could almost certainly be documented better, I probably
> just overlooked it.
>
> More inline:
>
> On 1 May 2018 at 10:26, Ömer Sinan Ağacan <[hidden email]> wrote:
>>
>> I have an idea but it doesn't explain everything;
>>
>> SRTs are used to collect CAFs, and CAFs are always added to the oldest
>> generation's mut_list when allocated [1].
>>
>> When we're scavenging a mut_list we know we're not doing a major GC, and
>> because mut_list of oldest generation has all the newly allocated CAFs,
>> which
>> will be scavenged anyway, no need to scavenge SRTs for those.
>>
>> Also, static objects are always evacuated to the oldest gen [2], so any
>> CAFs
>> that are alive but not in the mut_list of the oldest gen will stay alive
>> after
>> a non-major GC, again no need to scavenge SRTs to keep these alive.
>>
>> This also explains why it's OK to not collect static objects (and not
>> treat
>> them as roots) in non-major GCs.
>>
>> However this doesn't explain
>>
>> - Why it's OK to scavenge large objects with scavenge_one().
>
>
> I don't understand - perhaps you could elaborate on why you think it might
> not be OK? Large objects are treated exactly the same as small objects with
> respect to their lifetimes.
>
>>
>> - Why we scavenge SRTs in non-major collections in other places (e.g.
>>   scavenge_block()).
>
>
> If you look at scavenge_fun_srt() and co, you'll see that they return
> immediately if !major_gc.
>
>>
>> Simon, could you say a few words about this?
>
>
> Was that enough words? I have more if necessary :)
>
> Cheers
> Simon
>
>
>>
>>
>> [1]: https://github.com/ghc/ghc/blob/master/rts/sm/Storage.c#L445-L449
>> [2]: https://github.com/ghc/ghc/blob/master/rts/sm/Scav.c#L1761-L1763
>>
>> Ömer
>>
>> 2018-03-28 17:49 GMT+03:00 Ben Gamari <[hidden email]>:
>> > Hi Simon,
>> >
>> > I'm a bit confused by scavenge_one; namely it doesn't scavenge SRTs. It
>> > appears that it is primarily used for remembered set entries but it's
>> > not at all clear why this means that we can safely ignore SRTs (e.g. in
>> > the FUN and THUNK cases).
>> >
>> > Can you shed some light on this?
>> >
>> > Cheers,
>> >
>> > - Ben
>> >
>> > _______________________________________________
>> > ghc-devs mailing list
>> > [hidden email]
>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>> >
>> _______________________________________________
>> ghc-devs mailing list
>> [hidden email]
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>
>
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Scavenging SRTs in scavenge_one

Ömer Sinan Ağacan
Hi Simon,

I'm confused about this code again. You said

> scavenge_one() is only used for a non-major collection, where we aren't
> traversing SRTs.

But I think this is not true; scavenge_one() is also used to scavenge large
objects (in scavenge_large()), which are scavenged even in major GCs. So it
seems like we never really scavenge SRTs of large objects. This doesn't look
right to me. Am I missing anything? Can large objects not refer to static
objects?

Thanks

Ömer

Ömer Sinan Ağacan <[hidden email]>, 2 May 2018 Çar, 09:03
tarihinde şunu yazdı:

>
> Thanks Simon, this is really helpful.
>
> > If you look at scavenge_fun_srt() and co, you'll see that they return
> > immediately if !major_gc.
>
> Thanks for pointing this out -- I didn't realize it's returning early when
> !major_gc and this caused a lot of confusion. Now everything makes sense.
>
> I'll add a note for scavenging SRTs and refer to it in relevant code and submit
> a diff.
>
> Ömer
>
> 2018-05-01 22:10 GMT+03:00 Simon Marlow <[hidden email]>:
> > Your explanation is basically right. scavenge_one() is only used for a
> > non-major collection, where we aren't traversing SRTs. Admittedly this is a
> > subtle point that could almost certainly be documented better, I probably
> > just overlooked it.
> >
> > More inline:
> >
> > On 1 May 2018 at 10:26, Ömer Sinan Ağacan <[hidden email]> wrote:
> >>
> >> I have an idea but it doesn't explain everything;
> >>
> >> SRTs are used to collect CAFs, and CAFs are always added to the oldest
> >> generation's mut_list when allocated [1].
> >>
> >> When we're scavenging a mut_list we know we're not doing a major GC, and
> >> because mut_list of oldest generation has all the newly allocated CAFs,
> >> which
> >> will be scavenged anyway, no need to scavenge SRTs for those.
> >>
> >> Also, static objects are always evacuated to the oldest gen [2], so any
> >> CAFs
> >> that are alive but not in the mut_list of the oldest gen will stay alive
> >> after
> >> a non-major GC, again no need to scavenge SRTs to keep these alive.
> >>
> >> This also explains why it's OK to not collect static objects (and not
> >> treat
> >> them as roots) in non-major GCs.
> >>
> >> However this doesn't explain
> >>
> >> - Why it's OK to scavenge large objects with scavenge_one().
> >
> >
> > I don't understand - perhaps you could elaborate on why you think it might
> > not be OK? Large objects are treated exactly the same as small objects with
> > respect to their lifetimes.
> >
> >>
> >> - Why we scavenge SRTs in non-major collections in other places (e.g.
> >>   scavenge_block()).
> >
> >
> > If you look at scavenge_fun_srt() and co, you'll see that they return
> > immediately if !major_gc.
> >
> >>
> >> Simon, could you say a few words about this?
> >
> >
> > Was that enough words? I have more if necessary :)
> >
> > Cheers
> > Simon
> >
> >
> >>
> >>
> >> [1]: https://github.com/ghc/ghc/blob/master/rts/sm/Storage.c#L445-L449
> >> [2]: https://github.com/ghc/ghc/blob/master/rts/sm/Scav.c#L1761-L1763
> >>
> >> Ömer
> >>
> >> 2018-03-28 17:49 GMT+03:00 Ben Gamari <[hidden email]>:
> >> > Hi Simon,
> >> >
> >> > I'm a bit confused by scavenge_one; namely it doesn't scavenge SRTs. It
> >> > appears that it is primarily used for remembered set entries but it's
> >> > not at all clear why this means that we can safely ignore SRTs (e.g. in
> >> > the FUN and THUNK cases).
> >> >
> >> > Can you shed some light on this?
> >> >
> >> > Cheers,
> >> >
> >> > - Ben
> >> >
> >> > _______________________________________________
> >> > ghc-devs mailing list
> >> > [hidden email]
> >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
> >> >
> >> _______________________________________________
> >> ghc-devs mailing list
> >> [hidden email]
> >> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
> >
> >
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Scavenging SRTs in scavenge_one

Simon Marlow-7
Interesting point. I don't think there are any large objects with SRTs, but we should document the invariant because we're relying on it.

Large objects can only be primitive objects, like MUT_ARR_PTRS, allocated by the RTS, and none of these have SRTs.

We did have plans to allocate memory for large dynamic objects using `allocate()` from compiled code, in which case we could have large objects that could be THUNK, FUN, etc. and could have an SRT, in which case we would need to revisit this.  You might want to take a look at Note [big objects] in GCUtils.c, which is relevant here.

Cheers
Simon


On 20 June 2018 at 09:20, Ömer Sinan Ağacan <[hidden email]> wrote:
Hi Simon,

I'm confused about this code again. You said

> scavenge_one() is only used for a non-major collection, where we aren't
> traversing SRTs.

But I think this is not true; scavenge_one() is also used to scavenge large
objects (in scavenge_large()), which are scavenged even in major GCs. So it
seems like we never really scavenge SRTs of large objects. This doesn't look
right to me. Am I missing anything? Can large objects not refer to static
objects?

Thanks

Ömer

Ömer Sinan Ağacan <[hidden email]>, 2 May 2018 Çar, 09:03
tarihinde şunu yazdı:
>
> Thanks Simon, this is really helpful.
>
> > If you look at scavenge_fun_srt() and co, you'll see that they return
> > immediately if !major_gc.
>
> Thanks for pointing this out -- I didn't realize it's returning early when
> !major_gc and this caused a lot of confusion. Now everything makes sense.
>
> I'll add a note for scavenging SRTs and refer to it in relevant code and submit
> a diff.
>
> Ömer
>
> 2018-05-01 22:10 GMT+03:00 Simon Marlow <[hidden email]>:
> > Your explanation is basically right. scavenge_one() is only used for a
> > non-major collection, where we aren't traversing SRTs. Admittedly this is a
> > subtle point that could almost certainly be documented better, I probably
> > just overlooked it.
> >
> > More inline:
> >
> > On 1 May 2018 at 10:26, Ömer Sinan Ağacan <[hidden email]> wrote:
> >>
> >> I have an idea but it doesn't explain everything;
> >>
> >> SRTs are used to collect CAFs, and CAFs are always added to the oldest
> >> generation's mut_list when allocated [1].
> >>
> >> When we're scavenging a mut_list we know we're not doing a major GC, and
> >> because mut_list of oldest generation has all the newly allocated CAFs,
> >> which
> >> will be scavenged anyway, no need to scavenge SRTs for those.
> >>
> >> Also, static objects are always evacuated to the oldest gen [2], so any
> >> CAFs
> >> that are alive but not in the mut_list of the oldest gen will stay alive
> >> after
> >> a non-major GC, again no need to scavenge SRTs to keep these alive.
> >>
> >> This also explains why it's OK to not collect static objects (and not
> >> treat
> >> them as roots) in non-major GCs.
> >>
> >> However this doesn't explain
> >>
> >> - Why it's OK to scavenge large objects with scavenge_one().
> >
> >
> > I don't understand - perhaps you could elaborate on why you think it might
> > not be OK? Large objects are treated exactly the same as small objects with
> > respect to their lifetimes.
> >
> >>
> >> - Why we scavenge SRTs in non-major collections in other places (e.g.
> >>   scavenge_block()).
> >
> >
> > If you look at scavenge_fun_srt() and co, you'll see that they return
> > immediately if !major_gc.
> >
> >>
> >> Simon, could you say a few words about this?
> >
> >
> > Was that enough words? I have more if necessary :)
> >
> > Cheers
> > Simon
> >
> >
> >>
> >>
> >> [1]: https://github.com/ghc/ghc/blob/master/rts/sm/Storage.c#L445-L449
> >> [2]: https://github.com/ghc/ghc/blob/master/rts/sm/Scav.c#L1761-L1763
> >>
> >> Ömer
> >>
> >> 2018-03-28 17:49 GMT+03:00 Ben Gamari <[hidden email]>:
> >> > Hi Simon,
> >> >
> >> > I'm a bit confused by scavenge_one; namely it doesn't scavenge SRTs. It
> >> > appears that it is primarily used for remembered set entries but it's
> >> > not at all clear why this means that we can safely ignore SRTs (e.g. in
> >> > the FUN and THUNK cases).
> >> >
> >> > Can you shed some light on this?
> >> >
> >> > Cheers,
> >> >
> >> > - Ben
> >> >
> >> > _______________________________________________
> >> > ghc-devs mailing list
> >> > [hidden email]
> >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
> >> >
> >> _______________________________________________
> >> ghc-devs mailing list
> >> [hidden email]
> >> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
> >
> >


_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Scavenging SRTs in scavenge_one

Ömer Sinan Ağacan
> Large objects can only be primitive objects, like MUT_ARR_PTRS, allocated by
> the RTS, and none of these have SRTs.

Is is not possible to allocate a large STACK? I'm currently observing this in
gdb:

    >>> call *Bdescr(0x4200ec9000)
    $2 = {
      start = 0x4200ec9000,
      free = 0x4200ed1000,
      link = 0x4200100e80,
      u = {
        back = 0x4200103980,
        bitmap = 0x4200103980,
        scan = 0x4200103980
      },
      gen = 0x77b4b8,
      gen_no = 1,
      dest_no = 1,
      node = 0,
      flags = 1027, <-- BF_LARGE | BF_EVACUTED | ...
      blocks = 8,
      _padding = {[0] = 0, [1] = 0, [2] = 0}
    }

    >>> call printClosure(0x4200ec9000)
    0x4200ec9000: STACK

    >>> call checkClosure(0x4200ec9000)
    $3 = 4096 -- makes sense, larger than 3277 bytes

So I have a large STACK object, and STACKs can refer to static objects. But
when we scavenge this object we don't scavenge its SRTs because we use
scavenge_one(). This seems wrong to me.

Ömer

Simon Marlow <[hidden email]>, 20 Haz 2018 Çar, 14:32 tarihinde şunu yazdı:

>
> Interesting point. I don't think there are any large objects with SRTs, but we should document the invariant because we're relying on it.
>
> Large objects can only be primitive objects, like MUT_ARR_PTRS, allocated by the RTS, and none of these have SRTs.
>
> We did have plans to allocate memory for large dynamic objects using `allocate()` from compiled code, in which case we could have large objects that could be THUNK, FUN, etc. and could have an SRT, in which case we would need to revisit this.  You might want to take a look at Note [big objects] in GCUtils.c, which is relevant here.
>
> Cheers
> Simon
>
>
> On 20 June 2018 at 09:20, Ömer Sinan Ağacan <[hidden email]> wrote:
>>
>> Hi Simon,
>>
>> I'm confused about this code again. You said
>>
>> > scavenge_one() is only used for a non-major collection, where we aren't
>> > traversing SRTs.
>>
>> But I think this is not true; scavenge_one() is also used to scavenge large
>> objects (in scavenge_large()), which are scavenged even in major GCs. So it
>> seems like we never really scavenge SRTs of large objects. This doesn't look
>> right to me. Am I missing anything? Can large objects not refer to static
>> objects?
>>
>> Thanks
>>
>> Ömer
>>
>> Ömer Sinan Ağacan <[hidden email]>, 2 May 2018 Çar, 09:03
>> tarihinde şunu yazdı:
>> >
>> > Thanks Simon, this is really helpful.
>> >
>> > > If you look at scavenge_fun_srt() and co, you'll see that they return
>> > > immediately if !major_gc.
>> >
>> > Thanks for pointing this out -- I didn't realize it's returning early when
>> > !major_gc and this caused a lot of confusion. Now everything makes sense.
>> >
>> > I'll add a note for scavenging SRTs and refer to it in relevant code and submit
>> > a diff.
>> >
>> > Ömer
>> >
>> > 2018-05-01 22:10 GMT+03:00 Simon Marlow <[hidden email]>:
>> > > Your explanation is basically right. scavenge_one() is only used for a
>> > > non-major collection, where we aren't traversing SRTs. Admittedly this is a
>> > > subtle point that could almost certainly be documented better, I probably
>> > > just overlooked it.
>> > >
>> > > More inline:
>> > >
>> > > On 1 May 2018 at 10:26, Ömer Sinan Ağacan <[hidden email]> wrote:
>> > >>
>> > >> I have an idea but it doesn't explain everything;
>> > >>
>> > >> SRTs are used to collect CAFs, and CAFs are always added to the oldest
>> > >> generation's mut_list when allocated [1].
>> > >>
>> > >> When we're scavenging a mut_list we know we're not doing a major GC, and
>> > >> because mut_list of oldest generation has all the newly allocated CAFs,
>> > >> which
>> > >> will be scavenged anyway, no need to scavenge SRTs for those.
>> > >>
>> > >> Also, static objects are always evacuated to the oldest gen [2], so any
>> > >> CAFs
>> > >> that are alive but not in the mut_list of the oldest gen will stay alive
>> > >> after
>> > >> a non-major GC, again no need to scavenge SRTs to keep these alive.
>> > >>
>> > >> This also explains why it's OK to not collect static objects (and not
>> > >> treat
>> > >> them as roots) in non-major GCs.
>> > >>
>> > >> However this doesn't explain
>> > >>
>> > >> - Why it's OK to scavenge large objects with scavenge_one().
>> > >
>> > >
>> > > I don't understand - perhaps you could elaborate on why you think it might
>> > > not be OK? Large objects are treated exactly the same as small objects with
>> > > respect to their lifetimes.
>> > >
>> > >>
>> > >> - Why we scavenge SRTs in non-major collections in other places (e.g.
>> > >>   scavenge_block()).
>> > >
>> > >
>> > > If you look at scavenge_fun_srt() and co, you'll see that they return
>> > > immediately if !major_gc.
>> > >
>> > >>
>> > >> Simon, could you say a few words about this?
>> > >
>> > >
>> > > Was that enough words? I have more if necessary :)
>> > >
>> > > Cheers
>> > > Simon
>> > >
>> > >
>> > >>
>> > >>
>> > >> [1]: https://github.com/ghc/ghc/blob/master/rts/sm/Storage.c#L445-L449
>> > >> [2]: https://github.com/ghc/ghc/blob/master/rts/sm/Scav.c#L1761-L1763
>> > >>
>> > >> Ömer
>> > >>
>> > >> 2018-03-28 17:49 GMT+03:00 Ben Gamari <[hidden email]>:
>> > >> > Hi Simon,
>> > >> >
>> > >> > I'm a bit confused by scavenge_one; namely it doesn't scavenge SRTs. It
>> > >> > appears that it is primarily used for remembered set entries but it's
>> > >> > not at all clear why this means that we can safely ignore SRTs (e.g. in
>> > >> > the FUN and THUNK cases).
>> > >> >
>> > >> > Can you shed some light on this?
>> > >> >
>> > >> > Cheers,
>> > >> >
>> > >> > - Ben
>> > >> >
>> > >> > _______________________________________________
>> > >> > ghc-devs mailing list
>> > >> > [hidden email]
>> > >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>> > >> >
>> > >> _______________________________________________
>> > >> ghc-devs mailing list
>> > >> [hidden email]
>> > >> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>> > >
>> > >
>
>
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Scavenging SRTs in scavenge_one

Ömer Sinan Ağacan
Here's an example where we allocate a large (4K) stack:

    >>> bt
    #0  allocateMightFail (cap=0x7f366808cfc0 <MainCapability>,
n=4096) at rts/sm/Storage.c:876
    #1  0x00007f3667e4a85d in allocate (cap=0x7f366808cfc0
<MainCapability>, n=4096) at rts/sm/Storage.c:849
    #2  0x00007f3667e16f46 in threadStackOverflow (cap=0x7f366808cfc0
<MainCapability>, tso=0x4200152a68) at rts/Threads.c:600
    #3  0x00007f3667e12a64 in schedule
(initialCapability=0x7f366808cfc0 <MainCapability>, task=0x78c970) at
rts/Schedule.c:520
    #4  0x00007f3667e1215f in scheduleWaitThread (tso=0x4200105388,
ret=0x0, pcap=0x7ffef40dce78) at rts/Schedule.c:2533
    #5  0x00007f3667e25685 in rts_evalLazyIO (cap=0x7ffef40dce78,
p=0x736ef8, ret=0x0) at rts/RtsAPI.c:530
    #6  0x00007f3667e25f7a in hs_main (argc=16, argv=0x7ffef40dd0a8,
main_closure=0x736ef8, rts_config=...) t rts/RtsMain.c:72
    #7  0x00000000004f738f in main ()

This is based on an old tree so source locations may not be correct, it's this
code in threadStackOverflow():

    // Charge the current thread for allocating stack.  Stack usage is
    // non-deterministic, because the chunk boundaries might vary from
    // run to run, but accounting for this is better than not
    // accounting for it, since a deep recursion will otherwise not be
    // subject to allocation limits.
    cap->r.rCurrentTSO = tso;
    new_stack = (StgStack*) allocate(cap, chunk_size);
    cap->r.rCurrentTSO = NULL;

    SET_HDR(new_stack, &stg_STACK_info, old_stack->header.prof.ccs);
    TICK_ALLOC_STACK(chunk_size);

Ömer
Ömer Sinan Ağacan <[hidden email]>, 21 Haz 2018 Per, 13:42
tarihinde şunu yazdı:

>
> > Large objects can only be primitive objects, like MUT_ARR_PTRS, allocated by
> > the RTS, and none of these have SRTs.
>
> Is is not possible to allocate a large STACK? I'm currently observing this in
> gdb:
>
>     >>> call *Bdescr(0x4200ec9000)
>     $2 = {
>       start = 0x4200ec9000,
>       free = 0x4200ed1000,
>       link = 0x4200100e80,
>       u = {
>         back = 0x4200103980,
>         bitmap = 0x4200103980,
>         scan = 0x4200103980
>       },
>       gen = 0x77b4b8,
>       gen_no = 1,
>       dest_no = 1,
>       node = 0,
>       flags = 1027, <-- BF_LARGE | BF_EVACUTED | ...
>       blocks = 8,
>       _padding = {[0] = 0, [1] = 0, [2] = 0}
>     }
>
>     >>> call printClosure(0x4200ec9000)
>     0x4200ec9000: STACK
>
>     >>> call checkClosure(0x4200ec9000)
>     $3 = 4096 -- makes sense, larger than 3277 bytes
>
> So I have a large STACK object, and STACKs can refer to static objects. But
> when we scavenge this object we don't scavenge its SRTs because we use
> scavenge_one(). This seems wrong to me.
>
> Ömer
>
> Simon Marlow <[hidden email]>, 20 Haz 2018 Çar, 14:32 tarihinde şunu yazdı:
> >
> > Interesting point. I don't think there are any large objects with SRTs, but we should document the invariant because we're relying on it.
> >
> > Large objects can only be primitive objects, like MUT_ARR_PTRS, allocated by the RTS, and none of these have SRTs.
> >
> > We did have plans to allocate memory for large dynamic objects using `allocate()` from compiled code, in which case we could have large objects that could be THUNK, FUN, etc. and could have an SRT, in which case we would need to revisit this.  You might want to take a look at Note [big objects] in GCUtils.c, which is relevant here.
> >
> > Cheers
> > Simon
> >
> >
> > On 20 June 2018 at 09:20, Ömer Sinan Ağacan <[hidden email]> wrote:
> >>
> >> Hi Simon,
> >>
> >> I'm confused about this code again. You said
> >>
> >> > scavenge_one() is only used for a non-major collection, where we aren't
> >> > traversing SRTs.
> >>
> >> But I think this is not true; scavenge_one() is also used to scavenge large
> >> objects (in scavenge_large()), which are scavenged even in major GCs. So it
> >> seems like we never really scavenge SRTs of large objects. This doesn't look
> >> right to me. Am I missing anything? Can large objects not refer to static
> >> objects?
> >>
> >> Thanks
> >>
> >> Ömer
> >>
> >> Ömer Sinan Ağacan <[hidden email]>, 2 May 2018 Çar, 09:03
> >> tarihinde şunu yazdı:
> >> >
> >> > Thanks Simon, this is really helpful.
> >> >
> >> > > If you look at scavenge_fun_srt() and co, you'll see that they return
> >> > > immediately if !major_gc.
> >> >
> >> > Thanks for pointing this out -- I didn't realize it's returning early when
> >> > !major_gc and this caused a lot of confusion. Now everything makes sense.
> >> >
> >> > I'll add a note for scavenging SRTs and refer to it in relevant code and submit
> >> > a diff.
> >> >
> >> > Ömer
> >> >
> >> > 2018-05-01 22:10 GMT+03:00 Simon Marlow <[hidden email]>:
> >> > > Your explanation is basically right. scavenge_one() is only used for a
> >> > > non-major collection, where we aren't traversing SRTs. Admittedly this is a
> >> > > subtle point that could almost certainly be documented better, I probably
> >> > > just overlooked it.
> >> > >
> >> > > More inline:
> >> > >
> >> > > On 1 May 2018 at 10:26, Ömer Sinan Ağacan <[hidden email]> wrote:
> >> > >>
> >> > >> I have an idea but it doesn't explain everything;
> >> > >>
> >> > >> SRTs are used to collect CAFs, and CAFs are always added to the oldest
> >> > >> generation's mut_list when allocated [1].
> >> > >>
> >> > >> When we're scavenging a mut_list we know we're not doing a major GC, and
> >> > >> because mut_list of oldest generation has all the newly allocated CAFs,
> >> > >> which
> >> > >> will be scavenged anyway, no need to scavenge SRTs for those.
> >> > >>
> >> > >> Also, static objects are always evacuated to the oldest gen [2], so any
> >> > >> CAFs
> >> > >> that are alive but not in the mut_list of the oldest gen will stay alive
> >> > >> after
> >> > >> a non-major GC, again no need to scavenge SRTs to keep these alive.
> >> > >>
> >> > >> This also explains why it's OK to not collect static objects (and not
> >> > >> treat
> >> > >> them as roots) in non-major GCs.
> >> > >>
> >> > >> However this doesn't explain
> >> > >>
> >> > >> - Why it's OK to scavenge large objects with scavenge_one().
> >> > >
> >> > >
> >> > > I don't understand - perhaps you could elaborate on why you think it might
> >> > > not be OK? Large objects are treated exactly the same as small objects with
> >> > > respect to their lifetimes.
> >> > >
> >> > >>
> >> > >> - Why we scavenge SRTs in non-major collections in other places (e.g.
> >> > >>   scavenge_block()).
> >> > >
> >> > >
> >> > > If you look at scavenge_fun_srt() and co, you'll see that they return
> >> > > immediately if !major_gc.
> >> > >
> >> > >>
> >> > >> Simon, could you say a few words about this?
> >> > >
> >> > >
> >> > > Was that enough words? I have more if necessary :)
> >> > >
> >> > > Cheers
> >> > > Simon
> >> > >
> >> > >
> >> > >>
> >> > >>
> >> > >> [1]: https://github.com/ghc/ghc/blob/master/rts/sm/Storage.c#L445-L449
> >> > >> [2]: https://github.com/ghc/ghc/blob/master/rts/sm/Scav.c#L1761-L1763
> >> > >>
> >> > >> Ömer
> >> > >>
> >> > >> 2018-03-28 17:49 GMT+03:00 Ben Gamari <[hidden email]>:
> >> > >> > Hi Simon,
> >> > >> >
> >> > >> > I'm a bit confused by scavenge_one; namely it doesn't scavenge SRTs. It
> >> > >> > appears that it is primarily used for remembered set entries but it's
> >> > >> > not at all clear why this means that we can safely ignore SRTs (e.g. in
> >> > >> > the FUN and THUNK cases).
> >> > >> >
> >> > >> > Can you shed some light on this?
> >> > >> >
> >> > >> > Cheers,
> >> > >> >
> >> > >> > - Ben
> >> > >> >
> >> > >> > _______________________________________________
> >> > >> > ghc-devs mailing list
> >> > >> > [hidden email]
> >> > >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
> >> > >> >
> >> > >> _______________________________________________
> >> > >> ghc-devs mailing list
> >> > >> [hidden email]
> >> > >> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
> >> > >
> >> > >
> >
> >
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Scavenging SRTs in scavenge_one

Simon Marlow-7
When scavenge_one() sees a STACK, it calls scavenge_stack() which traverses the stack frames, including their SRTs.

So I don't understand what's going wrong for you - how are the SRTs not being traversed?

Cheers
Simon

On 21 June 2018 at 11:58, Ömer Sinan Ağacan <[hidden email]> wrote:
Here's an example where we allocate a large (4K) stack:

    >>> bt
    #0  allocateMightFail (cap=0x7f366808cfc0 <MainCapability>,
n=4096) at rts/sm/Storage.c:876
    #1  0x00007f3667e4a85d in allocate (cap=0x7f366808cfc0
<MainCapability>, n=4096) at rts/sm/Storage.c:849
    #2  0x00007f3667e16f46 in threadStackOverflow (cap=0x7f366808cfc0
<MainCapability>, tso=0x4200152a68) at rts/Threads.c:600
    #3  0x00007f3667e12a64 in schedule
(initialCapability=0x7f366808cfc0 <MainCapability>, task=0x78c970) at
rts/Schedule.c:520
    #4  0x00007f3667e1215f in scheduleWaitThread (tso=0x4200105388,
ret=0x0, pcap=0x7ffef40dce78) at rts/Schedule.c:2533
    #5  0x00007f3667e25685 in rts_evalLazyIO (cap=0x7ffef40dce78,
p=0x736ef8, ret=0x0) at rts/RtsAPI.c:530
    #6  0x00007f3667e25f7a in hs_main (argc=16, argv=0x7ffef40dd0a8,
main_closure=0x736ef8, rts_config=...) t rts/RtsMain.c:72
    #7  0x00000000004f738f in main ()

This is based on an old tree so source locations may not be correct, it's this
code in threadStackOverflow():

    // Charge the current thread for allocating stack.  Stack usage is
    // non-deterministic, because the chunk boundaries might vary from
    // run to run, but accounting for this is better than not
    // accounting for it, since a deep recursion will otherwise not be
    // subject to allocation limits.
    cap->r.rCurrentTSO = tso;
    new_stack = (StgStack*) allocate(cap, chunk_size);
    cap->r.rCurrentTSO = NULL;

    SET_HDR(new_stack, &stg_STACK_info, old_stack->header.prof.ccs);
    TICK_ALLOC_STACK(chunk_size);

Ömer
Ömer Sinan Ağacan <[hidden email]>, 21 Haz 2018 Per, 13:42
tarihinde şunu yazdı:
>
> > Large objects can only be primitive objects, like MUT_ARR_PTRS, allocated by
> > the RTS, and none of these have SRTs.
>
> Is is not possible to allocate a large STACK? I'm currently observing this in
> gdb:
>
>     >>> call *Bdescr(0x4200ec9000)
>     $2 = {
>       start = 0x4200ec9000,
>       free = 0x4200ed1000,
>       link = 0x4200100e80,
>       u = {
>         back = 0x4200103980,
>         bitmap = 0x4200103980,
>         scan = 0x4200103980
>       },
>       gen = 0x77b4b8,
>       gen_no = 1,
>       dest_no = 1,
>       node = 0,
>       flags = 1027, <-- BF_LARGE | BF_EVACUTED | ...
>       blocks = 8,
>       _padding = {[0] = 0, [1] = 0, [2] = 0}
>     }
>
>     >>> call printClosure(0x4200ec9000)
>     0x4200ec9000: STACK
>
>     >>> call checkClosure(0x4200ec9000)
>     $3 = 4096 -- makes sense, larger than 3277 bytes
>
> So I have a large STACK object, and STACKs can refer to static objects. But
> when we scavenge this object we don't scavenge its SRTs because we use
> scavenge_one(). This seems wrong to me.
>
> Ömer
>
> Simon Marlow <[hidden email]>, 20 Haz 2018 Çar, 14:32 tarihinde şunu yazdı:
> >
> > Interesting point. I don't think there are any large objects with SRTs, but we should document the invariant because we're relying on it.
> >
> > Large objects can only be primitive objects, like MUT_ARR_PTRS, allocated by the RTS, and none of these have SRTs.
> >
> > We did have plans to allocate memory for large dynamic objects using `allocate()` from compiled code, in which case we could have large objects that could be THUNK, FUN, etc. and could have an SRT, in which case we would need to revisit this.  You might want to take a look at Note [big objects] in GCUtils.c, which is relevant here.
> >
> > Cheers
> > Simon
> >
> >
> > On 20 June 2018 at 09:20, Ömer Sinan Ağacan <[hidden email]> wrote:
> >>
> >> Hi Simon,
> >>
> >> I'm confused about this code again. You said
> >>
> >> > scavenge_one() is only used for a non-major collection, where we aren't
> >> > traversing SRTs.
> >>
> >> But I think this is not true; scavenge_one() is also used to scavenge large
> >> objects (in scavenge_large()), which are scavenged even in major GCs. So it
> >> seems like we never really scavenge SRTs of large objects. This doesn't look
> >> right to me. Am I missing anything? Can large objects not refer to static
> >> objects?
> >>
> >> Thanks
> >>
> >> Ömer
> >>
> >> Ömer Sinan Ağacan <[hidden email]>, 2 May 2018 Çar, 09:03
> >> tarihinde şunu yazdı:
> >> >
> >> > Thanks Simon, this is really helpful.
> >> >
> >> > > If you look at scavenge_fun_srt() and co, you'll see that they return
> >> > > immediately if !major_gc.
> >> >
> >> > Thanks for pointing this out -- I didn't realize it's returning early when
> >> > !major_gc and this caused a lot of confusion. Now everything makes sense.
> >> >
> >> > I'll add a note for scavenging SRTs and refer to it in relevant code and submit
> >> > a diff.
> >> >
> >> > Ömer
> >> >
> >> > 2018-05-01 22:10 GMT+03:00 Simon Marlow <[hidden email]>:
> >> > > Your explanation is basically right. scavenge_one() is only used for a
> >> > > non-major collection, where we aren't traversing SRTs. Admittedly this is a
> >> > > subtle point that could almost certainly be documented better, I probably
> >> > > just overlooked it.
> >> > >
> >> > > More inline:
> >> > >
> >> > > On 1 May 2018 at 10:26, Ömer Sinan Ağacan <[hidden email]> wrote:
> >> > >>
> >> > >> I have an idea but it doesn't explain everything;
> >> > >>
> >> > >> SRTs are used to collect CAFs, and CAFs are always added to the oldest
> >> > >> generation's mut_list when allocated [1].
> >> > >>
> >> > >> When we're scavenging a mut_list we know we're not doing a major GC, and
> >> > >> because mut_list of oldest generation has all the newly allocated CAFs,
> >> > >> which
> >> > >> will be scavenged anyway, no need to scavenge SRTs for those.
> >> > >>
> >> > >> Also, static objects are always evacuated to the oldest gen [2], so any
> >> > >> CAFs
> >> > >> that are alive but not in the mut_list of the oldest gen will stay alive
> >> > >> after
> >> > >> a non-major GC, again no need to scavenge SRTs to keep these alive.
> >> > >>
> >> > >> This also explains why it's OK to not collect static objects (and not
> >> > >> treat
> >> > >> them as roots) in non-major GCs.
> >> > >>
> >> > >> However this doesn't explain
> >> > >>
> >> > >> - Why it's OK to scavenge large objects with scavenge_one().
> >> > >
> >> > >
> >> > > I don't understand - perhaps you could elaborate on why you think it might
> >> > > not be OK? Large objects are treated exactly the same as small objects with
> >> > > respect to their lifetimes.
> >> > >
> >> > >>
> >> > >> - Why we scavenge SRTs in non-major collections in other places (e.g.
> >> > >>   scavenge_block()).
> >> > >
> >> > >
> >> > > If you look at scavenge_fun_srt() and co, you'll see that they return
> >> > > immediately if !major_gc.
> >> > >
> >> > >>
> >> > >> Simon, could you say a few words about this?
> >> > >
> >> > >
> >> > > Was that enough words? I have more if necessary :)
> >> > >
> >> > > Cheers
> >> > > Simon
> >> > >
> >> > >
> >> > >>
> >> > >>
> >> > >> [1]: https://github.com/ghc/ghc/blob/master/rts/sm/Storage.c#L445-L449
> >> > >> [2]: https://github.com/ghc/ghc/blob/master/rts/sm/Scav.c#L1761-L1763
> >> > >>
> >> > >> Ömer
> >> > >>
> >> > >> 2018-03-28 17:49 GMT+03:00 Ben Gamari <[hidden email]>:
> >> > >> > Hi Simon,
> >> > >> >
> >> > >> > I'm a bit confused by scavenge_one; namely it doesn't scavenge SRTs. It
> >> > >> > appears that it is primarily used for remembered set entries but it's
> >> > >> > not at all clear why this means that we can safely ignore SRTs (e.g. in
> >> > >> > the FUN and THUNK cases).
> >> > >> >
> >> > >> > Can you shed some light on this?
> >> > >> >
> >> > >> > Cheers,
> >> > >> >
> >> > >> > - Ben
> >> > >> >
> >> > >> > _______________________________________________
> >> > >> > ghc-devs mailing list
> >> > >> > [hidden email]
> >> > >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
> >> > >> >
> >> > >> _______________________________________________
> >> > >> ghc-devs mailing list
> >> > >> [hidden email]
> >> > >> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
> >> > >
> >> > >
> >
> >


_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Scavenging SRTs in scavenge_one

Ömer Sinan Ağacan
OK, finally everything makes sense I think. I was very confused by the code and
previous emails where you said:

> Large objects can only be primitive objects, like MUT_ARR_PTRS, allocated by
> the RTS, and none of these have SRTs.

I was pointing out that this is not entirely correct; we allocate large stacks.
But as you say scavenge_one() handles that case by scavenging stack SRTs.

So in summary:

- scavenge_one() is called to scavenge mut_lists and large objects.
- When scavenging mut_lists no need to scaveng SRTs (see previous emails)
- When scavenging large objects we know that certain objects can't be large
  (i.e. FUN, THUNK), but some others can (i.e. STACK), so scavenge_one()
  scavenges stack SRTs but does not scavenge FUN and THUNK SRTs.

Ömer

Simon Marlow <[hidden email]>, 21 Haz 2018 Per, 21:27 tarihinde şunu yazdı:

>
> When scavenge_one() sees a STACK, it calls scavenge_stack() which traverses the stack frames, including their SRTs.
>
> So I don't understand what's going wrong for you - how are the SRTs not being traversed?
>
> Cheers
> Simon
>
> On 21 June 2018 at 11:58, Ömer Sinan Ağacan <[hidden email]> wrote:
>>
>> Here's an example where we allocate a large (4K) stack:
>>
>>     >>> bt
>>     #0  allocateMightFail (cap=0x7f366808cfc0 <MainCapability>,
>> n=4096) at rts/sm/Storage.c:876
>>     #1  0x00007f3667e4a85d in allocate (cap=0x7f366808cfc0
>> <MainCapability>, n=4096) at rts/sm/Storage.c:849
>>     #2  0x00007f3667e16f46 in threadStackOverflow (cap=0x7f366808cfc0
>> <MainCapability>, tso=0x4200152a68) at rts/Threads.c:600
>>     #3  0x00007f3667e12a64 in schedule
>> (initialCapability=0x7f366808cfc0 <MainCapability>, task=0x78c970) at
>> rts/Schedule.c:520
>>     #4  0x00007f3667e1215f in scheduleWaitThread (tso=0x4200105388,
>> ret=0x0, pcap=0x7ffef40dce78) at rts/Schedule.c:2533
>>     #5  0x00007f3667e25685 in rts_evalLazyIO (cap=0x7ffef40dce78,
>> p=0x736ef8, ret=0x0) at rts/RtsAPI.c:530
>>     #6  0x00007f3667e25f7a in hs_main (argc=16, argv=0x7ffef40dd0a8,
>> main_closure=0x736ef8, rts_config=...) t rts/RtsMain.c:72
>>     #7  0x00000000004f738f in main ()
>>
>> This is based on an old tree so source locations may not be correct, it's this
>> code in threadStackOverflow():
>>
>>     // Charge the current thread for allocating stack.  Stack usage is
>>     // non-deterministic, because the chunk boundaries might vary from
>>     // run to run, but accounting for this is better than not
>>     // accounting for it, since a deep recursion will otherwise not be
>>     // subject to allocation limits.
>>     cap->r.rCurrentTSO = tso;
>>     new_stack = (StgStack*) allocate(cap, chunk_size);
>>     cap->r.rCurrentTSO = NULL;
>>
>>     SET_HDR(new_stack, &stg_STACK_info, old_stack->header.prof.ccs);
>>     TICK_ALLOC_STACK(chunk_size);
>>
>> Ömer
>> Ömer Sinan Ağacan <[hidden email]>, 21 Haz 2018 Per, 13:42
>> tarihinde şunu yazdı:
>> >
>> > > Large objects can only be primitive objects, like MUT_ARR_PTRS, allocated by
>> > > the RTS, and none of these have SRTs.
>> >
>> > Is is not possible to allocate a large STACK? I'm currently observing this in
>> > gdb:
>> >
>> >     >>> call *Bdescr(0x4200ec9000)
>> >     $2 = {
>> >       start = 0x4200ec9000,
>> >       free = 0x4200ed1000,
>> >       link = 0x4200100e80,
>> >       u = {
>> >         back = 0x4200103980,
>> >         bitmap = 0x4200103980,
>> >         scan = 0x4200103980
>> >       },
>> >       gen = 0x77b4b8,
>> >       gen_no = 1,
>> >       dest_no = 1,
>> >       node = 0,
>> >       flags = 1027, <-- BF_LARGE | BF_EVACUTED | ...
>> >       blocks = 8,
>> >       _padding = {[0] = 0, [1] = 0, [2] = 0}
>> >     }
>> >
>> >     >>> call printClosure(0x4200ec9000)
>> >     0x4200ec9000: STACK
>> >
>> >     >>> call checkClosure(0x4200ec9000)
>> >     $3 = 4096 -- makes sense, larger than 3277 bytes
>> >
>> > So I have a large STACK object, and STACKs can refer to static objects. But
>> > when we scavenge this object we don't scavenge its SRTs because we use
>> > scavenge_one(). This seems wrong to me.
>> >
>> > Ömer
>> >
>> > Simon Marlow <[hidden email]>, 20 Haz 2018 Çar, 14:32 tarihinde şunu yazdı:
>> > >
>> > > Interesting point. I don't think there are any large objects with SRTs, but we should document the invariant because we're relying on it.
>> > >
>> > > Large objects can only be primitive objects, like MUT_ARR_PTRS, allocated by the RTS, and none of these have SRTs.
>> > >
>> > > We did have plans to allocate memory for large dynamic objects using `allocate()` from compiled code, in which case we could have large objects that could be THUNK, FUN, etc. and could have an SRT, in which case we would need to revisit this.  You might want to take a look at Note [big objects] in GCUtils.c, which is relevant here.
>> > >
>> > > Cheers
>> > > Simon
>> > >
>> > >
>> > > On 20 June 2018 at 09:20, Ömer Sinan Ağacan <[hidden email]> wrote:
>> > >>
>> > >> Hi Simon,
>> > >>
>> > >> I'm confused about this code again. You said
>> > >>
>> > >> > scavenge_one() is only used for a non-major collection, where we aren't
>> > >> > traversing SRTs.
>> > >>
>> > >> But I think this is not true; scavenge_one() is also used to scavenge large
>> > >> objects (in scavenge_large()), which are scavenged even in major GCs. So it
>> > >> seems like we never really scavenge SRTs of large objects. This doesn't look
>> > >> right to me. Am I missing anything? Can large objects not refer to static
>> > >> objects?
>> > >>
>> > >> Thanks
>> > >>
>> > >> Ömer
>> > >>
>> > >> Ömer Sinan Ağacan <[hidden email]>, 2 May 2018 Çar, 09:03
>> > >> tarihinde şunu yazdı:
>> > >> >
>> > >> > Thanks Simon, this is really helpful.
>> > >> >
>> > >> > > If you look at scavenge_fun_srt() and co, you'll see that they return
>> > >> > > immediately if !major_gc.
>> > >> >
>> > >> > Thanks for pointing this out -- I didn't realize it's returning early when
>> > >> > !major_gc and this caused a lot of confusion. Now everything makes sense.
>> > >> >
>> > >> > I'll add a note for scavenging SRTs and refer to it in relevant code and submit
>> > >> > a diff.
>> > >> >
>> > >> > Ömer
>> > >> >
>> > >> > 2018-05-01 22:10 GMT+03:00 Simon Marlow <[hidden email]>:
>> > >> > > Your explanation is basically right. scavenge_one() is only used for a
>> > >> > > non-major collection, where we aren't traversing SRTs. Admittedly this is a
>> > >> > > subtle point that could almost certainly be documented better, I probably
>> > >> > > just overlooked it.
>> > >> > >
>> > >> > > More inline:
>> > >> > >
>> > >> > > On 1 May 2018 at 10:26, Ömer Sinan Ağacan <[hidden email]> wrote:
>> > >> > >>
>> > >> > >> I have an idea but it doesn't explain everything;
>> > >> > >>
>> > >> > >> SRTs are used to collect CAFs, and CAFs are always added to the oldest
>> > >> > >> generation's mut_list when allocated [1].
>> > >> > >>
>> > >> > >> When we're scavenging a mut_list we know we're not doing a major GC, and
>> > >> > >> because mut_list of oldest generation has all the newly allocated CAFs,
>> > >> > >> which
>> > >> > >> will be scavenged anyway, no need to scavenge SRTs for those.
>> > >> > >>
>> > >> > >> Also, static objects are always evacuated to the oldest gen [2], so any
>> > >> > >> CAFs
>> > >> > >> that are alive but not in the mut_list of the oldest gen will stay alive
>> > >> > >> after
>> > >> > >> a non-major GC, again no need to scavenge SRTs to keep these alive.
>> > >> > >>
>> > >> > >> This also explains why it's OK to not collect static objects (and not
>> > >> > >> treat
>> > >> > >> them as roots) in non-major GCs.
>> > >> > >>
>> > >> > >> However this doesn't explain
>> > >> > >>
>> > >> > >> - Why it's OK to scavenge large objects with scavenge_one().
>> > >> > >
>> > >> > >
>> > >> > > I don't understand - perhaps you could elaborate on why you think it might
>> > >> > > not be OK? Large objects are treated exactly the same as small objects with
>> > >> > > respect to their lifetimes.
>> > >> > >
>> > >> > >>
>> > >> > >> - Why we scavenge SRTs in non-major collections in other places (e.g.
>> > >> > >>   scavenge_block()).
>> > >> > >
>> > >> > >
>> > >> > > If you look at scavenge_fun_srt() and co, you'll see that they return
>> > >> > > immediately if !major_gc.
>> > >> > >
>> > >> > >>
>> > >> > >> Simon, could you say a few words about this?
>> > >> > >
>> > >> > >
>> > >> > > Was that enough words? I have more if necessary :)
>> > >> > >
>> > >> > > Cheers
>> > >> > > Simon
>> > >> > >
>> > >> > >
>> > >> > >>
>> > >> > >>
>> > >> > >> [1]: https://github.com/ghc/ghc/blob/master/rts/sm/Storage.c#L445-L449
>> > >> > >> [2]: https://github.com/ghc/ghc/blob/master/rts/sm/Scav.c#L1761-L1763
>> > >> > >>
>> > >> > >> Ömer
>> > >> > >>
>> > >> > >> 2018-03-28 17:49 GMT+03:00 Ben Gamari <[hidden email]>:
>> > >> > >> > Hi Simon,
>> > >> > >> >
>> > >> > >> > I'm a bit confused by scavenge_one; namely it doesn't scavenge SRTs. It
>> > >> > >> > appears that it is primarily used for remembered set entries but it's
>> > >> > >> > not at all clear why this means that we can safely ignore SRTs (e.g. in
>> > >> > >> > the FUN and THUNK cases).
>> > >> > >> >
>> > >> > >> > Can you shed some light on this?
>> > >> > >> >
>> > >> > >> > Cheers,
>> > >> > >> >
>> > >> > >> > - Ben
>> > >> > >> >
>> > >> > >> > _______________________________________________
>> > >> > >> > ghc-devs mailing list
>> > >> > >> > [hidden email]
>> > >> > >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>> > >> > >> >
>> > >> > >> _______________________________________________
>> > >> > >> ghc-devs mailing list
>> > >> > >> [hidden email]
>> > >> > >> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>> > >> > >
>> > >> > >
>> > >
>> > >
>
>
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Scavenging SRTs in scavenge_one

Ömer Sinan Ağacan
Documented in https://phabricator.haskell.org/D4893

Ömer
Ömer Sinan Ağacan <[hidden email]>, 22 Haz 2018 Cum, 09:54
tarihinde şunu yazdı:

>
> OK, finally everything makes sense I think. I was very confused by the code and
> previous emails where you said:
>
> > Large objects can only be primitive objects, like MUT_ARR_PTRS, allocated by
> > the RTS, and none of these have SRTs.
>
> I was pointing out that this is not entirely correct; we allocate large stacks.
> But as you say scavenge_one() handles that case by scavenging stack SRTs.
>
> So in summary:
>
> - scavenge_one() is called to scavenge mut_lists and large objects.
> - When scavenging mut_lists no need to scaveng SRTs (see previous emails)
> - When scavenging large objects we know that certain objects can't be large
>   (i.e. FUN, THUNK), but some others can (i.e. STACK), so scavenge_one()
>   scavenges stack SRTs but does not scavenge FUN and THUNK SRTs.
>
> Ömer
>
> Simon Marlow <[hidden email]>, 21 Haz 2018 Per, 21:27 tarihinde şunu yazdı:
> >
> > When scavenge_one() sees a STACK, it calls scavenge_stack() which traverses the stack frames, including their SRTs.
> >
> > So I don't understand what's going wrong for you - how are the SRTs not being traversed?
> >
> > Cheers
> > Simon
> >
> > On 21 June 2018 at 11:58, Ömer Sinan Ağacan <[hidden email]> wrote:
> >>
> >> Here's an example where we allocate a large (4K) stack:
> >>
> >>     >>> bt
> >>     #0  allocateMightFail (cap=0x7f366808cfc0 <MainCapability>,
> >> n=4096) at rts/sm/Storage.c:876
> >>     #1  0x00007f3667e4a85d in allocate (cap=0x7f366808cfc0
> >> <MainCapability>, n=4096) at rts/sm/Storage.c:849
> >>     #2  0x00007f3667e16f46 in threadStackOverflow (cap=0x7f366808cfc0
> >> <MainCapability>, tso=0x4200152a68) at rts/Threads.c:600
> >>     #3  0x00007f3667e12a64 in schedule
> >> (initialCapability=0x7f366808cfc0 <MainCapability>, task=0x78c970) at
> >> rts/Schedule.c:520
> >>     #4  0x00007f3667e1215f in scheduleWaitThread (tso=0x4200105388,
> >> ret=0x0, pcap=0x7ffef40dce78) at rts/Schedule.c:2533
> >>     #5  0x00007f3667e25685 in rts_evalLazyIO (cap=0x7ffef40dce78,
> >> p=0x736ef8, ret=0x0) at rts/RtsAPI.c:530
> >>     #6  0x00007f3667e25f7a in hs_main (argc=16, argv=0x7ffef40dd0a8,
> >> main_closure=0x736ef8, rts_config=...) t rts/RtsMain.c:72
> >>     #7  0x00000000004f738f in main ()
> >>
> >> This is based on an old tree so source locations may not be correct, it's this
> >> code in threadStackOverflow():
> >>
> >>     // Charge the current thread for allocating stack.  Stack usage is
> >>     // non-deterministic, because the chunk boundaries might vary from
> >>     // run to run, but accounting for this is better than not
> >>     // accounting for it, since a deep recursion will otherwise not be
> >>     // subject to allocation limits.
> >>     cap->r.rCurrentTSO = tso;
> >>     new_stack = (StgStack*) allocate(cap, chunk_size);
> >>     cap->r.rCurrentTSO = NULL;
> >>
> >>     SET_HDR(new_stack, &stg_STACK_info, old_stack->header.prof.ccs);
> >>     TICK_ALLOC_STACK(chunk_size);
> >>
> >> Ömer
> >> Ömer Sinan Ağacan <[hidden email]>, 21 Haz 2018 Per, 13:42
> >> tarihinde şunu yazdı:
> >> >
> >> > > Large objects can only be primitive objects, like MUT_ARR_PTRS, allocated by
> >> > > the RTS, and none of these have SRTs.
> >> >
> >> > Is is not possible to allocate a large STACK? I'm currently observing this in
> >> > gdb:
> >> >
> >> >     >>> call *Bdescr(0x4200ec9000)
> >> >     $2 = {
> >> >       start = 0x4200ec9000,
> >> >       free = 0x4200ed1000,
> >> >       link = 0x4200100e80,
> >> >       u = {
> >> >         back = 0x4200103980,
> >> >         bitmap = 0x4200103980,
> >> >         scan = 0x4200103980
> >> >       },
> >> >       gen = 0x77b4b8,
> >> >       gen_no = 1,
> >> >       dest_no = 1,
> >> >       node = 0,
> >> >       flags = 1027, <-- BF_LARGE | BF_EVACUTED | ...
> >> >       blocks = 8,
> >> >       _padding = {[0] = 0, [1] = 0, [2] = 0}
> >> >     }
> >> >
> >> >     >>> call printClosure(0x4200ec9000)
> >> >     0x4200ec9000: STACK
> >> >
> >> >     >>> call checkClosure(0x4200ec9000)
> >> >     $3 = 4096 -- makes sense, larger than 3277 bytes
> >> >
> >> > So I have a large STACK object, and STACKs can refer to static objects. But
> >> > when we scavenge this object we don't scavenge its SRTs because we use
> >> > scavenge_one(). This seems wrong to me.
> >> >
> >> > Ömer
> >> >
> >> > Simon Marlow <[hidden email]>, 20 Haz 2018 Çar, 14:32 tarihinde şunu yazdı:
> >> > >
> >> > > Interesting point. I don't think there are any large objects with SRTs, but we should document the invariant because we're relying on it.
> >> > >
> >> > > Large objects can only be primitive objects, like MUT_ARR_PTRS, allocated by the RTS, and none of these have SRTs.
> >> > >
> >> > > We did have plans to allocate memory for large dynamic objects using `allocate()` from compiled code, in which case we could have large objects that could be THUNK, FUN, etc. and could have an SRT, in which case we would need to revisit this.  You might want to take a look at Note [big objects] in GCUtils.c, which is relevant here.
> >> > >
> >> > > Cheers
> >> > > Simon
> >> > >
> >> > >
> >> > > On 20 June 2018 at 09:20, Ömer Sinan Ağacan <[hidden email]> wrote:
> >> > >>
> >> > >> Hi Simon,
> >> > >>
> >> > >> I'm confused about this code again. You said
> >> > >>
> >> > >> > scavenge_one() is only used for a non-major collection, where we aren't
> >> > >> > traversing SRTs.
> >> > >>
> >> > >> But I think this is not true; scavenge_one() is also used to scavenge large
> >> > >> objects (in scavenge_large()), which are scavenged even in major GCs. So it
> >> > >> seems like we never really scavenge SRTs of large objects. This doesn't look
> >> > >> right to me. Am I missing anything? Can large objects not refer to static
> >> > >> objects?
> >> > >>
> >> > >> Thanks
> >> > >>
> >> > >> Ömer
> >> > >>
> >> > >> Ömer Sinan Ağacan <[hidden email]>, 2 May 2018 Çar, 09:03
> >> > >> tarihinde şunu yazdı:
> >> > >> >
> >> > >> > Thanks Simon, this is really helpful.
> >> > >> >
> >> > >> > > If you look at scavenge_fun_srt() and co, you'll see that they return
> >> > >> > > immediately if !major_gc.
> >> > >> >
> >> > >> > Thanks for pointing this out -- I didn't realize it's returning early when
> >> > >> > !major_gc and this caused a lot of confusion. Now everything makes sense.
> >> > >> >
> >> > >> > I'll add a note for scavenging SRTs and refer to it in relevant code and submit
> >> > >> > a diff.
> >> > >> >
> >> > >> > Ömer
> >> > >> >
> >> > >> > 2018-05-01 22:10 GMT+03:00 Simon Marlow <[hidden email]>:
> >> > >> > > Your explanation is basically right. scavenge_one() is only used for a
> >> > >> > > non-major collection, where we aren't traversing SRTs. Admittedly this is a
> >> > >> > > subtle point that could almost certainly be documented better, I probably
> >> > >> > > just overlooked it.
> >> > >> > >
> >> > >> > > More inline:
> >> > >> > >
> >> > >> > > On 1 May 2018 at 10:26, Ömer Sinan Ağacan <[hidden email]> wrote:
> >> > >> > >>
> >> > >> > >> I have an idea but it doesn't explain everything;
> >> > >> > >>
> >> > >> > >> SRTs are used to collect CAFs, and CAFs are always added to the oldest
> >> > >> > >> generation's mut_list when allocated [1].
> >> > >> > >>
> >> > >> > >> When we're scavenging a mut_list we know we're not doing a major GC, and
> >> > >> > >> because mut_list of oldest generation has all the newly allocated CAFs,
> >> > >> > >> which
> >> > >> > >> will be scavenged anyway, no need to scavenge SRTs for those.
> >> > >> > >>
> >> > >> > >> Also, static objects are always evacuated to the oldest gen [2], so any
> >> > >> > >> CAFs
> >> > >> > >> that are alive but not in the mut_list of the oldest gen will stay alive
> >> > >> > >> after
> >> > >> > >> a non-major GC, again no need to scavenge SRTs to keep these alive.
> >> > >> > >>
> >> > >> > >> This also explains why it's OK to not collect static objects (and not
> >> > >> > >> treat
> >> > >> > >> them as roots) in non-major GCs.
> >> > >> > >>
> >> > >> > >> However this doesn't explain
> >> > >> > >>
> >> > >> > >> - Why it's OK to scavenge large objects with scavenge_one().
> >> > >> > >
> >> > >> > >
> >> > >> > > I don't understand - perhaps you could elaborate on why you think it might
> >> > >> > > not be OK? Large objects are treated exactly the same as small objects with
> >> > >> > > respect to their lifetimes.
> >> > >> > >
> >> > >> > >>
> >> > >> > >> - Why we scavenge SRTs in non-major collections in other places (e.g.
> >> > >> > >>   scavenge_block()).
> >> > >> > >
> >> > >> > >
> >> > >> > > If you look at scavenge_fun_srt() and co, you'll see that they return
> >> > >> > > immediately if !major_gc.
> >> > >> > >
> >> > >> > >>
> >> > >> > >> Simon, could you say a few words about this?
> >> > >> > >
> >> > >> > >
> >> > >> > > Was that enough words? I have more if necessary :)
> >> > >> > >
> >> > >> > > Cheers
> >> > >> > > Simon
> >> > >> > >
> >> > >> > >
> >> > >> > >>
> >> > >> > >>
> >> > >> > >> [1]: https://github.com/ghc/ghc/blob/master/rts/sm/Storage.c#L445-L449
> >> > >> > >> [2]: https://github.com/ghc/ghc/blob/master/rts/sm/Scav.c#L1761-L1763
> >> > >> > >>
> >> > >> > >> Ömer
> >> > >> > >>
> >> > >> > >> 2018-03-28 17:49 GMT+03:00 Ben Gamari <[hidden email]>:
> >> > >> > >> > Hi Simon,
> >> > >> > >> >
> >> > >> > >> > I'm a bit confused by scavenge_one; namely it doesn't scavenge SRTs. It
> >> > >> > >> > appears that it is primarily used for remembered set entries but it's
> >> > >> > >> > not at all clear why this means that we can safely ignore SRTs (e.g. in
> >> > >> > >> > the FUN and THUNK cases).
> >> > >> > >> >
> >> > >> > >> > Can you shed some light on this?
> >> > >> > >> >
> >> > >> > >> > Cheers,
> >> > >> > >> >
> >> > >> > >> > - Ben
> >> > >> > >> >
> >> > >> > >> > _______________________________________________
> >> > >> > >> > ghc-devs mailing list
> >> > >> > >> > [hidden email]
> >> > >> > >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
> >> > >> > >> >
> >> > >> > >> _______________________________________________
> >> > >> > >> ghc-devs mailing list
> >> > >> > >> [hidden email]
> >> > >> > >> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
> >> > >> > >
> >> > >> > >
> >> > >
> >> > >
> >
> >
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs