зеркало из https://github.com/mozilla/gecko-dev.git
Bug 788022 - Add support for dalvik profiling. r=snorp,kats
--HG-- extra : rebase_source : 3eb56af40018a546586fd0fb33e343589ddcf207
This commit is contained in:
Родитель
230711127c
Коммит
c18ef0a706
|
@ -0,0 +1,184 @@
|
|||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import android.util.Log;
|
||||
import java.lang.Thread;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class GeckoJavaSampler {
|
||||
private static final String LOGTAG = "JavaSampler";
|
||||
private static Thread sSamplingThread = null;
|
||||
private static SamplingThread sSamplingRunnable = null;
|
||||
private static Thread sMainThread = null;
|
||||
|
||||
// Use the same timer primitive as the profiler
|
||||
// to get a perfect sample syncing.
|
||||
private static native double getProfilerTime();
|
||||
|
||||
private static class Sample {
|
||||
public Frame[] mFrames;
|
||||
public double mTime;
|
||||
public Sample(StackTraceElement[] aStack) {
|
||||
mFrames = new Frame[aStack.length];
|
||||
mTime = getProfilerTime();
|
||||
for (int i = 0; i < aStack.length; i++) {
|
||||
mFrames[aStack.length - 1 - i] = new Frame();
|
||||
mFrames[aStack.length - 1 - i].fileName = aStack[i].getFileName();
|
||||
mFrames[aStack.length - 1 - i].lineNo = aStack[i].getLineNumber();
|
||||
mFrames[aStack.length - 1 - i].methodName = aStack[i].getMethodName();
|
||||
mFrames[aStack.length - 1 - i].className = aStack[i].getClassName();
|
||||
}
|
||||
}
|
||||
}
|
||||
private static class Frame {
|
||||
public String fileName;
|
||||
public int lineNo;
|
||||
public String methodName;
|
||||
public String className;
|
||||
}
|
||||
|
||||
private static class SamplingThread implements Runnable {
|
||||
private final int mInterval;
|
||||
private final int mSampleCount;
|
||||
|
||||
private boolean mPauseSampler = false;
|
||||
private boolean mStopSampler = false;
|
||||
|
||||
private Map<Integer,Sample[]> mSamples = new HashMap<Integer,Sample[]>();
|
||||
private int mSamplePos;
|
||||
|
||||
public SamplingThread(final int aInterval, final int aSampleCount) {
|
||||
// If we sample faster then 10ms we get to many missed samples
|
||||
mInterval = Math.max(10, aInterval);
|
||||
mSampleCount = aSampleCount;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
synchronized (GeckoJavaSampler.class) {
|
||||
mSamples.put(0, new Sample[mSampleCount]);
|
||||
mSamplePos = 0;
|
||||
|
||||
// Find the main thread
|
||||
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
|
||||
for (Thread t : threadSet) {
|
||||
if (t.getName().compareToIgnoreCase("main") == 0) {
|
||||
sMainThread = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sMainThread == null) {
|
||||
Log.e(LOGTAG, "Main thread not found");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(mInterval);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
synchronized (GeckoJavaSampler.class) {
|
||||
if (!mPauseSampler) {
|
||||
StackTraceElement[] bt = sMainThread.getStackTrace();
|
||||
mSamples.get(0)[mSamplePos] = new Sample(bt);
|
||||
mSamplePos = (mSamplePos+1) % mSamples.get(0).length;
|
||||
}
|
||||
if (mStopSampler) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Sample getSample(int aThreadId, int aSampleId) {
|
||||
if (aThreadId < mSamples.size() && aSampleId < mSamples.get(aThreadId).length &&
|
||||
mSamples.get(aThreadId)[aSampleId] != null) {
|
||||
int startPos = 0;
|
||||
if (mSamples.get(aThreadId)[mSamplePos] != null) {
|
||||
startPos = mSamplePos;
|
||||
}
|
||||
int readPos = (startPos + aSampleId) % mSamples.get(aThreadId).length;
|
||||
return mSamples.get(aThreadId)[readPos];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static String getThreadName(int aThreadId) {
|
||||
if (aThreadId == 0 && sMainThread != null) {
|
||||
return sMainThread.getName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private synchronized static Sample getSample(int aThreadId, int aSampleId) {
|
||||
return sSamplingRunnable.getSample(aThreadId, aSampleId);
|
||||
}
|
||||
public synchronized static double getSampleTime(int aThreadId, int aSampleId) {
|
||||
Sample sample = getSample(aThreadId, aSampleId);
|
||||
if (sample != null) {
|
||||
System.out.println("Sample: " + sample.mTime);
|
||||
return sample.mTime;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
public synchronized static String getFrameName(int aThreadId, int aSampleId, int aFrameId) {
|
||||
Sample sample = getSample(aThreadId, aSampleId);
|
||||
if (sample != null && aFrameId < sample.mFrames.length) {
|
||||
Frame frame = sample.mFrames[aFrameId];
|
||||
if (frame == null) {
|
||||
return null;
|
||||
}
|
||||
return frame.className + "." + frame.methodName + "()";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void start(int aInterval, int aSamples) {
|
||||
synchronized (GeckoJavaSampler.class) {
|
||||
sSamplingRunnable = new SamplingThread(aInterval, aSamples);
|
||||
sSamplingThread = new Thread(sSamplingRunnable, "Java Sampler");
|
||||
sSamplingThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
public static void pause() {
|
||||
synchronized (GeckoJavaSampler.class) {
|
||||
sSamplingRunnable.mPauseSampler = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void unpause() {
|
||||
synchronized (GeckoJavaSampler.class) {
|
||||
sSamplingRunnable.mPauseSampler = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void stop() {
|
||||
synchronized (GeckoJavaSampler.class) {
|
||||
if (sSamplingThread == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
sSamplingRunnable.mStopSampler = true;
|
||||
try {
|
||||
sSamplingThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
sSamplingThread = null;
|
||||
sSamplingRunnable = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -107,6 +107,7 @@ FENNEC_JAVA_FILES = \
|
|||
GeckoPopupMenu.java \
|
||||
GeckoSmsManager.java \
|
||||
GeckoThread.java \
|
||||
GeckoJavaSampler.java \
|
||||
GlobalHistory.java \
|
||||
GeckoViewsFactory.java \
|
||||
HeightChangeAnimation.java \
|
||||
|
@ -1152,6 +1153,7 @@ jars:
|
|||
|
||||
CLASSES_WITH_JNI= \
|
||||
org.mozilla.gecko.GeckoAppShell \
|
||||
org.mozilla.gecko.GeckoJavaSampler \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_WEBSMS_BACKEND
|
||||
|
|
|
@ -69,7 +69,7 @@ class Generator:
|
|||
returnValue = ''
|
||||
elif returnType == 'jobject':
|
||||
returnValue = 'NULL'
|
||||
elif returnType in ('jint', 'jfloat'):
|
||||
elif returnType in ('jint', 'jfloat', 'jdouble'):
|
||||
returnValue = '0'
|
||||
else:
|
||||
raise Exception(('Unsupported JNI return type %s found; '
|
||||
|
|
|
@ -379,3 +379,22 @@ Java_org_mozilla_gecko_GeckoAppShell_notifyFilePickerResult(JNIEnv * arg0, jclas
|
|||
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_notifyFilePickerResult", &f_Java_org_mozilla_gecko_GeckoAppShell_notifyFilePickerResult);
|
||||
#endif
|
||||
|
||||
#ifdef JNI_STUBS
|
||||
|
||||
typedef jdouble (*Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime_t)(JNIEnv *, jclass);
|
||||
static Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime_t f_Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime;
|
||||
extern "C" NS_EXPORT jdouble JNICALL
|
||||
Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime(JNIEnv * arg0, jclass arg1) {
|
||||
if (!f_Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime) {
|
||||
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
|
||||
"JNI Function called before it was loaded");
|
||||
return 0;
|
||||
}
|
||||
return f_Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime(arg0, arg1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef JNI_BINDINGS
|
||||
xul_dlsym("Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime", &f_Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -245,7 +245,7 @@ void TableTicker::UnwinderTick(TickSample* sample)
|
|||
}
|
||||
|
||||
if (sample) {
|
||||
TimeDuration delta = sample->timestamp - mStartTime;
|
||||
TimeDuration delta = sample->timestamp - sStartTime;
|
||||
utb__addEntry( utb, ProfileEntry('t', delta.ToMilliseconds()) );
|
||||
}
|
||||
|
||||
|
|
|
@ -142,6 +142,8 @@ static inline void profiler_unregister_thread() {}
|
|||
// profiling on auxilerary threads.
|
||||
static inline void profiler_js_operation_callback() {}
|
||||
|
||||
static inline double profiler_time() { return 0; }
|
||||
|
||||
#else
|
||||
|
||||
#include "GeckoProfilerImpl.h"
|
||||
|
|
|
@ -61,6 +61,8 @@ void mozilla_sampler_unlock();
|
|||
bool mozilla_sampler_register_thread(const char* name);
|
||||
void mozilla_sampler_unregister_thread();
|
||||
|
||||
double mozilla_sampler_time();
|
||||
|
||||
/* Returns true if env var SPS_NEW is set to anything, else false. */
|
||||
extern bool sps_version2();
|
||||
|
||||
|
|
|
@ -163,6 +163,12 @@ void profiler_js_operation_callback()
|
|||
stack->jsOperationCallback();
|
||||
}
|
||||
|
||||
static inline
|
||||
double profiler_time()
|
||||
{
|
||||
return mozilla_sampler_time();
|
||||
}
|
||||
|
||||
// we want the class and function name but can't easily get that using preprocessor macros
|
||||
// __func__ doesn't have the class name and __PRETTY_FUNCTION__ has the parameters
|
||||
|
||||
|
|
|
@ -34,6 +34,10 @@
|
|||
#include "mozilla/Services.h"
|
||||
#include "PlatformMacros.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
#include "AndroidBridge.h"
|
||||
#endif
|
||||
|
||||
// JS
|
||||
#include "jsdbgapi.h"
|
||||
|
||||
|
@ -160,6 +164,54 @@ JSObject* TableTicker::ToJSObject(JSContext *aCx)
|
|||
return jsProfile;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
static
|
||||
JSCustomObject* BuildJavaThreadJSObject(JSAObjectBuilder& b)
|
||||
{
|
||||
JSCustomObject* javaThread = b.CreateObject();
|
||||
b.DefineProperty(javaThread, "name", "Java Main Thread");
|
||||
|
||||
JSCustomArray *samples = b.CreateArray();
|
||||
b.DefineProperty(javaThread, "samples", samples);
|
||||
|
||||
int sampleId = 0;
|
||||
while (true) {
|
||||
int frameId = 0;
|
||||
JSCustomObject *sample = nullptr;
|
||||
JSCustomArray *frames = nullptr;
|
||||
while (true) {
|
||||
nsCString result;
|
||||
bool hasFrame = AndroidBridge::Bridge()->GetFrameNameJavaProfiling(0, sampleId, frameId, result);
|
||||
if (!hasFrame) {
|
||||
if (frames) {
|
||||
b.DefineProperty(sample, "frames", frames);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!sample) {
|
||||
sample = b.CreateObject();
|
||||
frames = b.CreateArray();
|
||||
b.DefineProperty(sample, "frames", frames);
|
||||
b.ArrayPush(samples, sample);
|
||||
|
||||
double sampleTime = AndroidBridge::Bridge()->GetSampleTimeJavaProfiling(0, sampleId);
|
||||
b.DefineProperty(sample, "time", sampleTime);
|
||||
}
|
||||
JSCustomObject *frame = b.CreateObject();
|
||||
b.DefineProperty(frame, "location", result.BeginReading());
|
||||
b.ArrayPush(frames, frame);
|
||||
frameId++;
|
||||
}
|
||||
if (frameId == 0) {
|
||||
break;
|
||||
}
|
||||
sampleId++;
|
||||
}
|
||||
|
||||
return javaThread;
|
||||
}
|
||||
#endif
|
||||
|
||||
void TableTicker::BuildJSObject(JSAObjectBuilder& b, JSCustomObject* profile)
|
||||
{
|
||||
// Put shared library info
|
||||
|
@ -191,8 +243,19 @@ void TableTicker::BuildJSObject(JSAObjectBuilder& b, JSCustomObject* profile)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
if (ProfileJava()) {
|
||||
AndroidBridge::Bridge()->PauseJavaProfiling();
|
||||
|
||||
JSCustomObject* javaThread = BuildJavaThreadJSObject(b);
|
||||
b.ArrayPush(threads, javaThread);
|
||||
|
||||
AndroidBridge::Bridge()->UnpauseJavaProfiling();
|
||||
}
|
||||
#endif
|
||||
|
||||
SetPaused(false);
|
||||
}
|
||||
}
|
||||
|
||||
// END SaveProfileTask et al
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
@ -452,7 +515,7 @@ void TableTicker::InplaceTick(TickSample* sample)
|
|||
}
|
||||
|
||||
if (sample) {
|
||||
TimeDuration delta = sample->timestamp - mStartTime;
|
||||
TimeDuration delta = sample->timestamp - sStartTime;
|
||||
currThreadProfile.addTag(ProfileEntry('t', delta.ToMilliseconds()));
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ class TableTicker: public Sampler {
|
|||
const char** aFeatures, uint32_t aFeatureCount)
|
||||
: Sampler(aInterval, true, aEntrySize)
|
||||
, mPrimaryThreadProfile(nullptr)
|
||||
, mStartTime(TimeStamp::Now())
|
||||
, mSaveRequested(false)
|
||||
, mUnwinderThread(false)
|
||||
{
|
||||
|
@ -39,10 +38,13 @@ class TableTicker: public Sampler {
|
|||
//XXX: It's probably worth splitting the jank profiler out from the regular profiler at some point
|
||||
mJankOnly = hasFeature(aFeatures, aFeatureCount, "jank");
|
||||
mProfileJS = hasFeature(aFeatures, aFeatureCount, "js");
|
||||
mProfileThreads = true || hasFeature(aFeatures, aFeatureCount, "threads");
|
||||
mProfileJava = hasFeature(aFeatures, aFeatureCount, "java");
|
||||
mProfileThreads = hasFeature(aFeatures, aFeatureCount, "threads");
|
||||
mUnwinderThread = hasFeature(aFeatures, aFeatureCount, "unwinder") || sps_version2();
|
||||
mAddLeafAddresses = hasFeature(aFeatures, aFeatureCount, "leaf");
|
||||
|
||||
sStartTime = TimeStamp::Now();
|
||||
|
||||
{
|
||||
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
|
||||
|
@ -123,6 +125,7 @@ class TableTicker: public Sampler {
|
|||
|
||||
bool HasUnwinderThread() const { return mUnwinderThread; }
|
||||
bool ProfileJS() const { return mProfileJS; }
|
||||
bool ProfileJava() const { return mProfileJava; }
|
||||
bool ProfileThreads() const { return mProfileThreads; }
|
||||
|
||||
protected:
|
||||
|
@ -139,7 +142,6 @@ protected:
|
|||
|
||||
// This represent the application's main thread (SAMPLER_INIT)
|
||||
ThreadProfile* mPrimaryThreadProfile;
|
||||
TimeStamp mStartTime;
|
||||
bool mSaveRequested;
|
||||
bool mAddLeafAddresses;
|
||||
bool mUseStackWalk;
|
||||
|
@ -147,5 +149,6 @@ protected:
|
|||
bool mProfileJS;
|
||||
bool mProfileThreads;
|
||||
bool mUnwinderThread;
|
||||
bool mProfileJava;
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
#include "mozilla/Services.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
#include "AndroidBridge.h"
|
||||
#endif
|
||||
|
||||
mozilla::ThreadLocal<PseudoStack *> tlsPseudoStack;
|
||||
mozilla::ThreadLocal<TableTicker *> tlsTicker;
|
||||
// We need to track whether we've been initialized otherwise
|
||||
|
@ -29,6 +33,7 @@ mozilla::ThreadLocal<TableTicker *> tlsTicker;
|
|||
bool stack_key_initialized;
|
||||
|
||||
TimeStamp sLastTracerEvent; // is raced on
|
||||
TimeStamp sStartTime;
|
||||
int sFrameNumber = 0;
|
||||
int sLastFrameNumber = 0;
|
||||
int sInitCount = 0; // Each init must have a matched shutdown.
|
||||
|
@ -383,6 +388,7 @@ const char** mozilla_sampler_get_features()
|
|||
// Use a seperate thread of walking the stack.
|
||||
"unwinder",
|
||||
#endif
|
||||
"java",
|
||||
// Only record samples during periods of bad responsiveness
|
||||
"jank",
|
||||
// Tell the JS engine to emmit pseudostack entries in the
|
||||
|
@ -445,6 +451,17 @@ void mozilla_sampler_start(int aProfileEntries, int aInterval,
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
if (t->ProfileJava()) {
|
||||
int javaInterval = aInterval;
|
||||
// Java sampling doesn't accuratly keep up with 1ms sampling
|
||||
if (javaInterval < 10) {
|
||||
aInterval = 10;
|
||||
}
|
||||
mozilla::AndroidBridge::Bridge()->StartJavaProfiling(javaInterval, 1000);
|
||||
}
|
||||
#endif
|
||||
|
||||
sIsProfiling = true;
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
|
@ -560,6 +577,12 @@ void mozilla_sampler_unregister_thread()
|
|||
Sampler::UnregisterCurrentThread();
|
||||
}
|
||||
|
||||
double mozilla_sampler_time()
|
||||
{
|
||||
TimeDuration delta = TimeStamp::Now() - sStartTime;
|
||||
return delta.ToMilliseconds();
|
||||
}
|
||||
|
||||
// END externally visible functions
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
@ -80,6 +80,8 @@
|
|||
#define ENABLE_SPS_LEAF_DATA
|
||||
#endif
|
||||
|
||||
extern mozilla::TimeStamp sStartTime;
|
||||
|
||||
typedef uint8_t* Address;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -176,6 +176,15 @@ AndroidBridge::Init(JNIEnv *jEnv,
|
|||
jLockScreenOrientation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "lockScreenOrientation", "(I)V");
|
||||
jUnlockScreenOrientation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "unlockScreenOrientation", "()V");
|
||||
|
||||
jGeckoJavaSamplerClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("org/mozilla/gecko/GeckoJavaSampler"));
|
||||
jStart = jEnv->GetStaticMethodID(jGeckoJavaSamplerClass, "start", "(II)V");
|
||||
jStop = jEnv->GetStaticMethodID(jGeckoJavaSamplerClass, "stop", "()V");
|
||||
jPause = jEnv->GetStaticMethodID(jGeckoJavaSamplerClass, "pause", "()V");
|
||||
jUnpause = jEnv->GetStaticMethodID(jGeckoJavaSamplerClass, "unpause", "()V");
|
||||
jGetThreadName = jEnv->GetStaticMethodID(jGeckoJavaSamplerClass, "getThreadName", "(I)Ljava/lang/String;");
|
||||
jGetFrameName = jEnv->GetStaticMethodID(jGeckoJavaSamplerClass, "getFrameName", "(III)Ljava/lang/String;");
|
||||
jGetSampleTime = jEnv->GetStaticMethodID(jGeckoJavaSamplerClass, "getSampleTime", "(II)D");
|
||||
|
||||
jThumbnailHelperClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("org/mozilla/gecko/ThumbnailHelper"));
|
||||
jNotifyThumbnail = jEnv->GetStaticMethodID(jThumbnailHelperClass, "notifyThumbnail", "(Ljava/nio/ByteBuffer;IZ)V");
|
||||
|
||||
|
@ -2413,6 +2422,120 @@ __attribute__ ((visibility("default")))
|
|||
jobject JNICALL
|
||||
Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(JNIEnv *env, jclass, jlong size);
|
||||
|
||||
void
|
||||
AndroidBridge::StartJavaProfiling(int aInterval, int aSamples)
|
||||
{
|
||||
JNIEnv* env = GetJNIForThread();
|
||||
if (!env)
|
||||
return;
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env);
|
||||
|
||||
env->CallStaticVoidMethod(AndroidBridge::Bridge()->jGeckoJavaSamplerClass,
|
||||
AndroidBridge::Bridge()->jStart,
|
||||
aInterval, aSamples);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::StopJavaProfiling()
|
||||
{
|
||||
JNIEnv* env = GetJNIForThread();
|
||||
if (!env)
|
||||
return;
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env);
|
||||
|
||||
env->CallStaticVoidMethod(AndroidBridge::Bridge()->jGeckoJavaSamplerClass,
|
||||
AndroidBridge::Bridge()->jStop);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::PauseJavaProfiling()
|
||||
{
|
||||
JNIEnv* env = GetJNIForThread();
|
||||
if (!env)
|
||||
return;
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env);
|
||||
|
||||
env->CallStaticVoidMethod(AndroidBridge::Bridge()->jGeckoJavaSamplerClass,
|
||||
AndroidBridge::Bridge()->jPause);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::UnpauseJavaProfiling()
|
||||
{
|
||||
JNIEnv* env = GetJNIForThread();
|
||||
if (!env)
|
||||
return;
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env);
|
||||
|
||||
env->CallStaticVoidMethod(AndroidBridge::Bridge()->jGeckoJavaSamplerClass,
|
||||
AndroidBridge::Bridge()->jUnpause);
|
||||
}
|
||||
|
||||
bool
|
||||
AndroidBridge::GetThreadNameJavaProfiling(uint32_t aThreadId, nsCString & aResult)
|
||||
{
|
||||
JNIEnv* env = GetJNIForThread();
|
||||
if (!env)
|
||||
return false;
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env);
|
||||
|
||||
jstring jstrThreadName = static_cast<jstring>(
|
||||
env->CallStaticObjectMethod(AndroidBridge::Bridge()->jGeckoJavaSamplerClass,
|
||||
AndroidBridge::Bridge()->jGetThreadName,
|
||||
aThreadId));
|
||||
|
||||
if (!jstrThreadName)
|
||||
return false;
|
||||
|
||||
nsJNIString jniStr(jstrThreadName, env);
|
||||
CopyUTF16toUTF8(jniStr.get(), aResult);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
AndroidBridge::GetFrameNameJavaProfiling(uint32_t aThreadId, uint32_t aSampleId,
|
||||
uint32_t aFrameId, nsCString & aResult)
|
||||
{
|
||||
JNIEnv* env = GetJNIForThread();
|
||||
if (!env)
|
||||
return false;
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env);
|
||||
|
||||
jstring jstrSampleName = static_cast<jstring>(
|
||||
env->CallStaticObjectMethod(AndroidBridge::Bridge()->jGeckoJavaSamplerClass,
|
||||
AndroidBridge::Bridge()->jGetFrameName,
|
||||
aThreadId, aSampleId, aFrameId));
|
||||
|
||||
if (!jstrSampleName)
|
||||
return false;
|
||||
|
||||
nsJNIString jniStr(jstrSampleName, env);
|
||||
CopyUTF16toUTF8(jniStr.get(), aResult);
|
||||
return true;
|
||||
}
|
||||
|
||||
double
|
||||
AndroidBridge::GetSampleTimeJavaProfiling(uint32_t aThreadId, uint32_t aSampleId)
|
||||
{
|
||||
JNIEnv* env = GetJNIForThread();
|
||||
if (!env)
|
||||
return 0;
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env);
|
||||
|
||||
jdouble jSampleTime =
|
||||
env->CallStaticDoubleMethod(AndroidBridge::Bridge()->jGeckoJavaSamplerClass,
|
||||
AndroidBridge::Bridge()->jGetSampleTime,
|
||||
aThreadId, aSampleId);
|
||||
|
||||
return jSampleTime;
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::SendThumbnail(jobject buffer, int32_t tabId, bool success) {
|
||||
|
|
|
@ -152,6 +152,14 @@ public:
|
|||
|
||||
static void NotifyIMEChange(const PRUnichar *aText, uint32_t aTextLen, int aStart, int aEnd, int aNewEnd);
|
||||
|
||||
void StartJavaProfiling(int aInterval, int aSamples);
|
||||
void StopJavaProfiling();
|
||||
void PauseJavaProfiling();
|
||||
void UnpauseJavaProfiling();
|
||||
bool GetThreadNameJavaProfiling(uint32_t aThreadId, nsCString & aResult);
|
||||
bool GetFrameNameJavaProfiling(uint32_t aThreadId, uint32_t aSampleId, uint32_t aFrameId, nsCString & aResult);
|
||||
double GetSampleTimeJavaProfiling(uint32_t aThreadId, uint32_t aSampleId);
|
||||
|
||||
nsresult CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, jobject buffer);
|
||||
void SendThumbnail(jobject buffer, int32_t tabId, bool success);
|
||||
nsresult GetDisplayPort(bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort);
|
||||
|
@ -360,6 +368,15 @@ public:
|
|||
void RegisterSurfaceTextureFrameListener(jobject surfaceTexture, int id);
|
||||
void UnregisterSurfaceTextureFrameListener(jobject surfaceTexture);
|
||||
|
||||
jclass jGeckoJavaSamplerClass;
|
||||
jmethodID jStart;
|
||||
jmethodID jStop;
|
||||
jmethodID jPause;
|
||||
jmethodID jUnpause;
|
||||
jmethodID jGetThreadName;
|
||||
jmethodID jGetFrameName;
|
||||
jmethodID jGetSampleTime;
|
||||
|
||||
void GetGfxInfoData(nsACString& aRet);
|
||||
nsresult GetProxyForURI(const nsACString & aSpec,
|
||||
const nsACString & aScheme,
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "nsIMobileMessageDatabaseService.h"
|
||||
#include "nsPluginInstanceOwner.h"
|
||||
#include "nsSurfaceTexture.h"
|
||||
#include "GeckoProfiler.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -876,4 +877,10 @@ Java_org_mozilla_gecko_GeckoAppShell_onSurfaceTextureFrameAvailable(JNIEnv* jenv
|
|||
st->NotifyFrameAvailable();
|
||||
}
|
||||
|
||||
NS_EXPORT jdouble JNICALL
|
||||
Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime(JNIEnv *jenv, jclass jc)
|
||||
{
|
||||
return profiler_time();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче