Skip to content

Commit

Permalink
Merge pull request #84 from Grigory-Rylov/find_in_all_threads
Browse files Browse the repository at this point in the history
Find in all threads
  • Loading branch information
Grigory-Rylov committed Aug 9, 2022
2 parents ccd0656 + 4e2aaf2 commit 6e7c137
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 95 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ allprojects {
subprojects {
apply plugin: 'idea'
ext {
productVersion = '22.06.09.0'
productVersion = '22.08.08.0'
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.github.grishberg.profiler.chart;

import com.github.grishberg.profiler.core.AnalyzerResult;
import com.github.grishberg.profiler.core.ProfileData;
import com.github.grishberg.profiler.analyzer.AnalyzerResultImpl;
import com.github.grishberg.profiler.analyzer.ThreadTimeBoundsImpl;
import com.github.grishberg.profiler.chart.highlighting.MethodsColorImpl;
Expand All @@ -14,6 +12,8 @@
import com.github.grishberg.profiler.common.TraceContainer;
import com.github.grishberg.profiler.common.settings.SettingsFacade;
import com.github.grishberg.profiler.comparator.model.ComparableProfileData;
import com.github.grishberg.profiler.core.AnalyzerResult;
import com.github.grishberg.profiler.core.ProfileData;
import com.github.grishberg.profiler.ui.BookMarkInfo;
import com.github.grishberg.profiler.ui.SimpleComponentListener;
import com.github.grishberg.profiler.ui.TimeFormatter;
Expand All @@ -22,7 +22,6 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.lang.model.type.ArrayType;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Dimension;
Expand Down Expand Up @@ -57,7 +56,7 @@ public class CallTracePanel extends JPanel implements ProfileDataDimensionDelega
private static final double MINIMUM_WIDTH_IN_PX = 1;
private static final AnalyzerResultImpl RESULT_STUB = new AnalyzerResultImpl(Collections.emptyMap(), Collections.emptyMap(), 0, Collections.emptyMap(), Collections.emptyList(), 0, -1);

private final FoundInfoListener<ProfileData> foundInfoListener;
private final FoundNavigationListener<ProfileData> foundNavigationListener;
private boolean init = true;

private final Bookmarks bookmarks;
Expand Down Expand Up @@ -111,7 +110,7 @@ public class CallTracePanel extends JPanel implements ProfileDataDimensionDelega

public CallTracePanel(TimeFormatter timeFormatter,
MethodsColorImpl methodsColor,
FoundInfoListener foundInfoListener,
FoundNavigationListener foundInfoListener,
SettingsFacade settings,
AppLogger logger,
DependenciesFoundAction dependenciesFoundAction,
Expand All @@ -123,7 +122,7 @@ public CallTracePanel(TimeFormatter timeFormatter,
Palette palette) {
this.timeFormatter = timeFormatter;
this.methodsColor = methodsColor;
this.foundInfoListener = foundInfoListener;
this.foundNavigationListener = foundInfoListener;
this.settings = settings;
this.logger = logger;
this.stagesFacade = stagesFacade;
Expand Down Expand Up @@ -839,39 +838,28 @@ private int findElementIndexByXY(double x, double y) {
return -1;
}

public void findItems(String textToFind, boolean ignoreCase) {
boolean shouldEndsWithText = textToFind.endsWith("()");
if (shouldEndsWithText) {
textToFind = textToFind.substring(0, textToFind.length() - 2);
}
public void renderFoundItems(Finder.ThreadFindResult threadFindResult) {
isSearchingInProgress = true;
String targetString = ignoreCase ? textToFind.toLowerCase() : textToFind;

foundItems.clear();

List<ProfileRectangle> objectsForThread = objects.getOrDefault(currentThreadId, Collections.emptyList());
for (int i = 0; i < objectsForThread.size(); i++) {
ProfileRectangle element = objectsForThread.get(i);

String lowerCasedName = ignoreCase ? element.profileData.getName().toLowerCase() : element.profileData.getName();
boolean isEquals = shouldEndsWithText ? lowerCasedName.endsWith(targetString) : lowerCasedName.contains(targetString);
if (isEquals) {
if (threadFindResult.hasMethod(element.profileData)) {
foundItems.add(element);
element.isFoundElement = true;
} else {
element.isFoundElement = false;
}
}
if (foundItems.isEmpty()) {
foundInfoListener.onNotFound(textToFind, ignoreCase);
isSearchingInProgress = false;
repaint();
return;
}

currentFocusedFoundElement = 0;
ProfileRectangle element = foundItems.get(currentFocusedFoundElement);
foundInfoListener.onFound(foundItems.size(), currentFocusedFoundElement, element.profileData);
foundNavigationListener.onSelected(foundItems.size(), currentFocusedFoundElement, element.profileData);
zoomAndPanDelegate.fitZoom(element, FIT_PADDING, ZoomAndPanDelegate.VerticalAlign.ENABLED);

requestFocus();
}

private void navigateToElement(Shape element) {
Expand Down Expand Up @@ -965,26 +953,41 @@ public void focusPrevFoundItem() {
if (foundItems.size() > 0) {
currentFocusedFoundElement--;
if (currentFocusedFoundElement < 0) {
currentFocusedFoundElement = foundItems.size() - 1;
foundNavigationListener.onNavigatedOverFirstItem();
return;
}
ProfileRectangle found = foundItems.get(currentFocusedFoundElement);
zoomAndPanDelegate.fitZoom(found, FIT_PADDING, ZoomAndPanDelegate.VerticalAlign.ENABLED);
foundInfoListener.onFound(foundItems.size(), currentFocusedFoundElement, found.profileData);

focusFoundItem(currentFocusedFoundElement);
}
}

public void resetFoundItemToEnd() {
currentFocusedFoundElement = foundItems.size() - 1;
focusFoundItem(currentFocusedFoundElement);
}

private void focusFoundItem(int currentFocusedFoundElement) {
ProfileRectangle found = foundItems.get(currentFocusedFoundElement);
zoomAndPanDelegate.fitZoom(found, FIT_PADDING, ZoomAndPanDelegate.VerticalAlign.ENABLED);
foundNavigationListener.onSelected(foundItems.size(), currentFocusedFoundElement, found.profileData);
}

public void focusNextFoundItem() {
if (foundItems.size() > 0) {
currentFocusedFoundElement++;
if (currentFocusedFoundElement >= foundItems.size()) {
currentFocusedFoundElement = 0;
foundNavigationListener.onNavigatedOverLastItem();
return;
}
ProfileRectangle found = foundItems.get(currentFocusedFoundElement);
zoomAndPanDelegate.fitZoom(found, FIT_PADDING, ZoomAndPanDelegate.VerticalAlign.ENABLED);
foundInfoListener.onFound(foundItems.size(), currentFocusedFoundElement, found.profileData);
focusFoundItem(currentFocusedFoundElement);
}
}

public void resetFoundItemToStart() {
currentFocusedFoundElement = 0;
focusFoundItem(currentFocusedFoundElement);
}

public void focusPrevMarker() {
BookmarksRectangle currentSelectedBookmark = bookmarks.focusPreviousBookmark();
if (currentSelectedBookmark != null) {
Expand Down
135 changes: 124 additions & 11 deletions core/src/main/java/com/github/grishberg/profiler/chart/Finder.kt
Original file line number Diff line number Diff line change
@@ -1,37 +1,130 @@
package com.github.grishberg.profiler.chart

import com.github.grishberg.profiler.common.CoroutinesDispatchers
import com.github.grishberg.profiler.core.AnalyzerResult
import com.github.grishberg.profiler.core.ProfileData
import com.github.grishberg.profiler.core.ThreadItem
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class Finder(
private val analyzerResult: AnalyzerResult
private val coroutineScope: CoroutineScope,
private val dispatchers: CoroutinesDispatchers
) {
fun findInThread(textToFind: String, ignoreCase: Boolean, exceptThreadId: Int = -1): FindResult {
for (currentData in analyzerResult.data) {
val threadId = currentData.key
interface FindResultListener {
fun onFindDone(findResult: FindResult)
}

var listener: FindResultListener? = null

private var currentSelectedThreadIndex: Int = -1

private var currentFindResult: FindResult = FindResult(emptyList())

fun getSearchResultThreadsCount(): Int {
return currentFindResult.threadResults.size
}

fun getCurrentThreadResult(): ThreadFindResult = currentFindResult.threadResults[currentSelectedThreadIndex]

fun getNextThread(): ThreadItem {
val index = getNextThreadIndex()
return currentFindResult.threadResults[index].threadItem
}

fun getPreviousThread(): ThreadItem {
val index = getPreviousThreadIndex()
return currentFindResult.threadResults[index].threadItem
}

fun switchNextThread() {
currentSelectedThreadIndex = getNextThreadIndex()
}

private fun getNextThreadIndex(): Int {
if (currentSelectedThreadIndex == -1) {
return -1
}
return if (currentSelectedThreadIndex + 1 >= currentFindResult.threadResults.size) {
0
} else {
currentSelectedThreadIndex + 1
}
}

fun switchPreviousThread() {
currentSelectedThreadIndex = getPreviousThreadIndex()
}

private fun getPreviousThreadIndex(): Int {
if (currentSelectedThreadIndex == -1) {
return -1
}

return if (currentSelectedThreadIndex - 1 < 0) {
currentFindResult.threadResults.size - 1
} else {
currentSelectedThreadIndex - 1
}
}

fun findMethods(
analyzerResult: AnalyzerResult,
textToFind: String,
ignoreCase: Boolean,
) {
currentSelectedThreadIndex = -1
coroutineScope.launch {
val data = withContext(dispatchers.worker) {
findInThread(analyzerResult, textToFind, ignoreCase)
}
withContext(dispatchers.ui) {
currentFindResult = data
if (data.threadResults.isNotEmpty()) {
currentSelectedThreadIndex = 0
}
listener?.onFindDone(data)
}
}
}

private fun findInThread(
analyzerResult: AnalyzerResult,
textToFind: String,
ignoreCase: Boolean,
exceptThreadId: Int = -1
): FindResult {
val result = mutableListOf<ThreadFindResult>()
for (threadData in analyzerResult.data) {
val threadId = threadData.key
if (exceptThreadId == threadId) {
continue
}
val profileList = currentData.value

val profileList = threadData.value

val shouldEndsWithText: Boolean = textToFind.endsWith("()")
val targetString = prepareTextToFind(shouldEndsWithText, textToFind, ignoreCase)

val foundMethods = mutableSetOf<ProfileData>()
for (i in profileList.indices) {
val profileData = profileList[i]
val lowerCasedName: String = if (ignoreCase) profileData.name.toLowerCase() else profileData.name
val currentMethod = profileList[i]
val lowerCasedName: String = if (ignoreCase) currentMethod.name.toLowerCase() else currentMethod.name
val isEquals: Boolean =
if (shouldEndsWithText) lowerCasedName.endsWith(targetString) else lowerCasedName.contains(
targetString
)
if (isEquals) {
return FindResult(listOf(profileData), threadId)
foundMethods.add(currentMethod)
}
}
if (foundMethods.isNotEmpty()) {
val threadItem = analyzerResult.threads.find { it.threadId == threadId }!!
result.add(ThreadFindResult(foundMethods, threadId, threadItem))
}
}

return FindResult(emptyList(), -1)
return FindResult(result)
}

private fun prepareTextToFind(
Expand All @@ -48,5 +141,25 @@ class Finder(
return targetString
}

data class FindResult(val foundResult: List<ProfileData>, val threadId: Int)
data class FindResult(val threadResults: List<ThreadFindResult>) {
fun generateFoundThreadNames(): String {
if (threadResults.isEmpty()) {
return ""
}
val threadNames = threadResults.map { it.threadItem.name }
return threadNames.joinToString("\n")
}

fun getResultForThread(threadId: Int): ThreadFindResult? {
return threadResults.find { it.threadId == threadId }
}
}

data class ThreadFindResult(
val foundResult: Set<ProfileData>,
val threadId: Int,
val threadItem: ThreadItem
) {
fun hasMethod(method: ProfileData) = foundResult.contains(method)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.grishberg.profiler.chart

@Deprecated("Use FoundNavigationListener")
interface FoundInfoListener<T> {
fun onFound(count: Int, selectedIndex: Int, selectedElement: T)
fun onNotFound(text: String, ignoreCase: Boolean)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.github.grishberg.profiler.chart

interface FoundNavigationListener<T> {
fun onSelected(count: Int, selectedIndex: Int, selectedElement: T)
fun onNavigatedOverLastItem()
fun onNavigatedOverFirstItem()
}
Loading

0 comments on commit 6e7c137

Please sign in to comment.