-
Notifications
You must be signed in to change notification settings - Fork 20
/
FlamegraphGenerator.swift
52 lines (49 loc) · 1.81 KB
/
FlamegraphGenerator.swift
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
//
// FlamegraphGenerator.swift
// PerfAnalysisRunner
//
// Created by Itay Brenner on 7/3/23.
//
import Foundation
import ETModels
class FlamegraphGenerator {
static func generateFlamegraphs(stacks: [Stack], syms: [[Any]], writeFolded: Bool) -> FlameNode {
let times = stacks.map { $0.time }
var timeDiffs: [Double] = []
let sampleInterval = 0.005
var unattributedTime = 0.0
let partitions = partitions(times, size: 2, step: 1)
for (t1, t2) in partitions {
if t2 - t1 > sampleInterval * 2 {
unattributedTime += t2 - t1 - sampleInterval * 2
timeDiffs.append(sampleInterval * 2)
} else {
timeDiffs.append(t2 - t1)
}
}
timeDiffs.append(sampleInterval) // Assume last stack was the usual amount of time
var samples = zip(syms, timeDiffs).map { (stackSyms, timeDiff) -> Sample in
return Sample(time: timeDiff, stack: stackSyms)
}
if unattributedTime > 0 {
samples.append(Sample(time: unattributedTime, stack: [[nil, "<unattributed>"]]))
}
if writeFolded {
try! samples.map { $0.description }.joined(separator: "\n").write(toFile: "output.folded", atomically: true, encoding: .utf8)
}
let node = FlameNode.fromSamples(samples)
return node
}
private static func partitions(_ array: [Double], size: Int, step: Int? = nil) -> [(Double, Double)] {
let step = step ?? size
var startIdx = 0
var endIdx = size - 1
var partitions: [(Double, Double)] = []
while Int(endIdx) < array.count {
partitions.append( (array[startIdx], array[endIdx]) )
startIdx += step
endIdx += step
}
return partitions
}
}