Skip to content

Commit c5dffe8

Browse files
committed
feat: update SKBackTrace.backTraceInfoEntity return value.
1 parent 115b794 commit c5dffe8

File tree

3 files changed

+65
-21
lines changed

3 files changed

+65
-21
lines changed

SKApmTools/Classes/ANR/SKANRMonitor.swift

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,13 @@ open class SKANRMonitor: NSObject{
2020
fileprivate var semaphore: DispatchSemaphore?
2121

2222
fileprivate var underObserving: Bool = false
23-
// 卡顿次数记录
23+
/// 卡顿次数记录
2424
fileprivate var count: Int = 0
2525

26+
fileprivate var pendingEntitys: [SKBacktraceEntity] = []
27+
28+
fileprivate var pendingEntityDict: [String: SKBacktraceEntity] = [:]
29+
2630
@objc public func start() {
2731
if nil == self.observer {
2832
underObserving = true
@@ -37,16 +41,22 @@ open class SKANRMonitor: NSObject{
3741
SKANRMonitor.sharedInstance.logActivity(activity)
3842
let result = semaphore.wait(timeout: DispatchTime.now() + .milliseconds(self.singleTime))
3943
if result == .timedOut {
44+
if self.observer == nil {
45+
return
46+
}
4047
if activity == .beforeSources || activity == .afterWaiting {
41-
let stackSize = Thread.main.stackSize
4248
print("监测到卡顿")
43-
// let callStackSymbols = Thread.callStackSymbols
44-
// for (index, symbol) in callStackSymbols.enumerated() {
45-
// print("symbol【\(index)】: \(symbol)")
46-
// }
47-
let traces = SKBackTrace.backTrace(of: Thread.main)
48-
for (index, symbol) in traces.enumerated() {
49-
print("symbol【\(index)】: \(symbol.info)")
49+
let entity = SKBackTrace.backTraceInfoEntity(of: Thread.main)
50+
let key = "\(entity.validAddress)_\(entity.validFunction)"
51+
if !self.pendingEntityDict.keys.contains(key) {
52+
self.pendingEntityDict.updateValue(entity, forKey: key)
53+
self.pendingEntitys.append(entity)
54+
print(entity.threadId)
55+
print(entity.validAddress)
56+
print(entity.validFunction)
57+
print(entity.traceContent)
58+
} else {
59+
print("相同的卡顿只记录一次")
5060
}
5161
}
5262
} else {

SKApmTools/Classes/BackTrace/SKBackTrace.swift

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,43 @@ import MachO
1111
public class SKBackTrace {
1212

1313
/// 获取指定线程的堆栈信息
14-
public static func backTrace(of thread: Thread) -> [SKStackSymbol] {
14+
public static func backTraceInfoEntity(of thread: Thread) -> SKBacktraceEntity {
1515
let mach_thread = _machThread(from: thread)
16-
var symbols : [SKStackSymbol] = []
1716
let stackSize : UInt32 = 128
1817
let addrs = UnsafeMutablePointer<UnsafeMutableRawPointer?>.allocate(capacity: Int(stackSize))
1918
defer { addrs.deallocate() }
2019
let frameCount = mach_back_trace(mach_thread, stack: addrs, maxSymbols: Int32(stackSize))
2120
let buf = UnsafeBufferPointer(start: addrs, count: Int(frameCount))
21+
var validAddress = "", validFunction = "", traceContent = ""
22+
var symbols : [SKStackSymbol] = []
23+
let bundleName = Bundle.main.infoDictionary?["CFBundleName"] // like SKApmTools_Example
2224
/// 解析堆栈地址
2325
for (index, addr) in buf.enumerated() {
2426
guard let addr = addr else { continue }
2527
let address = UInt(bitPattern: addr)
26-
let symbol: SKStackSymbol
27-
symbol = mach_O_parseSymbol(with: address, index: index)
28+
let symbol = mach_O_parseSymbol(with: address, index: index)
29+
traceContent.append("\(symbol.info)")
2830
symbols.append(symbol)
31+
if let bundleName = bundleName, validAddress.count == 0, bundleName as! String == symbol.baseAddress {
32+
validAddress = symbol.formatAddress
33+
validFunction = symbol.demangledSymbol
34+
}
35+
}
36+
if validAddress.count == 0 {
37+
validAddress = symbols.first?.formatAddress ?? ""
38+
validFunction = symbols.first?.demangledSymbol ?? ""
2939
}
30-
return symbols
40+
let entity = SKBacktraceEntity(threadId: UInt(mach_thread), validAddress: validAddress, validFunction: validFunction, traceContent: traceContent, traceSymbols: symbols)
41+
return entity
3142
}
3243

33-
/// Thread to mach thread
3444
/// 获取线程对应的线程标识
3545
private static func _machThread(from thread: Thread) -> thread_t {
3646
guard let (threads, count) = _machAllThread() else {
3747
return mach_thread_self()
3848
}
3949

40-
// 判断目标 thread, 如果是主线程,直接返回对应标识
50+
/// 判断目标 thread, 如果是主线程,直接返回对应标识
4151
if thread.isMainThread {
4252
return get_main_thread_id()
4353
}
@@ -83,8 +93,8 @@ public class SKBackTrace {
8393

8494
@_silgen_name("mach_backtrace")
8595
public func mach_back_trace(_ thread: thread_t,
86-
stack: UnsafeMutablePointer<UnsafeMutableRawPointer?>,
87-
maxSymbols: Int32) -> Int32
96+
stack: UnsafeMutablePointer<UnsafeMutableRawPointer?>,
97+
maxSymbols: Int32) -> Int32
8898

8999
extension Character {
90100
var isAscii: Bool {

SKApmTools/Classes/BackTrace/SKStackSymbol.swift

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,41 @@ public struct SKStackSymbol {
2020
return _stdlib_demangleName(symbol)
2121
}
2222

23+
public var baseAddress: String {
24+
return image.utf8CString.withUnsafeBufferPointer { (imageBuffer: UnsafeBufferPointer<CChar>) -> String in
25+
return String(format: "%s", UInt(bitPattern: imageBuffer.baseAddress))
26+
}
27+
}
28+
29+
public var formatAddress: String {
30+
#if arch(x86_64) || arch(arm64)
31+
return String(format: "0x%016llx", address)
32+
#else
33+
return String(format: "0x%08lx", address)
34+
#endif
35+
}
36+
2337
public var info: String {
2438
return image.utf8CString.withUnsafeBufferPointer { (imageBuffer: UnsafeBufferPointer<CChar>) -> String in
39+
let add = UInt(bitPattern: imageBuffer.baseAddress)
2540
#if arch(x86_64) || arch(arm64)
26-
return String(format: "%-4ld%-35s 0x%016llx %@ + %ld \n", index, UInt(bitPattern: imageBuffer.baseAddress), address, demangledSymbol, offset)
41+
return String(format: "%-4ld%-35s 0x%016llx %@ + %ld \n", index, add, address, demangledSymbol, offset)
2742
#else
28-
return String(format: "%-4d%-35s 0x%08lx %@ + %d \n", index, UInt(bitPattern: imageBuffer.baseAddress), address, demangledSymbol, offset)
43+
return String(format: "%-4d%-35s 0x%08lx %@ + %d \n", index, add, address, demangledSymbol, offset)
2944
#endif
3045
}
3146
}
3247
}
3348

49+
50+
public struct SKBacktraceEntity {
51+
public let threadId: UInt // 259
52+
public let validAddress: String // address
53+
public let validFunction: String // function
54+
public let traceContent: String
55+
public let traceSymbols: [SKStackSymbol]
56+
}
57+
3458
public struct SKBacktraceEntry: Codable {
3559
public let `class`: String
3660
public let name: String
@@ -50,7 +74,7 @@ func _stdlib_demangleImpl(
5074
flags: UInt32
5175
) -> UnsafeMutablePointer<CChar>?
5276

53-
// Swift方法名还原
77+
/// Swift方法名还原
5478
private func _stdlib_demangleName(_ mangledName: String) -> String {
5579
return mangledName.utf8CString.withUnsafeBufferPointer {
5680
(mangledNameUTF8CStr) in

0 commit comments

Comments
 (0)