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

Garbage profiler #42658

Closed
wants to merge 13 commits into from
Closed

Conversation

vilterp
Copy link
Contributor

@vilterp vilterp commented Oct 15, 2021

Ever seen a @time printout like this:

5091.986425 seconds (5.59 G allocations: 324.011 GiB, 57.83% gc time, 5.70% compilation time)

…and wondered what the types are of all those objects which are being allocated and collected? This PR is for you…

It generates a report of how many objects of each type are being freed during each garbage collection.

Usage

file = open("gc-profile.csv", "w")
GC.start_garbage_profile(file)

# ... the code you want to profile ...

GC.stop_garbage_profile()
flush(file) # TODO: figure out how to do this from C...

Output

A CSV file with these columns:

  • gc_epoch: an integer that starts at 0 and increases each time the garbage collector runs
  • type: type of julia object being freed
  • num_freed number of that type freed during that GC epoch

e.g.:

gc_epoch,type,num_freed
1,Foo,5
1,Bar,6
2,Foo,3
2,Bar,2

Output is streamed to this file as the program runs.

To aggregate this over all GC epochs, I've been using csvsql to run do a group by:

$ csvsql --query 'select type, sum(num_freed) from "gc-profile" group by type order by sum(num_freed) desc' gc-profile.csv > gc-profile-agg.csv

Notes

issues / improvements

  • is this threadsafe? i.e. can the allocator be called into from multiple threads, which might lead to mutating the hash map concurrently?
  • put a timestamp on each log line
  • put GC type (full vs. incremental) on each log line
  • enable logging & profiling with one function call? can be defined in Julia

Future work

@vilterp vilterp mentioned this pull request Oct 15, 2021
1 task
don't seem to really be doing much
@DilumAluthge
Copy link
Member

You have trailing whitespace on the following lines:

src/gc-garbage-profiler.cpp:90:}    
src/gc-garbage-profiler.cpp:146:    

@timholy
Copy link
Sponsor Member

timholy commented Oct 15, 2021

Some kind of memory profiling would be awesome. I assume you've seen this alternative, but if not: #33467. If we had that, would you still want this?

@NHDaly
Copy link
Member

NHDaly commented Oct 15, 2021

(I think this is still in Draft, so i've removed me and Jameson as reviewers. Let me know when you're ready for review Pete, and i'll add us back)

@DilumAluthge
Copy link
Member

DilumAluthge commented Oct 15, 2021

FYI, you will need to fix the analyzegc failures.

@vilterp
Copy link
Contributor Author

vilterp commented Oct 22, 2021

@timholy good question. This seemed like the fastest way to get a basic handle on our garbage problem, but it does immediately beg the question of where the allocations come from. So, I would still love to get a memory profiler with stacks!

@vilterp vilterp mentioned this pull request Oct 22, 2021
7 tasks
@vilterp
Copy link
Contributor Author

vilterp commented Oct 23, 2021

Folded into #42768

@vilterp vilterp closed this Oct 23, 2021
NHDaly added a commit that referenced this pull request Jan 19, 2022
## Overview

Record the type and stack of every allocation (or only at a given sample interval), and return as Julia objects.

Alternate approach to existing alloc profiler PR: #33467
Complementary to garbage profiler PR: #42658 (maybe there's some nice way to meld them)

This may be reinventing the wheel from #33467, but I'm not sure why that one needs stuff like LLVM passes. I mimicked some stuff from it, but this was my attempt to get something up and running. Could easily be missing stuff.

## Usage:

```julia
using Profile.Allocs
res = Allocs.@Profile sample_rate=0.001 my_func()
prof = Allocs.fetch()
# do something with `prof`
```

See also: JuliaPerf/PProf.jl#46 for support for visualizing these.

Co-authored-by: Nathan Daly <nhdaly@gmail.com>
LilithHafner pushed a commit to LilithHafner/julia that referenced this pull request Feb 22, 2022
## Overview

Record the type and stack of every allocation (or only at a given sample interval), and return as Julia objects.

Alternate approach to existing alloc profiler PR: JuliaLang#33467
Complementary to garbage profiler PR: JuliaLang#42658 (maybe there's some nice way to meld them)

This may be reinventing the wheel from JuliaLang#33467, but I'm not sure why that one needs stuff like LLVM passes. I mimicked some stuff from it, but this was my attempt to get something up and running. Could easily be missing stuff.

## Usage:

```julia
using Profile.Allocs
res = Allocs.@Profile sample_rate=0.001 my_func()
prof = Allocs.fetch()
# do something with `prof`
```

See also: JuliaPerf/PProf.jl#46 for support for visualizing these.

Co-authored-by: Nathan Daly <nhdaly@gmail.com>
LilithHafner pushed a commit to LilithHafner/julia that referenced this pull request Mar 8, 2022
## Overview

Record the type and stack of every allocation (or only at a given sample interval), and return as Julia objects.

Alternate approach to existing alloc profiler PR: JuliaLang#33467
Complementary to garbage profiler PR: JuliaLang#42658 (maybe there's some nice way to meld them)

This may be reinventing the wheel from JuliaLang#33467, but I'm not sure why that one needs stuff like LLVM passes. I mimicked some stuff from it, but this was my attempt to get something up and running. Could easily be missing stuff.

## Usage:

```julia
using Profile.Allocs
res = Allocs.@Profile sample_rate=0.001 my_func()
prof = Allocs.fetch()
# do something with `prof`
```

See also: JuliaPerf/PProf.jl#46 for support for visualizing these.

Co-authored-by: Nathan Daly <nhdaly@gmail.com>
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.

4 participants