-
Notifications
You must be signed in to change notification settings - Fork 0
/
page-profile-parser.jl
158 lines (145 loc) · 4.09 KB
/
page-profile-parser.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
const doc = """page-profile-parser.jl -- Parses a page profile JSON file
Usage:
page-profile-parser.jl [<name>] [--page-size=<size>]
page-profile-parser.jl -h | --help
page-profile-parser.jl --version
"""
using DocOpt
using JSON3
using Printf
const args = docopt(doc, version = v"0.1.1")
PAGE_SIZE = 4096
function main()
global PAGE_SIZE
name = args["<name>"]
if name === nothing
error("Missing argument <name>")
end
if args["--page-size"] !== nothing
PAGE_SIZE *= parse(UInt64, args["--page-size"])
else
error("Missing argument --page-size")
end
parse_page_profile(name)
end
mutable struct HeapPage
address::String
object_size::Int64
type_count::Dict{String,UInt64}
function HeapPage(address::String, object_size::Int64)
new(address, object_size, Dict{String,UInt64}())
end
end
function insert_object!(page::HeapPage, object_type::String)
if haskey(page.type_count, object_type)
page.type_count[object_type] += 1
else
page.type_count[object_type] = 1
end
end
mutable struct PageProfile
types::Set{String}
pages::Vector{HeapPage}
function PageProfile()
new(Set{String}(), Vector{HeapPage}())
end
end
function insert_type!(profile::PageProfile, type::String)
push!(profile.types, type)
end
function insert_page!(profile::PageProfile, page::HeapPage)
push!(profile.pages, page)
end
function compute_average_utilization(profile::PageProfile, type::String)
object_bytes = 0
page_bytes = 0
for page in profile.pages
if haskey(page.type_count, type)
for (t, count) in page.type_count
object_bytes += count * page.object_size
end
page_bytes += PAGE_SIZE
end
end
return object_bytes / page_bytes
end
function compute_object_bytes(profile::PageProfile)
object_bytes = 0
for page in profile.pages
for (type, count) in page.type_count
object_bytes += count * page.object_size
end
end
return object_bytes
end
function Base.show(io::IO, profile::PageProfile)
@printf(
io,
"PageProfile(%d pages, %.2f MiB)",
length(profile.pages),
length(profile.pages) * PAGE_SIZE / 1024 / 1024,
)
@printf(
io,
"Wasted bytes due to fragmentation: %.2f MiB",
length(profile.pages) * PAGE_SIZE / 1024 / 1024 -
compute_object_bytes(profile) / 1024 / 1024,
)
d = Dict{String,UInt64}()
for page in profile.pages
for (type, count) in page.type_count
if haskey(d, type)
d[type] += 1
else
d[type] = 1
end
end
end
types = sort(collect(profile.types), by = ty -> d[ty])
reverse!(types)
for type in types
npages = d[type]
@printf(
io,
"\n %s: %.2f%% utilization %d pages (%.2f MiB)",
type,
compute_average_utilization(profile, type) * 100,
npages,
npages * PAGE_SIZE / 1024 / 1024
)
end
for page in profile.pages
if isempty(page.type_count)
continue
end
@printf(io, "\n Page(%s, %d bytes)", page.address, page.object_size)
if isempty(page.type_count)
@printf(io, "\n empty")
else
for (type, count) in page.type_count
@printf(io, "\n %s: %d", type, count)
end
end
end
end
function parse_page_profile(filename::String)
profile = PageProfile()
dict = JSON3.read(filename)
for page in dict["pages"]
address = page["address"]
object_size = page["object_size"]
heap_page = HeapPage(address, object_size)
for object in page["objects"]
if object == "empty" || object == "garbage"
continue
end
insert_object!(heap_page, object)
insert_type!(profile, object)
end
if !isempty(heap_page.type_count)
insert_page!(profile, heap_page)
end
end
@show profile
end
main()