mobile/android/base/GeckoJavaSampler.java

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial