/** * Contains the data structures for storing the information gathered during a profiling session with as little * redundancy as possible. * <h1>Profiler Basics</h1> * <h2>Collected Information</h2> * <p> * During a profiling session, the following information is gathered : * <ul> * <li>Stack trace start events, specifying : * <ul> * <li>the id of the thread the following stack trace sample comes from</li> * <li>the timestamp in nanoseconds</li> * </ul> * <li>Stack trace samples consisting of a series of stack frames, each specifying : * <ul> * <li>the id of the method being executed in the frame</li> * <li>the line number correponding to the code being executed in the frame</li> * <li>the Byte Code Index (BCI), pointing to the bytecode instruction being executed in the frame</li> * </ul> * </li> * <li>Thread metadata, which associates a name with the thread id</li> * <li>Method metadata, specifying : * <ul> * <li>the id of the method</li> * <li>the name of the Java source file defining the method</li> * <li>the fully qualified name of the class defining the method</li> * <li>the name of the method</li> * </ul> * </li> * </ul> * <h2>Stack Trace Samples</h2> * <p> * A stack trace sample contains the information about the method currently being executed by the JVM when the sample * was taken. It is structured as a hierarchical list of stack frames, where the "bottom frame" (received first) * specifies the method whose bytecode is executed in the stack frame. Every subsequent stack frame is the parent of the * previous stack frame, and specifies which method called the method in the previous frame. * <p> * The final "root" frame specifies the top-level method executed by the containing {@link java.lang.Thread}. Typically * this is the <code>java.lang.Thread.run()</code> method, but it can also be class initialization or classloader * launching code. * <h1>{@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanProfile} Aggregation</h1> * <p> * All of this information is aggregated into a * {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanProfile} object by the * {@link com.insightfullogic.honest_profiler.core.collector.lean.LeanLogCollector}. * <h2>Metadata</h2> * <p> * For the metadata, no aggregation takes place, except for the thread name : sometimes multiple Thread metadata events * are received for the same thread id, with only one containing the name. In that case, the last metadata with a * non-trivial (non-null and not empty) name is retained. * </p> * <h3>Thread Metadata</h3> * <p> * The metadata for a thread is stored in the * {@link com.insightfullogic.honest_profiler.core.profiles.lean.info.ThreadInfo} object. These objects are stored in * the {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanProfile} in a {@link java.util.Map} with the * thread id as key. * </p> * <h3>Method Metadata</h3> * <p> * The metadata for a method is stored in the * {@link com.insightfullogic.honest_profiler.core.profiles.lean.info.MethodInfo} object. These objects are stored in * the {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanProfile} in a {@link java.util.Map} with the * method id as key. * </p> * <h2>Core Profile Data</h2> * <p> * The stack frame samples are all aggregated into trees of * {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanNode}s. * </p> * <h3>Aggregated Numeric Data</h3> * <p> * Aggregating data means that you split up the data in groups, each group having a unique identifier or key which we'll * call an aggregation key, and calculating some values for each group, which we'll call the aggregated data. * <p> * The aggregated data in {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanProfile}s is stored in the * {@link com.insightfullogic.honest_profiler.core.profiles.lean.info.NumericInfo} object. There are only four basic * quantities which are directly or indirectly measured, and these are all represented as members of * {@link com.insightfullogic.honest_profiler.core.profiles.lean.info.NumericInfo} : * <ul> * <li>Total Sample Count : the number of times a frame was seen in a stack sample</li> * <li>Self Sample Count : the number of times a frame was seen in a stack sample as "bottom frame"</li> * <li>Total Time : the amount of time, in nanoseconds, which was spent executing the method or a method called by this * method</li> * <li>Self Time : the amount of time, in nanoseconds, which was spent executing the method itself</li> * </ul> * <p> * For each frame, these quantities can be calculated. The Count quantities are pretty straightforward. The Time * quantities, for a particular frame, are approximated by taking the difference between the timestamp in the Stack * trace start events immediately preceding and following the stack trace sample the frame is seen in, and adding this * to the Total Time, and if the frame is the bottom frame, to the Self Time as well. * </p> * <h3>{@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanNode} Trees</h3> * <p> * For the basic {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanProfile} aggregation, stack frames * are grouped by method id + line number + bci, and by the identities of its ancestors as well as the id of the thread * the frame was executed on. * <p> * This is modeled by a {@link java.util.Map} of trees of * {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanNode}s. There are two kinds : * <ul> * <li>the {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanThreadNode} subclass which represents the * thread</li> * <li>a "pure" {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanNode} which represents a frame</li> * </ul> * <p> * The root {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanNode} of every tree is a * {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanThreadNode} representing the thread by which the * frames were executed. The quantities in its * {@link com.insightfullogic.honest_profiler.core.profiles.lean.info.NumericInfo} are the sum of those of all its * descendants. * <p> * The {@link java.util.Map} in the {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanProfile} * associates the thread id with the corresponding root * {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanThreadNode}. * <p> * Every {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanNode} contains a {@link java.util.Map} of its * child {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanNode}s, which represent the child stack * frames called at least once in a stack trace sample by the frame represented by the * {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanNode}. The key in the child {@link java.util.Map} * is the {@link com.insightfullogic.honest_profiler.core.profiles.lean.info.FrameInfo} for the frame represented by the * child {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanNode}. In case of a * {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanThreadNode}, the children are the frames * representing methods called directly by the thread. * <p> * Every {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanNode} in the tree is therefore identified by * the list of its ancestors and the contents of its * {@link com.insightfullogic.honest_profiler.core.profiles.lean.info.FrameInfo}. * <p> * For navigation and aggregation purposes, every * {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanNode} also contains the reference to its parent * {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanNode} (with the exception of * {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanThreadNode}s which have null as parent reference). * </p> * <h1>Summary</h1> As a form of synopsis, here's a diagram of the * {@link com.insightfullogic.honest_profiler.core.profiles.lean.LeanProfile} contents : * * <pre> * {@code * LeanProfile * | * ---MAP : Thread id -> ThreadInfo --- Thread id * | | * | -- Thread name * * | * ---MAP : Method id -> MethodInfo --- Method id * | | * | -- File name * | | * | -- Class name (FQCN) * | | * | -- Method name * | * | * --MAP : Thread id -> LeanThreadNode --- ThreadInfo * | * -- NumericInfo --- Total Sample Count (sum of descendant TSC) * | | * | -- Self Sample Count (sum of descendant SSC) * | | * | -- Total Time (sum of descendant TT) * | | * | -- Self Time (sum of descendant ST) * | * -- Parent -> null * | * -- MAP : FrameInfo -> LeanNode --- Parent -> [Parent Lean(Thread)Node] * | * -- NumericInfo --- Total Sample Count * | | * | -- Self Sample Count * | | * | -- Total Time * | | * | -- Self Time * | * -- MAP : FrameInfo -> LeanNode --- ... * } * </pre> */ package com.insightfullogic.honest_profiler.core.profiles.lean;