Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- |
michael@0 | 2 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | package org.mozilla.gecko; |
michael@0 | 7 | |
michael@0 | 8 | import android.os.SystemClock; |
michael@0 | 9 | import android.util.Log; |
michael@0 | 10 | import android.util.SparseArray; |
michael@0 | 11 | |
michael@0 | 12 | import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI; |
michael@0 | 13 | |
michael@0 | 14 | import java.lang.Thread; |
michael@0 | 15 | import java.util.Set; |
michael@0 | 16 | |
michael@0 | 17 | public class GeckoJavaSampler { |
michael@0 | 18 | private static final String LOGTAG = "JavaSampler"; |
michael@0 | 19 | private static Thread sSamplingThread = null; |
michael@0 | 20 | private static SamplingThread sSamplingRunnable = null; |
michael@0 | 21 | private static Thread sMainThread = null; |
michael@0 | 22 | private static volatile boolean sLibsLoaded = false; |
michael@0 | 23 | |
michael@0 | 24 | // Use the same timer primitive as the profiler |
michael@0 | 25 | // to get a perfect sample syncing. |
michael@0 | 26 | private static native double getProfilerTime(); |
michael@0 | 27 | |
michael@0 | 28 | private static class Sample { |
michael@0 | 29 | public Frame[] mFrames; |
michael@0 | 30 | public double mTime; |
michael@0 | 31 | public long mJavaTime; // non-zero if Android system time is used |
michael@0 | 32 | public Sample(StackTraceElement[] aStack) { |
michael@0 | 33 | mFrames = new Frame[aStack.length]; |
michael@0 | 34 | if (sLibsLoaded) { |
michael@0 | 35 | mTime = getProfilerTime(); |
michael@0 | 36 | } |
michael@0 | 37 | if (mTime == 0.0d) { |
michael@0 | 38 | // getProfilerTime is not available yet; either libs are not loaded, |
michael@0 | 39 | // or profiling hasn't started on the Gecko side yet |
michael@0 | 40 | mJavaTime = SystemClock.elapsedRealtime(); |
michael@0 | 41 | } |
michael@0 | 42 | for (int i = 0; i < aStack.length; i++) { |
michael@0 | 43 | mFrames[aStack.length - 1 - i] = new Frame(); |
michael@0 | 44 | mFrames[aStack.length - 1 - i].fileName = aStack[i].getFileName(); |
michael@0 | 45 | mFrames[aStack.length - 1 - i].lineNo = aStack[i].getLineNumber(); |
michael@0 | 46 | mFrames[aStack.length - 1 - i].methodName = aStack[i].getMethodName(); |
michael@0 | 47 | mFrames[aStack.length - 1 - i].className = aStack[i].getClassName(); |
michael@0 | 48 | } |
michael@0 | 49 | } |
michael@0 | 50 | } |
michael@0 | 51 | private static class Frame { |
michael@0 | 52 | public String fileName; |
michael@0 | 53 | public int lineNo; |
michael@0 | 54 | public String methodName; |
michael@0 | 55 | public String className; |
michael@0 | 56 | } |
michael@0 | 57 | |
michael@0 | 58 | private static class SamplingThread implements Runnable { |
michael@0 | 59 | private final int mInterval; |
michael@0 | 60 | private final int mSampleCount; |
michael@0 | 61 | |
michael@0 | 62 | private boolean mPauseSampler = false; |
michael@0 | 63 | private boolean mStopSampler = false; |
michael@0 | 64 | |
michael@0 | 65 | private SparseArray<Sample[]> mSamples = new SparseArray<Sample[]>(); |
michael@0 | 66 | private int mSamplePos; |
michael@0 | 67 | |
michael@0 | 68 | public SamplingThread(final int aInterval, final int aSampleCount) { |
michael@0 | 69 | // If we sample faster then 10ms we get to many missed samples |
michael@0 | 70 | mInterval = Math.max(10, aInterval); |
michael@0 | 71 | mSampleCount = aSampleCount; |
michael@0 | 72 | } |
michael@0 | 73 | |
michael@0 | 74 | public void run() { |
michael@0 | 75 | synchronized (GeckoJavaSampler.class) { |
michael@0 | 76 | mSamples.put(0, new Sample[mSampleCount]); |
michael@0 | 77 | mSamplePos = 0; |
michael@0 | 78 | |
michael@0 | 79 | // Find the main thread |
michael@0 | 80 | Set<Thread> threadSet = Thread.getAllStackTraces().keySet(); |
michael@0 | 81 | for (Thread t : threadSet) { |
michael@0 | 82 | if (t.getName().compareToIgnoreCase("main") == 0) { |
michael@0 | 83 | sMainThread = t; |
michael@0 | 84 | break; |
michael@0 | 85 | } |
michael@0 | 86 | } |
michael@0 | 87 | |
michael@0 | 88 | if (sMainThread == null) { |
michael@0 | 89 | Log.e(LOGTAG, "Main thread not found"); |
michael@0 | 90 | return; |
michael@0 | 91 | } |
michael@0 | 92 | } |
michael@0 | 93 | |
michael@0 | 94 | while (true) { |
michael@0 | 95 | try { |
michael@0 | 96 | Thread.sleep(mInterval); |
michael@0 | 97 | } catch (InterruptedException e) { |
michael@0 | 98 | e.printStackTrace(); |
michael@0 | 99 | } |
michael@0 | 100 | synchronized (GeckoJavaSampler.class) { |
michael@0 | 101 | if (!mPauseSampler) { |
michael@0 | 102 | StackTraceElement[] bt = sMainThread.getStackTrace(); |
michael@0 | 103 | mSamples.get(0)[mSamplePos] = new Sample(bt); |
michael@0 | 104 | mSamplePos = (mSamplePos+1) % mSamples.get(0).length; |
michael@0 | 105 | } |
michael@0 | 106 | if (mStopSampler) { |
michael@0 | 107 | break; |
michael@0 | 108 | } |
michael@0 | 109 | } |
michael@0 | 110 | } |
michael@0 | 111 | } |
michael@0 | 112 | |
michael@0 | 113 | private Sample getSample(int aThreadId, int aSampleId) { |
michael@0 | 114 | if (aThreadId < mSamples.size() && aSampleId < mSamples.get(aThreadId).length && |
michael@0 | 115 | mSamples.get(aThreadId)[aSampleId] != null) { |
michael@0 | 116 | int startPos = 0; |
michael@0 | 117 | if (mSamples.get(aThreadId)[mSamplePos] != null) { |
michael@0 | 118 | startPos = mSamplePos; |
michael@0 | 119 | } |
michael@0 | 120 | int readPos = (startPos + aSampleId) % mSamples.get(aThreadId).length; |
michael@0 | 121 | return mSamples.get(aThreadId)[readPos]; |
michael@0 | 122 | } |
michael@0 | 123 | return null; |
michael@0 | 124 | } |
michael@0 | 125 | } |
michael@0 | 126 | |
michael@0 | 127 | |
michael@0 | 128 | @WrapElementForJNI(allowMultithread = true, stubName = "GetThreadNameJavaProfilingWrapper") |
michael@0 | 129 | public synchronized static String getThreadName(int aThreadId) { |
michael@0 | 130 | if (aThreadId == 0 && sMainThread != null) { |
michael@0 | 131 | return sMainThread.getName(); |
michael@0 | 132 | } |
michael@0 | 133 | return null; |
michael@0 | 134 | } |
michael@0 | 135 | |
michael@0 | 136 | private synchronized static Sample getSample(int aThreadId, int aSampleId) { |
michael@0 | 137 | return sSamplingRunnable.getSample(aThreadId, aSampleId); |
michael@0 | 138 | } |
michael@0 | 139 | |
michael@0 | 140 | @WrapElementForJNI(allowMultithread = true, stubName = "GetSampleTimeJavaProfiling") |
michael@0 | 141 | public synchronized static double getSampleTime(int aThreadId, int aSampleId) { |
michael@0 | 142 | Sample sample = getSample(aThreadId, aSampleId); |
michael@0 | 143 | if (sample != null) { |
michael@0 | 144 | if (sample.mJavaTime != 0) { |
michael@0 | 145 | return (double)(sample.mJavaTime - |
michael@0 | 146 | SystemClock.elapsedRealtime()) + getProfilerTime(); |
michael@0 | 147 | } |
michael@0 | 148 | System.out.println("Sample: " + sample.mTime); |
michael@0 | 149 | return sample.mTime; |
michael@0 | 150 | } |
michael@0 | 151 | return 0; |
michael@0 | 152 | } |
michael@0 | 153 | |
michael@0 | 154 | @WrapElementForJNI(allowMultithread = true, stubName = "GetFrameNameJavaProfilingWrapper") |
michael@0 | 155 | public synchronized static String getFrameName(int aThreadId, int aSampleId, int aFrameId) { |
michael@0 | 156 | Sample sample = getSample(aThreadId, aSampleId); |
michael@0 | 157 | if (sample != null && aFrameId < sample.mFrames.length) { |
michael@0 | 158 | Frame frame = sample.mFrames[aFrameId]; |
michael@0 | 159 | if (frame == null) { |
michael@0 | 160 | return null; |
michael@0 | 161 | } |
michael@0 | 162 | return frame.className + "." + frame.methodName + "()"; |
michael@0 | 163 | } |
michael@0 | 164 | return null; |
michael@0 | 165 | } |
michael@0 | 166 | |
michael@0 | 167 | @WrapElementForJNI(allowMultithread = true, stubName = "StartJavaProfiling") |
michael@0 | 168 | public static void start(int aInterval, int aSamples) { |
michael@0 | 169 | synchronized (GeckoJavaSampler.class) { |
michael@0 | 170 | if (sSamplingRunnable != null) { |
michael@0 | 171 | return; |
michael@0 | 172 | } |
michael@0 | 173 | sSamplingRunnable = new SamplingThread(aInterval, aSamples); |
michael@0 | 174 | sSamplingThread = new Thread(sSamplingRunnable, "Java Sampler"); |
michael@0 | 175 | sSamplingThread.start(); |
michael@0 | 176 | } |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | @WrapElementForJNI(allowMultithread = true, stubName = "PauseJavaProfiling") |
michael@0 | 180 | public static void pause() { |
michael@0 | 181 | synchronized (GeckoJavaSampler.class) { |
michael@0 | 182 | sSamplingRunnable.mPauseSampler = true; |
michael@0 | 183 | } |
michael@0 | 184 | } |
michael@0 | 185 | |
michael@0 | 186 | @WrapElementForJNI(allowMultithread = true, stubName = "UnpauseJavaProfiling") |
michael@0 | 187 | public static void unpause() { |
michael@0 | 188 | synchronized (GeckoJavaSampler.class) { |
michael@0 | 189 | sSamplingRunnable.mPauseSampler = false; |
michael@0 | 190 | } |
michael@0 | 191 | } |
michael@0 | 192 | |
michael@0 | 193 | @WrapElementForJNI(allowMultithread = true, stubName = "StopJavaProfiling") |
michael@0 | 194 | public static void stop() { |
michael@0 | 195 | synchronized (GeckoJavaSampler.class) { |
michael@0 | 196 | if (sSamplingThread == null) { |
michael@0 | 197 | return; |
michael@0 | 198 | } |
michael@0 | 199 | |
michael@0 | 200 | sSamplingRunnable.mStopSampler = true; |
michael@0 | 201 | try { |
michael@0 | 202 | sSamplingThread.join(); |
michael@0 | 203 | } catch (InterruptedException e) { |
michael@0 | 204 | e.printStackTrace(); |
michael@0 | 205 | } |
michael@0 | 206 | sSamplingThread = null; |
michael@0 | 207 | sSamplingRunnable = null; |
michael@0 | 208 | } |
michael@0 | 209 | } |
michael@0 | 210 | |
michael@0 | 211 | public static void setLibsLoaded() { |
michael@0 | 212 | sLibsLoaded = true; |
michael@0 | 213 | } |
michael@0 | 214 | } |
michael@0 | 215 | |
michael@0 | 216 | |
michael@0 | 217 |