Skip to content

Commit

Permalink
kram-profile - add info popup with thread info for mem traces, log im…
Browse files Browse the repository at this point in the history
…provements
  • Loading branch information
alecazam committed Mar 5, 2024
1 parent ed8fbcd commit 498b436
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 35 deletions.
59 changes: 39 additions & 20 deletions kram-profile/kram-profile/Log.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,75 +103,94 @@ class Log {
#endif
}

func error(_ message: String, _ function: String = #function, _ line: Int = #line) {
let text = formatMessage(message, .error, function, line)
private func logToOSLog(_ text: String, _ type: OSLogType) {
// TODO: this needs to split the string up, since os_log limits length to
// some paltry 1023 chars.
os_log("%s", log: log, type: type, text)
}

func error(_ message: @autoclosure () -> String, _ function: String = #function, _ line: Int = #line) {
let text = formatMessage(message(), .error, function, line)
if Log.prints {
print(text)
} else {
os_log("%@", log: log, type: .error, text)
logToOSLog(text, .error)
}
}

// os_log left out warnings, so reuse default type for that
func warn(_ message: String, _ function: String = #function, _ line: Int = #line) {
let text = formatMessage(message, .default, function, line)
func warn(_ message: @autoclosure () -> String, _ function: String = #function, _ line: Int = #line) {
let text = formatMessage(message(), .default, function, line)
if Log.prints {
print(text)
} else {
os_log("%@", log: log, type: .default, text)
logToOSLog(text, .default) // this doesn't get colored yellow like a warning
}
}

func info(_ message: String) {
let text = formatMessage(message, .info)
func info(_ message: @autoclosure () -> String) {
let text = formatMessage(message(), .info)
if Log.prints {
print(text)
} else {
os_log("%@", log: log, type: .info, text)
logToOSLog(text, .info)
}
}

func debug(_ message: String) {
func debug(_ message: @autoclosure () -> String) {
// debug logs are stripped from release builds
#if DEBUG
let text = formatMessage(message, .debug)
let text = formatMessage(message(), .debug)
if Log.prints {
print(text)
} else {
os_log("%@", log: log, type: .debug, text)
logToOSLog(text, .debug)
}
#endif
}

private func formatLevel(_ level: OSLogType) -> String {
switch level {
case .debug: return ""
case .info: return ""
case .default: return "⚠️"
case .error: return "🛑"
default: return ""
}
}

// Customize this printing as desired.
private func formatMessage(_ message: String, _ type: OSLogType, _ function: String = "", _ line: Int = 0) -> String {
private func formatMessage(_ message: String, _ level: OSLogType, _ function: String = "", _ line: Int = 0) -> String {
var text = ""

let levelText = formatLevel(level)

if Log.prints {
let timestamp = Log.formatTimestamp()

// These messages never go out to the system console, just the debugger.
switch type {
switch level {
case .debug:
text += "\(timestamp)D[\(category)] \(message)"
text += "\(timestamp)\(levelText)D[\(category)] \(message)"
case .info:
text += "\(timestamp)I[\(category)] \(message)"
text += "\(timestamp)\(levelText)I[\(category)] \(message)"
case .default: // not a keyword
text += "\(timestamp)W[\(category)] \(message)"
text += "\(timestamp)\(levelText)W[\(category)] \(message)"
text += Log.formatLocation(file, line, function)
case .error:
text += "\(timestamp)E[\(category)] \(message)\n"
text += "\(timestamp)\(levelText)E[\(category)] \(message)\n"
text += Log.formatLocation(file, line, function)
default:
text += message
}
} else {
// Consider reporting the data above to os_log.
// os_log reports data, time, app, threadId and message to stderr.
text += levelText
text += message

// os_log can't show correct file/line, since it uses addrReturnAddress - ugh
switch type {
switch level {
case .default: fallthrough
case .error:
text += Log.formatLocation(file, line, function)
Expand All @@ -180,7 +199,7 @@ class Log {
}
}

if Log.stacktraces && (type == .error) {
if Log.stacktraces && (level == .error) {
text += "\n"

// Improve this - these are mangled symbols without file/line of where
Expand Down
67 changes: 52 additions & 15 deletions kram-profile/kram-profile/kram_profileApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ struct File: Identifiable, Hashable, Equatable, Comparable
var modStamp: Date?
var loadStamp: Date?

// only available for memory file type right now
var threadInfo = ""

init(url: URL) {
self.url = url
self.modStamp = fileModificationDate(url:url)
Expand Down Expand Up @@ -164,12 +167,12 @@ func generateDuration(file: File) -> String {
}
}

func generateNavigationTitle(_ str: String?) -> String {
if str == nil {
func generateNavigationTitle(_ sel: String?) -> String {
if sel == nil {
return ""
}

let f = lookupFile(url: URL(string:str!)!)
let f = lookupFile(selection: sel!)
return generateDuration(file: f) + " " + generateName(file: f)
}

Expand Down Expand Up @@ -198,6 +201,10 @@ func lookupFile(url: URL) -> File {
return file
}

func lookupFile(selection: String) -> File {
return lookupFile(url:URL(string:selection)!)
}

// This one won't be one in the list, though
func updateFileCache(file: File) {
fileCache[file.url] = file
Expand Down Expand Up @@ -586,7 +593,7 @@ func loadFileJS(_ path: String) -> String? {

var description: String {
let duration = Double(endTime - startTime) * 1e-6
return "\(id) \(threadName) \(duration) \(count)x"
return "\(id) '\(threadName)' \(duration)s \so(count)x"
}

}
Expand Down Expand Up @@ -623,10 +630,16 @@ func loadFileJS(_ path: String) -> String? {
}
}

// TODO: could store this in the File object, just append with \n
// DONE: could store this in the File object, just append with \n
var text = ""
for threadInfo in threadInfos.values.sorted() {
log.info(threadInfo.description)
// log.info(threadInfo.description)
text += threadInfo.description
text += "\n"
}

file.threadInfo = text
updateFileCache(file: file)
}

func updateDuration(_ catapultProfile: CatapultProfile, _ file: inout File) {
Expand Down Expand Up @@ -1046,7 +1059,7 @@ struct kram_profileApp: App {

func isReloadEnabled(_ selection: String?) -> Bool {
guard let sel = selection else { return false }
let file = lookupFile(url:URL(string: sel)!)
let file = lookupFile(selection: sel)
return file.isReloadNeeded()
}

Expand Down Expand Up @@ -1074,7 +1087,7 @@ struct kram_profileApp: App {
if str != nil {
runJavascript(webView, str!)

var file = lookupFile(url: URL(string: sel)!)
var file = lookupFile(selection: sel)
file.setLoadStamp()
updateFileCache(file: file)
}
Expand Down Expand Up @@ -1222,12 +1235,20 @@ A tool to help profile mem, perf, and builds.
return false
}

@State private var isShowingPopover = false

func getSelectedThreadInfo(_ selection: String?) -> String {
if selection == nil {
return ""
}
return lookupFile(selection: selection!).threadInfo
}

var body: some Scene {

// WindowGroup brings up old windows which isn't really what I want
// TODO: WindowGroup brings up old windows which isn't really what I want

Window("Main", id: "main") {
//WindowGroup {
NavigationSplitView() {
VStack {
List(searchResults, selection:$selection) { file in
Expand All @@ -1245,7 +1266,7 @@ A tool to help profile mem, perf, and builds.

Text(generateDuration(file: file))
.frame(maxWidth: 70)
//.alignment(.trailing)
//.alignment(.trailing)
.font(durationFont)

}
Expand All @@ -1259,12 +1280,28 @@ A tool to help profile mem, perf, and builds.

}
detail: {
WebView(webView: myWebView)
.focused($focusedField, equals: .webView)
.focusable()
VStack {
// This button conveys data Perfetto does not
// It's basically a hud.
Button("Info") {
self.isShowingPopover.toggle()
}
.keyboardShortcut("I", modifiers:.command)
.disabled(selection == nil)
.popover(isPresented: $isShowingPopover) {
Text(getSelectedThreadInfo(selection))
.multilineTextAlignment(.leading)
.lineLimit(16)
.padding()
}

WebView(webView: myWebView)
.focused($focusedField, equals: .webView)
.focusable()
}
}
.searchableOptional(text: $searchText, isPresented: $searchIsActive, placement: .sidebar, prompt: "Filter")

.onChange(of: selection /*, initial: true*/) { newState in
openFileSelection(myWebView)
//focusedField = .webView
Expand Down

0 comments on commit 498b436

Please sign in to comment.