Skip to content

Commit

Permalink
Hide smallest nodes if tree is too big
Browse files Browse the repository at this point in the history
  • Loading branch information
kornilova203 committed May 13, 2019
1 parent e4d4ab5 commit 0951663
Show file tree
Hide file tree
Showing 43 changed files with 386 additions and 297 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.github.korniloval.flameviewer.converters.calltraces

import com.github.kornilova_l.flamegraph.proto.TreeProtos
import com.github.kornilova_l.flamegraph.proto.TreeProtos.Tree.Node
import com.github.korniloval.flameviewer.cflamegraph.Tree
import com.github.korniloval.flameviewer.converters.Converter
import com.github.korniloval.flameviewer.converters.cflamegraph.CFlamegraph
import com.github.korniloval.flameviewer.converters.cflamegraph.CFlamegraphLine
import com.github.korniloval.flameviewer.converters.trees.TreesUtil
import com.github.korniloval.flameviewer.server.handlers.treeBuilder
import java.io.File
import java.nio.ByteBuffer
import java.util.*
Expand All @@ -15,9 +17,9 @@ class CFlamegraphToCallTracesConverter(private val cf: CFlamegraph) : Converter<
private var maxDepth = 0

override fun convert(): TreeProtos.Tree {
val tree = createEmptyTree()
val tree = treeBuilder(Node.newBuilder())

val currentStack = ArrayList<TreeProtos.Tree.Node.Builder>()
val currentStack = ArrayList<Node.Builder>()
currentStack.add(tree.baseNodeBuilder)

for (line in cf.lines) {
Expand All @@ -26,12 +28,13 @@ class CFlamegraphToCallTracesConverter(private val cf: CFlamegraph) : Converter<

tree.depth = maxDepth
TreesUtil.setNodesOffsetRecursively(tree.baseNodeBuilder, 0)
TreesUtil.setNodesIndices(tree.baseNodeBuilder)
TreesUtil.setTreeWidth(tree)
TreesUtil.setNodesCount(tree)
return tree.build()
}

private fun processLine(line: CFlamegraphLine, currentStack: ArrayList<TreeProtos.Tree.Node.Builder>) {
private fun processLine(line: CFlamegraphLine, currentStack: ArrayList<Node.Builder>) {
validateLine(line)

while (line.depth < currentStack.size) { // if some calls are finished
Expand Down Expand Up @@ -61,12 +64,6 @@ class CFlamegraphToCallTracesConverter(private val cf: CFlamegraph) : Converter<
require(line.methodNameId >= 0) { "node method name id must be set." }
}

private fun createEmptyTree(): TreeProtos.Tree.Builder {
val tree = TreeProtos.Tree.newBuilder()
tree.setBaseNode(TreeProtos.Tree.Node.newBuilder())
return tree
}

companion object {
const val EXTENSION = "cflamegraph"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import com.github.korniloval.flameviewer.converters.trees.TreesUtil.setNodesCoun
import com.github.korniloval.flameviewer.converters.trees.TreesUtil.setNodesOffsetRecursively
import com.github.korniloval.flameviewer.converters.trees.TreesUtil.updateNodeList
import com.github.korniloval.flameviewer.converters.trees.UniqueStringsKeeper
import com.github.korniloval.flameviewer.server.handlers.treeBuilder


class StacksToTreeBuilder(stacks: Map<String, Int>) : TreeBuilder {
private val treeBuilder: Tree.Builder = Tree.newBuilder()
private val treeBuilder = treeBuilder()
private val tree: Tree
private var maxDepth = 0
private val uniqueStrings = UniqueStringsKeeper()
Expand All @@ -27,6 +28,7 @@ class StacksToTreeBuilder(stacks: Map<String, Int>) : TreeBuilder {
treeBuilder.setBaseNode(Tree.Node.newBuilder())
processStacks(stacks)
setNodesOffsetRecursively(treeBuilder.baseNodeBuilder, 0)
TreesUtil.setNodesIndices(treeBuilder.baseNodeBuilder)
TreesUtil.setTreeWidth(treeBuilder)
setNodesCount(treeBuilder)
treeBuilder.depth = maxDepth
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.github.korniloval.flameviewer.converters.calltraces

import com.github.kornilova_l.flamegraph.proto.TreeProtos
import com.github.kornilova_l.flamegraph.proto.TreeProtos.Tree
import com.github.korniloval.flameviewer.converters.Converter
import com.github.korniloval.flameviewer.converters.trees.TreesUtil
import com.github.korniloval.flameviewer.converters.trees.TreesUtil.parsePositiveInt
import com.github.korniloval.flameviewer.converters.trees.TreesUtil.parsePositiveLong
import com.github.korniloval.flameviewer.converters.trees.UniqueStringsKeeper
import com.github.korniloval.flameviewer.server.handlers.treeBuilder
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
Expand All @@ -14,15 +15,15 @@ import java.util.*

@Deprecated("When a new csv file is added it's converted with YourkitCsvToCFlamegraphConverterFactory. " +
"This converter is to support already uploaded csv files.")
class YourkitToCallTracesConverter(private val file: File) : Converter<TreeProtos.Tree> {
class YourkitToCallTracesConverter(private val file: File) : Converter<Tree> {
private val uniqueStringsClassName = UniqueStringsKeeper()
private val uniqueStringsMethodName = UniqueStringsKeeper()
private val uniqueStringsDesc = UniqueStringsKeeper()
private var maxDepth = 0

override fun convert(): TreeProtos.Tree {
val tree = createEmptyTree()
val currentStack = ArrayList<TreeProtos.Tree.Node.Builder>()
override fun convert(): Tree {
val tree = treeBuilder(Tree.Node.newBuilder())
val currentStack = ArrayList<Tree.Node.Builder>()
currentStack.add(tree.baseNodeBuilder)
BufferedReader(FileReader(file), 1000 * 8192).use { reader ->
var line = reader.readLine()
Expand All @@ -33,13 +34,13 @@ class YourkitToCallTracesConverter(private val file: File) : Converter<TreeProto
}
tree.depth = maxDepth
TreesUtil.setNodesOffsetRecursively(tree.baseNodeBuilder, 0)
TreesUtil.setNodesIndices(tree.baseNodeBuilder)
TreesUtil.setTreeWidth(tree)
TreesUtil.setNodesCount(tree)
return tree.build()
}

private fun processLine(line: String,
currentStack: ArrayList<TreeProtos.Tree.Node.Builder>) {
private fun processLine(line: String, currentStack: ArrayList<Tree.Node.Builder>) {
val delimPos = line.indexOf("\",\"")
if (delimPos == -1) {
return
Expand Down Expand Up @@ -107,12 +108,6 @@ class YourkitToCallTracesConverter(private val file: File) : Converter<TreeProto
return name.substring(lastDot + 1, parametersPos)
}

private fun createEmptyTree(): TreeProtos.Tree.Builder {
val tree = TreeProtos.Tree.newBuilder()
tree.setBaseNode(TreeProtos.Tree.Node.newBuilder())
return tree
}

private fun getCleanName(name: String): String {
val openBracketPos = name.lastIndexOf('(')
val lastSpacePos = name.substring(0, openBracketPos).lastIndexOf(' ') // remove parameters because they may contain spaces
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package com.github.korniloval.flameviewer.converters.calltree;

import com.github.korniloval.flameviewer.converters.trees.TreesSet;
import com.github.korniloval.flameviewer.converters.trees.TreesUtil;
import com.github.kornilova_l.flamegraph.proto.EventProtos;
import com.github.kornilova_l.flamegraph.proto.TreeProtos.Tree;
import com.github.kornilova_l.flamegraph.proto.TreeProtos.Tree.Node;
import com.github.korniloval.flameviewer.converters.trees.TreesSet;
import com.github.korniloval.flameviewer.converters.trees.TreesUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.LinkedList;
import java.util.List;

import static com.github.korniloval.flameviewer.converters.trees.DescriptionConverter.getBeautifulDesc;
import static com.github.korniloval.flameviewer.server.handlers.CoreUtilKt.treeBuilder;

class CTBuilder {
private final String threadName;
Expand Down Expand Up @@ -120,7 +121,7 @@ private void subtractOffsetRecursively(Node.Builder node, long threadStartTime)

@NotNull
private Tree.Builder initTreeBuilder(long startTimeOfFirstThread) {
return Tree.newBuilder()
return treeBuilder()
.setTreeInfo(
Tree.TreeInfo.newBuilder()
.setStartTime(threadStartTime - startTimeOfFirstThread)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.github.kornilova_l.flamegraph.proto.TreeProtos.Tree;

import static com.github.korniloval.flameviewer.server.handlers.CoreUtilKt.treeBuilder;

public class CallTracesMethodBuilder implements TreeBuilder {
private final Tree tree;
private final String className;
Expand All @@ -21,6 +23,7 @@ public CallTracesMethodBuilder(Tree sourceTree,
initTreeBuilder();
traverseTreeAndFind(sourceTree.getBaseNode());
TreesUtil.INSTANCE.setNodesOffsetRecursively(treeBuilder.getBaseNodeBuilder(), 0);
TreesUtil.INSTANCE.setNodesIndices(treeBuilder.getBaseNodeBuilder());
TreesUtil.INSTANCE.setTreeWidth(treeBuilder);
TreesUtil.INSTANCE.setNodesCount(treeBuilder);
setTimePercent(sourceTree);
Expand Down Expand Up @@ -88,8 +91,7 @@ private void initTreeBuilder() {
desc
)
));
treeBuilder = Tree.newBuilder()
.setBaseNode(baseNode);
treeBuilder = treeBuilder(baseNode);
wantedMethodNode = treeBuilder.getBaseNodeBuilder().getNodesBuilder(0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import com.github.kornilova_l.flamegraph.proto.TreesPreviewProtos.TreesPreview
import com.github.kornilova_l.flamegraph.proto.TreesProtos
import com.github.korniloval.flameviewer.converters.trees.TreeType.BACK_TRACES
import com.github.korniloval.flameviewer.converters.trees.TreeType.CALL_TRACES
import com.github.korniloval.flameviewer.converters.trees.TreesUtil.copyNode
import com.github.korniloval.flameviewer.converters.trees.backtraces.BackTracesBuilder
import com.github.korniloval.flameviewer.converters.trees.backtraces.BackTracesMethodBuilder
import com.github.korniloval.flameviewer.converters.trees.hotspots.HotSpot
import com.github.korniloval.flameviewer.converters.trees.hotspots.HotSpotsBuilder
import com.github.korniloval.flameviewer.server.handlers.treeBuilder
import java.util.*


const val maximumNodesCount = 25_000 // amount of visible nodes
const val maximumNodesCount = 2_000 // amount of visible nodes

abstract class TreesSet {
private var hotSpots: ArrayList<HotSpot>? = null
Expand All @@ -33,19 +35,11 @@ abstract class TreesSet {
filter: Filter?): Tree? {
getTree(CALL_TRACES, null) // tree will be filtered later
val callTraces = callTraces ?: return null
val tree: Tree? = when (treeType) {
CALL_TRACES -> {
CallTracesMethodBuilder(callTraces, className, methodName, desc).tree
}
BACK_TRACES -> {
BackTracesMethodBuilder(callTraces, className, methodName, desc).tree
}
}
return if (filter == null) {
tree
} else {
filterTree(tree, filter, false)
val tree = when (treeType) {
CALL_TRACES -> CallTracesMethodBuilder(callTraces, className, methodName, desc).tree
BACK_TRACES -> BackTracesMethodBuilder(callTraces, className, methodName, desc).tree
}
return if (filter == null) tree else filterTree(tree, filter, false)
}

abstract fun getCallTree(filter: Filter?): TreesProtos.Trees?
Expand All @@ -62,16 +56,16 @@ abstract class TreesSet {
return hotSpots
}

protected fun filterTree(tree: Tree?,
protected fun filterTree(tree: Tree,
filter: Filter,
isCallTree: Boolean): Tree? {
val filteredTree = Tree.newBuilder()
val filteredTree = treeBuilder().setVisibleDepth(tree.visibleDepth)
filteredTree.setBaseNode(Node.newBuilder())
if (isCallTree) {
filteredTree.treeInfo = tree!!.treeInfo
filteredTree.treeInfo = tree.treeInfo
buildFilteredCallTreeRecursively(filteredTree.baseNodeBuilder, tree.baseNode, filter)
} else {
buildFilteredTreeRecursively(filteredTree.baseNodeBuilder, tree!!.baseNode, filter)
buildFilteredTreeRecursively(filteredTree.baseNodeBuilder, tree.baseNode, filter)
}
if (filteredTree.baseNodeBuilder.nodesCount == 0) {
return null
Expand Down Expand Up @@ -146,10 +140,8 @@ abstract class TreesSet {

for (child in node.nodesList) {
if (filter.isNodeIncluded(child)) {
var newNode = copyNode(child)
newNode.offset = child.offset
nodeBuilder.addNodes(newNode)
newNode = nodeBuilder.nodesBuilderList[nodeBuilder.nodesBuilderList.size - 1]
nodeBuilder.addNodes(copyNode(child))
val newNode = nodeBuilder.nodesBuilderList[nodeBuilder.nodesBuilderList.size - 1]
buildFilteredCallTreeRecursively(
newNode,
child,
Expand All @@ -160,34 +152,18 @@ abstract class TreesSet {
}
}

private fun copyNode(node: Node): Node.Builder {
val nodeBuilder = Node.newBuilder()
nodeBuilder.width = node.width
nodeBuilder.nodeInfo = node.nodeInfo
return nodeBuilder
}

protected fun getCallTracesMaybeFiltered(filter: Filter?): Tree? {
return if (filter == null) {
callTraces
} else {
filterTree(callTraces, filter, false)
}
val callTraces = callTraces ?: return null
return if (filter == null) callTraces else filterTree(callTraces, filter, false)
}

protected fun getBackTracesMaybeFiltered(filter: Filter?): Tree? {
val callTraces = callTraces ?: return null
if (callTraces.treeInfo.nodesCount > maximumNodesCount) {
throw IllegalArgumentException("Calltraces must contain less than $maximumNodesCount nodes")
}
if (backTraces == null) {
backTraces = BackTracesBuilder(callTraces).tree
}
return if (filter == null) {
backTraces
} else {
filterTree(backTraces, filter, false)
}
val backTraces = if (backTraces != null) backTraces!! else BackTracesBuilder(callTraces).tree
return if (filter == null) backTraces else filterTree(backTraces, filter, false)
}

companion object {
Expand Down
Loading

0 comments on commit 0951663

Please sign in to comment.