Skip to content

[swift-inspect] Add json and summary options to DumpRawMetadata #81186

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

Conversation

jabrylg
Copy link
Contributor

@jabrylg jabrylg commented Apr 29, 2025

Add json and summary options to swift-inspect --dump-raw-metadata. These options already exist for --dump-generic-metadata albeit with slightly different functionality.

  • --json: This will output the list of allocations as a json list. If --summary is specified the summary will be included in this json. If --output-file is specified then this output will save to a file otherwise it is printed without formatting.
  • --summary: This will output the amount of bytes allocated per tag type and the total amount of bytes allocated. If --json is specified this will be displayed as part of the larger json otherwise it is printed without formatting.
  • output-file: As mentioned above this will save the json to the specified parameter file.

Example invocation: swift-inspect dump-raw-metadata Finder --summary --json --output-file=example.json
example.json

rdar://148131548

var metadataOptions: MetadataOptions

@Flag(help: "Show allocations in mangled form")
var mangled: Bool = false
Copy link
Contributor

Choose a reason for hiding this comment

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

Why has this moved from the metadataOptions group?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

MetadataOptions was previously GenericMetadataOptions and only provided options for swift-inspect --dump-generic-metadata. This PR is proposing that three of the four options from GenericMetadataOptions (json, summary', and outputFile) be added to swift-inspect --dump-raw-metadata. Rather than manually type these options out in [DumpRawMetadata.swift](https://github.com/swiftlang/swift/pull/81186/files#diff-bbb7ba64f4c92e0e341aa925f49f73da14ed9d4aeb92ea4f2e8c50f7c10cc129), I opted to share this set of ParsableArguments`, hence the name change.

However, this PR does not implement the pre-existing mangled option in --dump-raw-metadata. Which is why I chose to remove it from this now more generally used GenericMetadataOptions.


func run() throws {
var allocatorTagTotals = [Int: AllocatorTagTotal]()
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's drop AllocatorTagTotal, as we really only need the number of bytes allocated. We can get the name later by calling name(allocation:) in the summary output loop (it's cheap) and the the tag is already in the dictionary key. And a minor style thing, it's a bit nicer to initialize this with the empty dictionary literal like var allocatorTagTotals: [Int: Int] = [:], like allocationList's declaration just below.

Copy link
Contributor Author

@jabrylg jabrylg May 1, 2025

Choose a reason for hiding this comment

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

Ah realized we can't easily get name(allocation:) outside of the closure because we need process.context to call it. Also can't throw the summary into the closure because it would break --all.

@@ -33,6 +57,18 @@ internal struct DumpRawMetadata: ParsableCommand {
try process.context.allocations.forEach { allocation in
let name: String = process.context.name(allocation: allocation.tag) ?? "<unknown>"
print("Metadata allocation at: \(hex: allocation.ptr) size: \(allocation.size) tag: \(allocation.tag) (\(name))")

if metadataOptions.summary {
if var allocatorTagTotal = allocatorTagTotals[Int(allocation.tag)] {
Copy link
Contributor

Choose a reason for hiding this comment

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

There's a fun shorthand way to write this. Assuming this dictionary is now typed [swift_metadata_allocation_tag_t: Int] like I mentioned above, you can do this add-or-insert thing in a single line:

allocatorTagTotals[allocation.tag, default: 0] += allocation.size


if metadataOptions.json {
let jsonStruct: RawMetadataOutput
let allocatorTagArray = Array(allocatorTagTotals.values).sorted(by: {$0.totalBytes > $1.totalBytes})
Copy link
Contributor

Choose a reason for hiding this comment

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

If you change the dictionary as suggested above, then you can grab the keys and values together and sort them like:

let tagSizes = allocatorTagTotals.sorted(by: { $0.1 > $1.1 })

Then you can iterate like:

for (tag, size) in tagSizes {

@jabrylg
Copy link
Contributor Author

jabrylg commented May 8, 2025

@swift-ci please test

@mikeash mikeash merged commit cf48deb into swiftlang:main May 9, 2025
5 checks passed
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.

3 participants