[[BackLinksMenu]] [[TicketQuery(summary=GROUP_APP_PERFORMANCE_R1, format=table, col=summary|owner|status|type|component|priority|effort|importance, rows=description|analysis_owners|analysis_reviewers|analysis_score|design_owners|design_reviewers|design_score|implementation_owners|implementation_reviewers|implementation_score|test_owners|test_reviewers|test_score|)]] = Analysis = == Overview == The goal of this task is to improve the performance of the Sophie2 platform before the weekly at 2009-05-26. Concrete subtasks in the next section. == Task requirements == * A custom profiler should be developed for our needs. Lots of profilers exist, I tried some, but for now I think a simple profiler can be written quickly and have some features which I couldn't find in other profilers. So what should the custom profiler do: * Measure time consumption per method as a percentage of the overall time. * Provide an ''own'' mode of measurement -- this means to measure the time which the method itself consumed, excluding the time any other methods that were called consumed. * Provide a ''total'' mode of measurement -- this includes the time which other invoked methods consumed. * Sort the above results by decreasing order of percentage of the total time. * This includes truncating the result to only the first N (given some N). Such reports tend to waste much memory and usually only some of the first ones are interesting and useful for being targeted for optimization. * Structure the profiler report by the natural stack trace execution tree-like structure. This means that at the top of the tree there should be the main() run method of FakeAuthorMain for instance with total time consumption of 100%. Lower there should be methods which are directly invoked from main() and the sum of their total time consumption should be 100%, etc. * This profiler is intended to locate higher level methods which consume too much time and/or are called too many times, so we can optimize them. Locating that lowest level methods like native library file system IO calls are called lots of times doesn't help much because we can't do much to optimize such cases, but finding out that ReflectionUtil.findMethodAnnotation() consumes much time led to a big startup performance optimization before. * If other useful features come up in mind and can be implemented in time, implement them. * Provide a report with the described results in an output plain-text file. * Providing the functionality described above is generally done in two ways -- by actually measuring real execution time and by statistically measuring time consumption. The second is done by doing snapshots of the program's state at a given interval and gathering statistics about current methods in all alive threads. First one seems to be too slow and me and Milo think that the second gives a good enough accuracy of the result, so use the second approach. * If a good enough profiler is proposed and there's no longer a need for a customer profiler, drop it and use the existing one. * Use the (custom or already-existing) profiler to identify low performance spots which could be optimized. * Optimize these spots by either doing quick low-level hacks or by proposing new design which could be implemented in time. == Task result == * A useful profiler should be developed/chosen and a how-to-use section should be included in the wiki. * Ideas for optimizations should be proposed for concrete low performance spots. * If there's time left, implement optimizations. == Implementation idea == * '''hprof''''s file format can be used as a base for the output format of our custom profiler. * Use Thread.getAllStackTraces() and then build a tree. == Related == * [wiki:GROUP_APP_PERFORMANCE_R0] * [wiki:GROUP_PRO_LIB_PERFORMANCE_R0] * [wiki:GROUP_PRO_LIB_PERFORMANCE_R1] == How to demo == * run the profiler * show the profiler results = Design = * a new '''org.sophie2.system''' module will be introduced * a new '''org.sophie2.system.profiler''' package will be introduced * there will be two classes, '''Profiler''' (described below) and '''ProfileUtil''' which will contain of static helper methods. * here's what the Profiler class will look like: {{{ /** * A profiler class which provides a plain-text report for a given application's performance. * * After an instance of this profiler is started, it starts monitoring all the stack traces * in all the {@link Thread}s which execute in the application. It does so by collecting * statistics for the application by performing a snapshot of the application's state at a * given time interval. Thus, this is a statistical profiler, not an event-based profiler * which uses hooks to the JVM. * * The profiler can dump the report to a given {@link PrintStream} at any time by calling * some of the dump*() methods. * * Currently, three types of reports can be produced: * * 1) For each {@link Thread}, a hierarchical view of the stack trace execution is provided: * Each stack trace element is displayed with indent corresponding to its position in the * stack trace when the snapshot was performed along with a number which is the percentage * of the total snapshots done during the {@link Profiler}'s life when this element was present * at this position in the stack trace of the given {@link Thread}. This number is somewhat * identical to the percentage of the {@link Thread}'s execution time this particular method * or a method which it invoked was running. * Also, for each {@Thread}, the percentage of total runtime of the application which the * {@link Thread} consumed is shown. * At each line the {@link Profiler} might put a * which indicates that this method * has spent much time executing (this excludes time spent in execution of other methods * called from the current method) and thus detects a potential optimization spot. * * 2) All stack trace elements in all {@link Thread}s are sorted in decreasing order of their * total execution time. Using this report one can spot methods which have been in the stack * traces much of the time and thus optimizing them could lead to an optimization. * * 3) Same as above but not displaying stack trace elements but methods in all the classes used * during the application's execution. Useful for similar reasons. * * The {@link Profiler} can be killed using the kill() method. * * @author gogov */ public class Profiler { /** * Constructor. * @param snapshotInterval * The interval at which the {@link Profiler} performs a snapshot, * measured in milliseconds. * @param stream * The {@link PrintStream} which the {@Profiler} writes the reports to. */ public Profiler(int snapshotInterval, PrintStream stream); /** * Takes a snapshot of the current application state and updates the inner statistic * records appropriately. */ public void takeSnapshot(); /** * Runs the {@link Profiler}. */ public void run(); /** * Kills the {@link Profiler}. */ public void kill(); /** * Dumps all the stack traces for all {@link Thread}s according to spec. * @param hitsPercentageThreshold * @param ownPercentageWarningThreshold * @param depthLimit */ public void dumpForest(float hitsPercentageThreshold, float ownPercentageWarningThreshold, int depthLimit); /** * Dumps all {@link StackTraceElement}s according to spec. */ public void dumpStackTraceElements(); /** * Dumps all methods according to spec. */ public void dumpMethods(); } }}} * All explanation of the functionality is included in the javadoc of this sample structure. * A helper class which runs a given method, launching a Profiler before the method starts execution and respectively killing it and dumping a report to a file will be added in '''org.sophie2.system'''. * The ''Debug'' launch configurations for Author and Reader will be renamed to ''Profiler'' due to milo's request (: * They will be altered to run helper clases which run FakeAuthorMain and FakeReaderMain's main() methods and dump a report. * Besides running and showing the report, there's no deterministic test for this task because the stack traces of the execution threads are not deterministic so I'm not including a unit test because it's kind of unwriteable at this moment (: * There wasn't enough time to optimize particular pieces of client code in Sophie2 so this is left for the next revision. * Dumping only the first N of the list of stack trace elements or methods respectively, doesn't seem like a big issue for now, because they're not so many after all. * More research of existing profilers will be done in the next revision. = Implementation = = Testing = = Comments = * enter() and leave() behavior for counting method calls can be included in next revisions