Skip to content

Commit 57bbff6

Browse files
Profile: make heap snapshots viewable in vscode viewer (#53833)
1 parent e64fa86 commit 57bbff6

File tree

5 files changed

+57
-13
lines changed

5 files changed

+57
-13
lines changed

src/gc-heap-snapshot.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,9 @@ void _record_gc_just_edge(const char *edge_type, size_t from_idx, size_t to_idx,
606606
void final_serialize_heap_snapshot(ios_t *json, ios_t *strings, HeapSnapshot &snapshot, char all_one)
607607
{
608608
// mimicking https://github.com/nodejs/node/blob/5fd7a72e1c4fbaf37d3723c4c81dce35c149dc84/deps/v8/src/profiler/heap-snapshot-generator.cc#L2567-L2567
609+
// also https://github.com/microsoft/vscode-v8-heap-tools/blob/c5b34396392397925ecbb4ecb904a27a2754f2c1/v8-heap-parser/src/decoder.rs#L43-L51
609610
ios_printf(json, "{\"snapshot\":{");
611+
610612
ios_printf(json, "\"meta\":{");
611613
ios_printf(json, "\"node_fields\":[\"type\",\"name\",\"id\",\"self_size\",\"edge_count\",\"trace_node_id\",\"detachedness\"],");
612614
ios_printf(json, "\"node_types\":[");
@@ -617,10 +619,26 @@ void final_serialize_heap_snapshot(ios_t *json, ios_t *strings, HeapSnapshot &sn
617619
ios_printf(json, "\"edge_types\":[");
618620
snapshot.edge_types.print_json_array(json, false);
619621
ios_printf(json, ",");
620-
ios_printf(json, "\"string_or_number\",\"from_node\"]");
622+
ios_printf(json, "\"string_or_number\",\"from_node\"],");
623+
// not used. Required by microsoft/vscode-v8-heap-tools
624+
ios_printf(json, "\"trace_function_info_fields\":[\"function_id\",\"name\",\"script_name\",\"script_id\",\"line\",\"column\"],");
625+
ios_printf(json, "\"trace_node_fields\":[\"id\",\"function_info_index\",\"count\",\"size\",\"children\"],");
626+
ios_printf(json, "\"sample_fields\":[\"timestamp_us\",\"last_assigned_id\"],");
627+
ios_printf(json, "\"location_fields\":[\"object_index\",\"script_id\",\"line\",\"column\"]");
628+
// end not used
621629
ios_printf(json, "},\n"); // end "meta"
630+
622631
ios_printf(json, "\"node_count\":%zu,", snapshot.num_nodes);
623-
ios_printf(json, "\"edge_count\":%zu", snapshot.num_edges);
624-
ios_printf(json, "}\n"); // end "snapshot"
632+
ios_printf(json, "\"edge_count\":%zu,", snapshot.num_edges);
633+
ios_printf(json, "\"trace_function_count\":0"); // not used. Required by microsoft/vscode-v8-heap-tools
634+
ios_printf(json, "},\n"); // end "snapshot"
635+
636+
// not used. Required by microsoft/vscode-v8-heap-tools
637+
ios_printf(json, "\"trace_function_infos\":[],");
638+
ios_printf(json, "\"trace_tree\":[],");
639+
ios_printf(json, "\"samples\":[],");
640+
ios_printf(json, "\"locations\":[]");
641+
// end not used
642+
625643
ios_printf(json, "}");
626644
}

stdlib/Manifest.toml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
julia_version = "1.12.0-DEV"
44
manifest_format = "2.0"
5-
project_hash = "13f2dd600364a1e8b659dc5796bf185b37d1c95d"
5+
project_hash = "d3a1f6b706609fe0c59521e1d770be6e2b8c489d"
66

77
[[deps.ArgTools]]
88
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
@@ -23,7 +23,7 @@ version = "1.11.0"
2323
[[deps.CompilerSupportLibraries_jll]]
2424
deps = ["Artifacts", "Libdl"]
2525
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"
26-
version = "1.1.0+0"
26+
version = "1.1.1+0"
2727

2828
[[deps.Dates]]
2929
deps = ["Printf"]
@@ -113,7 +113,7 @@ version = "1.11.0+1"
113113
[[deps.LibUV_jll]]
114114
deps = ["Artifacts", "Libdl"]
115115
uuid = "183b4373-6708-53ba-ad28-60e28bb38547"
116-
version = "2.0.1+15"
116+
version = "2.0.1+16"
117117

118118
[[deps.LibUnwind_jll]]
119119
deps = ["Artifacts", "Libdl"]
@@ -155,7 +155,7 @@ version = "1.11.0"
155155

156156
[[deps.MozillaCACerts_jll]]
157157
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
158-
version = "2023.12.12"
158+
version = "2024.3.11"
159159

160160
[[deps.NetworkOptions]]
161161
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
@@ -177,9 +177,9 @@ uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15"
177177
version = "10.43.0+0"
178178

179179
[[deps.Pkg]]
180-
deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
180+
deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "Random", "SHA", "TOML", "Tar", "UUIDs", "p7zip_jll"]
181181
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
182-
version = "1.11.0"
182+
version = "1.12.0"
183183
weakdeps = ["REPL"]
184184

185185
[deps.Pkg.extensions]
@@ -191,6 +191,7 @@ uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
191191
version = "1.11.0"
192192

193193
[[deps.Profile]]
194+
deps = ["Unicode"]
194195
uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79"
195196
version = "1.11.0"
196197

stdlib/Profile/Project.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ name = "Profile"
22
uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79"
33
version = "1.11.0"
44

5+
[deps]
6+
Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
7+
8+
[compat]
9+
Unicode = "1.11.0"
10+
511
[extras]
612
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
713
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"

stdlib/Profile/src/Profile.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,6 +1286,7 @@ function take_heap_snapshot(filepath::AbstractString, all_one::Bool=false; strea
12861286
prefix = filepath
12871287
_stream_heap_snapshot(prefix, all_one)
12881288
Profile.HeapSnapshot.assemble_snapshot(prefix, filepath)
1289+
Profile.HeapSnapshot.cleanup_streamed_files(prefix)
12891290
end
12901291
return filepath
12911292
end

stdlib/Profile/src/heapsnapshot_reassemble.jl

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
module HeapSnapshot
44

5+
using Unicode
6+
57
"""
68
assemble_snapshot(filepath::AbstractString, out_file::AbstractString)
79
@@ -92,7 +94,7 @@ function assemble_snapshot(in_prefix, io::IO)
9294
node_count = parse(Int, String(@view preamble[pos:endpos]))
9395

9496
pos = last(findnext("edge_count\":", preamble, endpos)) + 1
95-
endpos = findnext(==('}'), preamble, pos) - 1
97+
endpos = findnext(==(','), preamble, pos) - 1
9698
edge_count = parse(Int, String(@view preamble[pos:endpos]))
9799

98100
nodes = Nodes(node_count, edge_count)
@@ -137,7 +139,8 @@ function assemble_snapshot(in_prefix, io::IO)
137139
end
138140

139141
_digits_buf = zeros(UInt8, ndigits(typemax(UInt)))
140-
println(io, @view(preamble[1:end-2]), ",") # remove trailing "}\n", we don't end the snapshot here
142+
println(io, @view(preamble[1:end-1]), ",") # remove trailing "}" to reopen the object
143+
141144
println(io, "\"nodes\":[")
142145
for i in 1:length(nodes)
143146
i > 1 && println(io, ",")
@@ -182,12 +185,11 @@ function assemble_snapshot(in_prefix, io::IO)
182185
str_bytes = read(strings_io, str_size)
183186
str = String(str_bytes)
184187
if first
185-
print_str_escape_json(io, str)
186188
first = false
187189
else
188190
print(io, ",\n")
189-
print_str_escape_json(io, str)
190191
end
192+
print_str_escape_json(io, str)
191193
end
192194
end
193195
print(io, "]}")
@@ -202,6 +204,19 @@ function assemble_snapshot(in_prefix, io::IO)
202204
return nothing
203205
end
204206

207+
"""
208+
cleanup_streamed_files(prefix::AbstractString)
209+
210+
Remove files streamed during `take_heap_snapshot` in streaming mode.
211+
"""
212+
function cleanup_streamed_files(prefix::AbstractString)
213+
rm(string(prefix, ".metadata.json"))
214+
rm(string(prefix, ".nodes"))
215+
rm(string(prefix, ".edges"))
216+
rm(string(prefix, ".strings"))
217+
return nothing
218+
end
219+
205220
function print_str_escape_json(stream::IO, s::AbstractString)
206221
print(stream, '"')
207222
for c in s
@@ -221,6 +236,9 @@ function print_str_escape_json(stream::IO, s::AbstractString)
221236
print(stream, "\\t")
222237
elseif '\x00' <= c <= '\x1f'
223238
print(stream, "\\u", lpad(string(UInt16(c), base=16), 4, '0'))
239+
elseif !Unicode.isassigned(c)
240+
# we have to do this because vscode's viewer doesn't like the replace character
241+
print(stream, "[invalid unicode character]")
224242
else
225243
print(stream, c)
226244
end

0 commit comments

Comments
 (0)