Skip to content
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

[profiler] Rework GC roots reporting. #5710

Closed
wants to merge 13 commits into from

Conversation

luhenry
Copy link
Contributor

@luhenry luhenry commented Oct 5, 2017

This change re-implement GC roots reporting in a way that allows users to correctly track the source of a GC root.

The new design is based on emitting GC root information upfront and only report addresses during heap dumps.

When a GC root is registered we emit an event that is an address range, the root kind, a key and a text description.

A decoder can use this information to match a reported root address with all registration addresses to figure out what they mean.

A GC Root key is used to further its meaning. For example, if kind is thread, key is a tid, if kind is static variables, key is the class pointer and so on.

The build of the change is introducing this key argument across all root registration code and rework our root reporting code to encode their addresses.

Some roots use pseudo-addresses when they are not registrable. This is the case of thread stacks/registers and the finalizer queue.

Finally, root reporting was changed to happen only once per collection and at the end, leading to correct and useful data being produced.

kumpera and others added 2 commits July 17, 2017 16:22
This change re-implement GC roots reporting in a way that allows users to correctly track the source of a GC root.

The new design is based on emitting GC root information upfront and only report addresses during heap dumps.

When a GC root is registered we emit an event that is an address range, the root kind, a key and a text description.

A decoder can use this information to match a reported root address with all registration addresses to figure out what they mean.

A GC Root key is used to further its meaning. For example, if kind is thread, key is a tid, if kind is static variables, key is the class pointer and so on.

The build of the change is introducing this key argument across all root registration code and rework our root reporting code to encode their addresses.

Some roots use pseudo-addresses when they are not registrable. This is the case of thread stacks/registers and the finalizer queue.

Finally, root reporting was changed to happen only once per collection and at the end, leading to correct and useful data being produced.
@luhenry
Copy link
Contributor Author

luhenry commented Oct 5, 2017

This is #5126 with master merged in to resolve conflicts.

@alexrp
Copy link
Contributor

alexrp commented Oct 7, 2017

build profiler stress

1 similar comment
@luhenry
Copy link
Contributor Author

luhenry commented Oct 9, 2017

build profiler stress

Attributes = StreamHeader.FormatVersion == 13 ? (LogHeapRootAttributes) _reader.ReadByte () : (LogHeapRootAttributes) _reader.ReadULeb128 (),
ExtraInfo = (long) _reader.ReadULeb128 (),
AddressPointer = ReadPointer (),
ObjectPointer = ReadObject ()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is breaking support for v13, isn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something I missed from merging master, I will fix that.

@DavidKarlas
Copy link
Member

@monojenkins build pkg
I want to do some testing locally profiling VSfM, local build of mono doesn't have GTK and MSBuild assemblies... hence I need .pkg

@DavidKarlas
Copy link
Member

@monojenkins build pkg

@luhenry
Copy link
Contributor Author

luhenry commented Oct 12, 2017

build

@luhenry
Copy link
Contributor Author

luhenry commented Oct 16, 2017

build profiler stress

@luhenry
Copy link
Contributor Author

luhenry commented Oct 16, 2017

build pkg

@DavidKarlas
Copy link
Member

Jetlag doesn't let me sleep...
So with help from @alexrp I finally got my custom profiler working to be loaded at startup...
I will explain how my profiler work:

Issue that I have...
Via mono_profiler_set_gc_roots_callback I receive 224,902 unique roots
Via new(from this PR) mono_profiler_set_gc_root_register_callback I get 1886 roots registrations
Via new(from this PR) mono_profiler_set_gc_root_unregister_callback I get 257 root unregistrations
And I also get 788,591 objects via heap_walk.

So my issue is... Which number is off here? New API registering too little stuff or mono_profiler_set_gc_roots_callback too much? Or am I just using it wrong?

@DavidKarlas
Copy link
Member

I'm trying to make sense of all this data without much success...

Would be nice if some unit tests could be added for example... profile app which creates object and assign it to static variable... In unit test verify that root is reported...

Copy link
Contributor

@kumpera kumpera left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR looks good, it might be missing some gc roots from things like local handles. But it's a good starting point.

I pushed a fix for the compilation issue.

@luhenry
Copy link
Contributor Author

luhenry commented Oct 26, 2017

build profiler stress

@luhenry
Copy link
Contributor Author

luhenry commented Oct 30, 2017

@kumpera
Copy link
Contributor

kumpera commented Oct 30, 2017

Ugg, the stress test actually caught a bug in thread registration.

@luhenry
Copy link
Contributor Author

luhenry commented Nov 22, 2017

@kumpera could you please work on getting the profiler stress test fixed? I will rebase on master, fix the conflicts and push back here. Feel free to push anything you want to luhenry/mono:gc_roots_experiments

@luhenry
Copy link
Contributor Author

luhenry commented Nov 22, 2017

build profiler stress

@DavidKarlas
Copy link
Member

@monojenkins build pkg

@DavidKarlas
Copy link
Member

@monojenkins build pkg

Alex Rønne Petersen added 4 commits November 28, 2017 10:37
thread_stopping occurs earlier than thread_stopped, before any of the detach
code has run. thread_exited occurs after thread_stopped, once all detach logic
has finished.
…events.

With the revamped GC root reporting work, some GC root unregister events will
arrive after the thread_stopped event. This will cause the thread to be
re-added to the thread list in the profiler, and never be removed until program
exit. This meant that if such a thread had actually exited and a new thread
would reuse its thread ID, that new thread would fail to add itself to the
thread list, leading to failures like this one:

    init_thread: failed to insert thread 0x70000b761000 in log_profiler.profiler_thread_list, found = true

By using the new thread_exited event, we remove the thread from the thread list
after these GC root unregister events have arrived, thereby ensuring that the
thread won't be incorrectly 'resurrected'.
…ents.

These checks are no longer necessary as these thread callbacks are not invoked
for tools threads in the first place.
@luhenry
Copy link
Contributor Author

luhenry commented Nov 28, 2017

@monojenkins build profiler stress

@DavidKarlas
Copy link
Member

@monojenkins build pkg

@DavidKarlas
Copy link
Member

@DavidKarlas
Copy link
Member

This can be closed since it was reopened and merged as another PR.

@alexrp alexrp closed this Dec 12, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants