/**
* Copyright (c) 2014 Richard Warburton (richard.warburton@gmail.com)
* <p>
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
* <p>
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
* <p>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
**/
package com.insightfullogic.honest_profiler.ports.console;
import com.insightfullogic.honest_profiler.core.collector.FlatProfileEntry;
import com.insightfullogic.honest_profiler.core.collector.Frame;
import com.insightfullogic.honest_profiler.core.profiles.Profile;
import com.insightfullogic.honest_profiler.core.profiles.ProfileNode;
import java.io.PrintStream;
import java.util.function.Consumer;
import java.util.stream.IntStream;
/**
* Formats printed output for different types of profile.
* <p>
* NB: The use of unnecessary StringBuilder instances rather than
* directly calling print on PrintStream is a deliberate performance
* optimisation to fix issue #56. If you're piping the output through
* head the repeated calls to print cause unnecessary buffering and
* context switching overhead. Using local buffers improves performance
* by 6x-10x.
*/
public enum ProfileFormat
{
FLAT_BY_METHOD
{
@Override
public void printProfile(Profile profile, PrintStream out)
{
StringBuilder sb = new StringBuilder("\n\nFlat Profile (by method):");
profile.flatByMethodProfile().forEach(entry -> appendFlatProfileEntry(sb, entry));
out.print(sb);
}
},
FLAT_BY_LINE
{
@Override
public void printProfile(Profile profile, PrintStream out)
{
StringBuilder sb = new StringBuilder("\n\nFlat Profile (by line):");
profile.flatByFrameProfile().forEach(entry -> appendFlatProfileEntry(sb, entry));
out.print(sb);
}
},
TREE
{
@Override
public void printProfile(Profile profile, PrintStream out)
{
StringBuilder sb = new StringBuilder("\n\nTree Profile:");
profile.getTrees().forEach(tree -> printNode(tree.getRootNode(), 1, sb));
out.print(sb);
}
},
ALL
{
@Override
public void printProfile(Profile profile, PrintStream out)
{
FLAT_BY_METHOD.printProfile(profile, out);
FLAT_BY_LINE.printProfile(profile, out);
TREE.printProfile(profile, out);
}
};
public abstract void printProfile(Profile profile, PrintStream out);
static void appendFlatProfileEntry(StringBuilder sb, FlatProfileEntry entry)
{
Frame method = entry.getFrameInfo();
double totalShare = entry.getTotalTimeShare();
double selfShare = entry.getSelfTimeShare();
sb.append("\n\t");
printFrameInfo(method, totalShare, selfShare, sb::append);
}
static void printFrameInfo(Frame frameInfo, double totalShare, double selfShare, Consumer<String> out)
{
if (frameInfo == null)
{
out.accept("NULL FRAME ERR");
}
else if (frameInfo.getBci() == Frame.BCI_ERR_IGNORE)
{
out.accept(String.format("(t %4.1f,s %4.1f) %s::%s",
totalShare * 100, selfShare * 100,
frameInfo.getClassName(), frameInfo.getMethodName()));
}
else
{
out.accept(String.format("(t %4.1f,s %4.1f) %s::%s @ (bci=%d,line=%d)",
totalShare * 100, selfShare * 100,
frameInfo.getClassName(), frameInfo.getMethodName(),
frameInfo.getBci(), frameInfo.getLine()));
}
}
void printNode(ProfileNode node, int depth, StringBuilder out)
{
out.append("\n");
IntStream.range(0, depth).forEach(ignore -> out.append(' '));
printFrameInfo(node.getFrameInfo(), node.getTotalTimeShare(), node.getSelfTimeShare(), out::append);
int childDepth = depth + 1;
node.children().forEach(child -> printNode(child, childDepth, out));
}
}