From 1eb446d8e926494bd6d8904d1312d1fe63c2302e Mon Sep 17 00:00:00 2001 From: Grirgory Rylov Date: Mon, 5 Feb 2024 09:02:17 +0300 Subject: [PATCH 1/2] #97 added report package filter for current chart --- .../profiler/common/settings/JsonSettings.kt | 1 - .../profiler/analyzer/FlatMethodsReportGenerator.kt | 5 +++-- .../grishberg/profiler/analyzer/ReportGenerator.kt | 2 +- .../profiler/ui/dialogs/ReportsGeneratorDialog.kt | 11 +++++++++-- gradle.properties | 2 +- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/github/grishberg/profiler/common/settings/JsonSettings.kt b/app/src/main/java/com/github/grishberg/profiler/common/settings/JsonSettings.kt index 682d727..b52e294 100644 --- a/app/src/main/java/com/github/grishberg/profiler/common/settings/JsonSettings.kt +++ b/app/src/main/java/com/github/grishberg/profiler/common/settings/JsonSettings.kt @@ -342,7 +342,6 @@ class JsonSettings( override fun filesDir() = filesDirName override var shouldShowToolbar: Boolean = false - override var lastVersion: String = "" private fun initWithDefaults() { initWithDefaultStringValue(SETTINGS_FONT_NAME, "Arial") diff --git a/core/src/main/java/com/github/grishberg/profiler/analyzer/FlatMethodsReportGenerator.kt b/core/src/main/java/com/github/grishberg/profiler/analyzer/FlatMethodsReportGenerator.kt index 728b106..ea8b826 100644 --- a/core/src/main/java/com/github/grishberg/profiler/analyzer/FlatMethodsReportGenerator.kt +++ b/core/src/main/java/com/github/grishberg/profiler/analyzer/FlatMethodsReportGenerator.kt @@ -12,7 +12,7 @@ class FlatMethodsReportGenerator( private val data: CallTracePanel.ProfilerPanelData ) : ReportGenerator { - override fun generate(file: File, onlyConstructor: Boolean, minimumDurationInMs: Int) { + override fun generate(file: File, onlyConstructor: Boolean, minimumDurationInMs: Int, packageFilter: String) { val fos = FileOutputStream(file) BufferedWriter(OutputStreamWriter(fos)).use { bw -> @@ -24,7 +24,8 @@ class FlatMethodsReportGenerator( it.profileData.threadEndTimeInMillisecond - it.profileData.threadStartTimeInMillisecond val globalDuration = it.profileData.globalEndTimeInMillisecond - it.profileData.globalStartTimeInMillisecond - if (threadDuration > minimumDurationInMs && (!onlyConstructor || isConstructor(it.profileData.name))) { + if (threadDuration > minimumDurationInMs && (!onlyConstructor || isConstructor(it.profileData.name)) && + (packageFilter.isEmpty() || it.profileData.name.startsWith(packageFilter))) { bw.write( String.format( "%s\t%.3f\t%.3f\t%.3f\t%.3f", diff --git a/core/src/main/java/com/github/grishberg/profiler/analyzer/ReportGenerator.kt b/core/src/main/java/com/github/grishberg/profiler/analyzer/ReportGenerator.kt index b038faf..a187e02 100644 --- a/core/src/main/java/com/github/grishberg/profiler/analyzer/ReportGenerator.kt +++ b/core/src/main/java/com/github/grishberg/profiler/analyzer/ReportGenerator.kt @@ -3,5 +3,5 @@ package com.github.grishberg.profiler.analyzer import java.io.File interface ReportGenerator { - fun generate(file: File, onlyConstructor: Boolean, minimumDurationInMs: Int) + fun generate(file: File, onlyConstructor: Boolean, minimumDurationInMs: Int, packageFilter: String) } diff --git a/core/src/main/java/com/github/grishberg/profiler/ui/dialogs/ReportsGeneratorDialog.kt b/core/src/main/java/com/github/grishberg/profiler/ui/dialogs/ReportsGeneratorDialog.kt index a38b957..71666fa 100644 --- a/core/src/main/java/com/github/grishberg/profiler/ui/dialogs/ReportsGeneratorDialog.kt +++ b/core/src/main/java/com/github/grishberg/profiler/ui/dialogs/ReportsGeneratorDialog.kt @@ -16,6 +16,7 @@ import javax.swing.JComponent import javax.swing.JFileChooser import javax.swing.JLabel import javax.swing.JPanel +import javax.swing.JTextField import javax.swing.border.EmptyBorder import javax.swing.filechooser.FileNameExtensionFilter @@ -28,6 +29,7 @@ class ReportsGeneratorDialog( private val constructorsCheckbox: JCheckBox private val durationLimit: JNumberField + private val packageFilter: JTextField init { val content = JPanel() @@ -59,6 +61,11 @@ class ReportsGeneratorDialog( "minimum duration", durationLimit, "If checked - will be exported only constructors" ) + packageFilter = JTextField(20) + addLabelAndField( + content, labelConstraints, fieldConstraints, + "package filter", packageFilter, "If not empty - show methods with given package prefix" + ) fieldConstraints.gridy++ fieldConstraints.gridwidth = 2 @@ -102,11 +109,11 @@ class ReportsGeneratorDialog( if (userSelection == JFileChooser.APPROVE_OPTION) { var fileToSave = fileChooser.selectedFile - if (fileToSave.extension.toLowerCase() != "txt") { + if (fileToSave.extension.lowercase() != "txt") { fileToSave = File(fileToSave.absolutePath + ".txt") } settings.reportsFileDialogDir = fileToSave.parent - reportsGeneratorDelegate.generate(fileToSave, constructorsCheckbox.isSelected, durationLimit.value as Int) + reportsGeneratorDelegate.generate(fileToSave, constructorsCheckbox.isSelected, durationLimit.value as Int, packageFilter.text.trim()) isVisible = false } } diff --git a/gradle.properties b/gradle.properties index ba39791..98a7189 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ studioCompilePath=/Applications/Android Studio.app/Contents pluginGroup = com.github.grishberg pluginName = android-methods-profiler -yampVersion = 23.08.25 +yampVersion = 24.02.05 # See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html # for insight into build numbers and IntelliJ Platform versions. From dded8c60ea5374378ae63ebf0218ffba6585c527 Mon Sep 17 00:00:00 2001 From: Grirgory Rylov Date: Tue, 6 Feb 2024 07:31:16 +0300 Subject: [PATCH 2/2] #97 all threads dialog --- .../AllThreadsMethodsReportGenerator.kt | 28 +++++++++++++ .../analyzer/FlatMethodsReportGenerator.kt | 37 ++++++++++------- .../profiler/analyzer/ReportGenerator.kt | 8 +++- .../github/grishberg/profiler/ui/KeyBinder.kt | 2 +- .../github/grishberg/profiler/ui/Main.java | 41 ++++++++++++++++++- .../grishberg/profiler/ui/MenuHistoryItems.kt | 2 +- .../profiler/ui/ShowDialogDelegate.kt | 3 +- .../ui/dialogs/ReportsGeneratorDialog.kt | 10 +++-- gradle.properties | 2 +- 9 files changed, 109 insertions(+), 24 deletions(-) create mode 100644 core/src/main/java/com/github/grishberg/profiler/analyzer/AllThreadsMethodsReportGenerator.kt diff --git a/core/src/main/java/com/github/grishberg/profiler/analyzer/AllThreadsMethodsReportGenerator.kt b/core/src/main/java/com/github/grishberg/profiler/analyzer/AllThreadsMethodsReportGenerator.kt new file mode 100644 index 0000000..d0e02e6 --- /dev/null +++ b/core/src/main/java/com/github/grishberg/profiler/analyzer/AllThreadsMethodsReportGenerator.kt @@ -0,0 +1,28 @@ +package com.github.grishberg.profiler.analyzer + +import com.github.grishberg.profiler.core.AnalyzerResult +import java.io.File + +class AllThreadsMethodsReportGenerator( + private val data: AnalyzerResult, +) : ReportGenerator { + + override fun generate( + file: File, onlyConstructor: Boolean, minimumDurationInMs: Int, packageFilter: String + ) { + val baseDir = file.path + + data.threads.forEach { threadItem -> + val profileData = data.data[threadItem.threadId] ?: return + val reportFile = File(baseDir, normalizeFileName(threadItem.name)) + val singleThreadReportGenerator = FlatMethodsReportGenerator(profileData) + singleThreadReportGenerator.generate( + reportFile, onlyConstructor, minimumDurationInMs, packageFilter + ) + } + } + + private fun normalizeFileName(threadName: String): String { + return threadName.replace("/", "_").replace("\\", "_").replace(":", "_") + } +} diff --git a/core/src/main/java/com/github/grishberg/profiler/analyzer/FlatMethodsReportGenerator.kt b/core/src/main/java/com/github/grishberg/profiler/analyzer/FlatMethodsReportGenerator.kt index ea8b826..85d47a2 100644 --- a/core/src/main/java/com/github/grishberg/profiler/analyzer/FlatMethodsReportGenerator.kt +++ b/core/src/main/java/com/github/grishberg/profiler/analyzer/FlatMethodsReportGenerator.kt @@ -1,42 +1,51 @@ package com.github.grishberg.profiler.analyzer -import com.github.grishberg.profiler.core.ProfileData import com.github.grishberg.profiler.chart.BookmarksRectangle import com.github.grishberg.profiler.chart.CallTracePanel +import com.github.grishberg.profiler.core.ProfileData import java.io.BufferedWriter import java.io.File import java.io.FileOutputStream import java.io.OutputStreamWriter class FlatMethodsReportGenerator( - private val data: CallTracePanel.ProfilerPanelData + private val profileData: List, + private val markers: List = emptyList(), ) : ReportGenerator { - override fun generate(file: File, onlyConstructor: Boolean, minimumDurationInMs: Int, packageFilter: String) { + override fun generate( + file: File, + onlyConstructor: Boolean, + minimumDurationInMs: Int, + packageFilter: String + ) { val fos = FileOutputStream(file) BufferedWriter(OutputStreamWriter(fos)).use { bw -> bw.write("name\tglobal time\tthread time\tglobal self time\tthread self time") bw.newLine() - data.profileData.forEach { - val threadDuration = - it.profileData.threadEndTimeInMillisecond - it.profileData.threadStartTimeInMillisecond - val globalDuration = - it.profileData.globalEndTimeInMillisecond - it.profileData.globalStartTimeInMillisecond - if (threadDuration > minimumDurationInMs && (!onlyConstructor || isConstructor(it.profileData.name)) && - (packageFilter.isEmpty() || it.profileData.name.startsWith(packageFilter))) { + profileData.forEach { + val threadDuration = it.threadEndTimeInMillisecond - it.threadStartTimeInMillisecond + val globalDuration = it.globalEndTimeInMillisecond - it.globalStartTimeInMillisecond + if (threadDuration > minimumDurationInMs && (!onlyConstructor || isConstructor(it.name)) && (packageFilter.isEmpty() || it.name.startsWith( + packageFilter + )) + ) { bw.write( String.format( "%s\t%.3f\t%.3f\t%.3f\t%.3f", - it.profileData.name, globalDuration, threadDuration, - it.profileData.globalSelfTime, it.profileData.threadSelfTime + it.name, + globalDuration, + threadDuration, + it.globalSelfTime, + it.threadSelfTime ) ) bw.newLine() } - val markerRectangle = findMarkerForElement(it.profileData) + val markerRectangle = findMarkerForElement(it) if (markerRectangle != null) { bw.write(": ${markerRectangle.name}") bw.newLine() @@ -46,7 +55,7 @@ class FlatMethodsReportGenerator( } private fun findMarkerForElement(profileData: ProfileData): BookmarksRectangle? { - for (marker in data.markersData) { + for (marker in markers) { if (marker.isForElement(profileData)) { return marker } diff --git a/core/src/main/java/com/github/grishberg/profiler/analyzer/ReportGenerator.kt b/core/src/main/java/com/github/grishberg/profiler/analyzer/ReportGenerator.kt index a187e02..807c58d 100644 --- a/core/src/main/java/com/github/grishberg/profiler/analyzer/ReportGenerator.kt +++ b/core/src/main/java/com/github/grishberg/profiler/analyzer/ReportGenerator.kt @@ -1,7 +1,13 @@ package com.github.grishberg.profiler.analyzer +import com.github.grishberg.profiler.core.ProfileData import java.io.File interface ReportGenerator { - fun generate(file: File, onlyConstructor: Boolean, minimumDurationInMs: Int, packageFilter: String) + fun generate( + file: File, + onlyConstructor: Boolean, + minimumDurationInMs: Int, + packageFilter: String + ) } diff --git a/core/src/main/java/com/github/grishberg/profiler/ui/KeyBinder.kt b/core/src/main/java/com/github/grishberg/profiler/ui/KeyBinder.kt index fed4ce5..b05e8b6 100644 --- a/core/src/main/java/com/github/grishberg/profiler/ui/KeyBinder.kt +++ b/core/src/main/java/com/github/grishberg/profiler/ui/KeyBinder.kt @@ -322,7 +322,7 @@ class KeyBinder( private inner class GenerateReportsAction : AbstractAction() { override fun actionPerformed(e: ActionEvent) { - dialogDelegate.showReportsDialog() + dialogDelegate.showCurrentThreadMethodsReportsDialog() } } diff --git a/core/src/main/java/com/github/grishberg/profiler/ui/Main.java b/core/src/main/java/com/github/grishberg/profiler/ui/Main.java index 4507d2c..3770b28 100644 --- a/core/src/main/java/com/github/grishberg/profiler/ui/Main.java +++ b/core/src/main/java/com/github/grishberg/profiler/ui/Main.java @@ -1,6 +1,8 @@ package com.github.grishberg.profiler.ui; +import com.github.grishberg.profiler.analyzer.AllThreadsMethodsReportGenerator; import com.github.grishberg.profiler.analyzer.FlatMethodsReportGenerator; +import com.github.grishberg.profiler.analyzer.ReportGenerator; import com.github.grishberg.profiler.chart.*; import com.github.grishberg.profiler.chart.flame.FlameChartController; import com.github.grishberg.profiler.chart.flame.FlameChartDialog; @@ -492,6 +494,12 @@ private JMenu createFileMenu() { JMenuItem deleteCurrentFile = new JMenuItem("Delete current file"); + JMenuItem generateCurrentThreadMethodsReportFor = new JMenuItem("Current thread methods duration report"); + generateCurrentThreadMethodsReportFor.setAccelerator(MenuAcceleratorHelperKt.createControlAccelerator('P')); + + JMenuItem generateAllThreadMethodsReportFor = new JMenuItem("All threads methods duration report"); + + file.add(openFile); file.add(openFileInNewWindow); file.add(openMappingFile); @@ -502,6 +510,10 @@ private JMenu createFileMenu() { file.addSeparator(); file.add(openTracesDirInExternalFileManager); file.add(deleteCurrentFile); + file.addSeparator(); + file.add(generateCurrentThreadMethodsReportFor); + file.add(generateAllThreadMethodsReportFor); + openFile.addActionListener(arg0 -> showOpenFileChooser(false)); openFileInNewWindow.addActionListener(arg0 -> showOpenFileChooser(true)); @@ -511,6 +523,9 @@ private JMenu createFileMenu() { exportTraceWithBookmarks.addActionListener(arg0 -> exportTraceWithBookmarks()); openTracesDirInExternalFileManager.addActionListener(arg -> openTracesDirInExternalFileManager()); deleteCurrentFile.addActionListener(arg -> deleteCurrentFile()); + generateCurrentThreadMethodsReportFor.addActionListener(arg -> showCurrentThreadMethodsReportsDialog()); + generateAllThreadMethodsReportFor.addActionListener(arg -> showAllThreadReportsDialog()); + file.addSeparator(); return file; } @@ -1142,10 +1157,32 @@ public void showErrorDialog(String title, String errorMessage) { } @Override - public void showReportsDialog() { + public void showCurrentThreadMethodsReportsDialog() { + final TraceContainer currentResultContainer = resultContainer; + if (currentResultContainer == null) { + log.d("There is no any opened trace file"); + return; + } + hoverInfoPanel.hidePanel(); + + FlatMethodsReportGenerator generator = new FlatMethodsReportGenerator(chart.getCurrentThreadMethods(), chart.getData().markersData); + ReportsGeneratorDialog reportsGeneratorDialog = new ReportsGeneratorDialog(frame, settings, generator); + reportsGeneratorDialog.pack(); + + reportsGeneratorDialog.setLocationRelativeTo(frame); + reportsGeneratorDialog.setVisible(true); + } + + @Override + public void showAllThreadReportsDialog() { + final TraceContainer currentResultContainer = resultContainer; + if (currentResultContainer == null) { + log.d("There is no any opened trace file"); + return; + } hoverInfoPanel.hidePanel(); - FlatMethodsReportGenerator generator = new FlatMethodsReportGenerator(chart.getData()); + final ReportGenerator generator = new AllThreadsMethodsReportGenerator(currentResultContainer.getResult()); ReportsGeneratorDialog reportsGeneratorDialog = new ReportsGeneratorDialog(frame, settings, generator); reportsGeneratorDialog.pack(); diff --git a/core/src/main/java/com/github/grishberg/profiler/ui/MenuHistoryItems.kt b/core/src/main/java/com/github/grishberg/profiler/ui/MenuHistoryItems.kt index 78ac176..db80bee 100644 --- a/core/src/main/java/com/github/grishberg/profiler/ui/MenuHistoryItems.kt +++ b/core/src/main/java/com/github/grishberg/profiler/ui/MenuHistoryItems.kt @@ -7,7 +7,7 @@ import javax.swing.JMenu import javax.swing.JMenuItem private const val MAX_HISTORY_SIZE = 10 -private const val FILE_MENU_ITEMS_COUNT_BEFORE_HISTORY = 11 +private const val FILE_MENU_ITEMS_COUNT_BEFORE_HISTORY = 14 class MenuHistoryItems( diff --git a/core/src/main/java/com/github/grishberg/profiler/ui/ShowDialogDelegate.kt b/core/src/main/java/com/github/grishberg/profiler/ui/ShowDialogDelegate.kt index c15114a..478e9fe 100644 --- a/core/src/main/java/com/github/grishberg/profiler/ui/ShowDialogDelegate.kt +++ b/core/src/main/java/com/github/grishberg/profiler/ui/ShowDialogDelegate.kt @@ -3,6 +3,7 @@ package com.github.grishberg.profiler.ui interface ShowDialogDelegate { fun showOpenFileChooser(inNewWindow: Boolean = false) fun showNewTraceDialog(inNewWindow: Boolean = false) - fun showReportsDialog() + fun showCurrentThreadMethodsReportsDialog() + fun showAllThreadReportsDialog() fun showScaleRangeDialog() } diff --git a/core/src/main/java/com/github/grishberg/profiler/ui/dialogs/ReportsGeneratorDialog.kt b/core/src/main/java/com/github/grishberg/profiler/ui/dialogs/ReportsGeneratorDialog.kt index 71666fa..28f53e4 100644 --- a/core/src/main/java/com/github/grishberg/profiler/ui/dialogs/ReportsGeneratorDialog.kt +++ b/core/src/main/java/com/github/grishberg/profiler/ui/dialogs/ReportsGeneratorDialog.kt @@ -3,7 +3,6 @@ package com.github.grishberg.profiler.ui.dialogs import com.github.grishberg.profiler.analyzer.ReportGenerator import com.github.grishberg.profiler.common.JNumberField import com.github.grishberg.profiler.common.settings.SettingsFacade -import com.github.grishberg.profiler.ui.Main import java.awt.Frame import java.awt.GridBagConstraints import java.awt.GridBagLayout @@ -58,7 +57,7 @@ class ReportsGeneratorDialog( durationLimit.value = 0 addLabelAndField( content, labelConstraints, fieldConstraints, - "minimum duration", durationLimit, "If checked - will be exported only constructors" + "minimum duration", durationLimit, "Minimum global time duration in ms" ) packageFilter = JTextField(20) @@ -113,7 +112,12 @@ class ReportsGeneratorDialog( fileToSave = File(fileToSave.absolutePath + ".txt") } settings.reportsFileDialogDir = fileToSave.parent - reportsGeneratorDelegate.generate(fileToSave, constructorsCheckbox.isSelected, durationLimit.value as Int, packageFilter.text.trim()) + reportsGeneratorDelegate.generate( + fileToSave, + constructorsCheckbox.isSelected, + durationLimit.value as Int, + packageFilter.text.trim() + ) isVisible = false } } diff --git a/gradle.properties b/gradle.properties index 98a7189..4164b92 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ studioCompilePath=/Applications/Android Studio.app/Contents pluginGroup = com.github.grishberg pluginName = android-methods-profiler -yampVersion = 24.02.05 +yampVersion = 24.02.06 # See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html # for insight into build numbers and IntelliJ Platform versions.