mobile/android/base/GeckoJavaSampler.java

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

mercurial