001 /* 002 Copyright (c) 2008 Evan Jones, Yang Zhang 003 004 Permission is hereby granted, free of charge, to any person obtaining a copy 005 of this software and associated documentation files (the "Software"), to deal 006 in the Software without restriction, including without limitation the rights 007 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 008 copies of the Software, and to permit persons to whom the Software is 009 furnished to do so, subject to the following conditions: 010 011 The above copyright notice and this permission notice shall be included in 012 all copies or substantial portions of the Software. 013 014 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 015 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 016 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 017 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 018 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 019 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 020 THE SOFTWARE. 021 */ 022 023 package util; 024 025 import java.util.ArrayDeque; 026 import java.util.ArrayList; 027 import java.util.Deque; 028 import java.util.HashMap; 029 import java.util.List; 030 import java.util.Map; 031 032 /** 033 * A minimal pure Java sampling profiler. 034 * 035 * Due to biased placement of yield points. Samples will be 036 * biased towards code that contains many such points [1]. Can't 037 * do much about this problem with a pure Java sampler. 038 * 039 * [1] Mytkowicz, Diwan, Hauswirth, Sweeney. "Evaluating the Accuracy of Java Profilers." PLDI 2010 040 */ 041 public class StackSampler extends Sampler { 042 private final Deque<Map<Thread, StackTraceElement[]>> samples; 043 044 /** 045 * Only include stack traces that contain this method name. 046 */ 047 public static final String includeMethodName = "__stackSamplerRecordMe"; 048 049 protected StackSampler(int intervalMillis) { 050 super(intervalMillis); 051 052 samples = new ArrayDeque<Map<Thread, StackTraceElement[]>>(); 053 } 054 055 @Override 056 protected void sample() { 057 samples.add(Thread.getAllStackTraces()); 058 } 059 060 private Map<Thread, List<StackTraceElement[]>> getSamples() { 061 Map<Thread, List<StackTraceElement[]>> retval = new HashMap<Thread, List<StackTraceElement[]>>(); 062 for (Map<Thread, StackTraceElement[]> sample : samples) { 063 for (Map.Entry<Thread, StackTraceElement[]> entry : sample.entrySet()) { 064 Thread t = entry.getKey(); 065 066 StackTraceElement[] stack = entry.getValue(); 067 boolean keep = false; 068 for (int i = 0; i < stack.length; i++) { 069 if (stack[i].getMethodName().startsWith(includeMethodName)) { 070 keep = true; 071 } 072 } 073 074 if (!keep) 075 continue; 076 077 List<StackTraceElement[]> list = retval.get(t); 078 if (list == null) { 079 list = new ArrayList<StackTraceElement[]>(); 080 retval.put(t, list); 081 } 082 083 list.add(stack); 084 } 085 } 086 return retval; 087 } 088 089 @Override 090 protected StackStatistics dumpSamples() { 091 return new StackStatistics(getSamples()); 092 } 093 094 /** 095 * Start sampling with this sampler. 096 * 097 * @param interval sample interval in milliseconds 098 * @return a sampler 099 */ 100 public static Sampler start(int interval) { 101 return start(new StackSampler(interval)); 102 } 103 }