Skip to content

Commit d81045c

Browse files
author
Mihail Slavchev
committed
add support to configure V8 profiler output directory
1 parent 6ff56eb commit d81045c

6 files changed

Lines changed: 116 additions & 67 deletions

File tree

src/jni/Profiler.cpp

Lines changed: 80 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,26 @@ Profiler::Profiler()
1414
{
1515
}
1616

17-
void Profiler::Init(const string& appName)
17+
void Profiler::Init(Isolate *isolate, const Local<Object>& globalObj, const string& appName, const string& outputDir)
1818
{
19-
s_appName = appName;
19+
m_appName = appName;
20+
m_outputDir = outputDir;
21+
auto extData = External::New(isolate, this);
22+
globalObj->Set(ConvertToV8String("__startCPUProfiler"), FunctionTemplate::New(isolate, Profiler::StartCPUProfilerCallback, extData)->GetFunction());
23+
globalObj->Set(ConvertToV8String("__stopCPUProfiler"), FunctionTemplate::New(isolate, Profiler::StopCPUProfilerCallback, extData)->GetFunction());
24+
globalObj->Set(ConvertToV8String("__heapSnapshot"), FunctionTemplate::New(isolate, Profiler::HeapSnapshotMethodCallback, extData)->GetFunction());
25+
globalObj->Set(ConvertToV8String("__startNDKProfiler"), FunctionTemplate::New(isolate, Profiler::StartNDKProfilerCallback, extData)->GetFunction());
26+
globalObj->Set(ConvertToV8String("__stopNDKProfiler"), FunctionTemplate::New(isolate, Profiler::StopNDKProfilerCallback, extData)->GetFunction());
2027
}
2128

2229
void Profiler::StartCPUProfilerCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
2330
{
2431
try
2532
{
2633
auto isolate = args.GetIsolate();
27-
auto started = false;
28-
if ((args.Length() == 1) && (args[0]->IsString()))
29-
{
30-
auto name = args[0]->ToString();
31-
StartCPUProfiler(isolate, name);
32-
started = true;
33-
}
34-
35-
args.GetReturnValue().Set(Boolean::New(isolate, started));
36-
34+
auto extData = args.Data().As<External>();
35+
auto thiz = static_cast<Profiler*>(extData->Value());
36+
thiz->StartCPUProfilerCallbackImpl(args);
3737
}
3838
catch (NativeScriptException& e)
3939
{
@@ -51,18 +51,27 @@ void Profiler::StartCPUProfilerCallback(const v8::FunctionCallbackInfo<v8::Value
5151
}
5252
}
5353

54+
void Profiler::StartCPUProfilerCallbackImpl(const v8::FunctionCallbackInfo<v8::Value>& args)
55+
{
56+
auto isolate = args.GetIsolate();
57+
auto started = false;
58+
if ((args.Length() == 1) && (args[0]->IsString()))
59+
{
60+
auto name = args[0]->ToString();
61+
StartCPUProfiler(isolate, name);
62+
started = true;
63+
}
64+
args.GetReturnValue().Set(started);
65+
}
66+
5467
void Profiler::StopCPUProfilerCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
5568
{
5669
try
5770
{
5871
auto isolate = args.GetIsolate();
59-
auto stopped = false;
60-
if ((args.Length() == 1) && (args[0]->IsString()))
61-
{
62-
auto name = args[0]->ToString();
63-
stopped = StopCPUProfiler(isolate, name);
64-
}
65-
args.GetReturnValue().Set(Boolean::New(isolate, stopped));
72+
auto extData = args.Data().As<External>();
73+
auto thiz = static_cast<Profiler*>(extData->Value());
74+
thiz->StopCPUProfilerCallbackImpl(args);
6675
}
6776
catch (NativeScriptException& e)
6877
{
@@ -80,6 +89,18 @@ void Profiler::StopCPUProfilerCallback(const v8::FunctionCallbackInfo<v8::Value>
8089
}
8190
}
8291

92+
void Profiler::StopCPUProfilerCallbackImpl(const v8::FunctionCallbackInfo<v8::Value>& args)
93+
{
94+
auto isolate = args.GetIsolate();
95+
auto stopped = false;
96+
if ((args.Length() == 1) && (args[0]->IsString()))
97+
{
98+
auto name = args[0]->ToString();
99+
stopped = StopCPUProfiler(isolate, name);
100+
}
101+
args.GetReturnValue().Set(stopped);
102+
}
103+
83104
void Profiler::StartCPUProfiler(Isolate *isolate, const Local<String>& name)
84105
{
85106
auto v8prof = isolate->GetCpuProfiler();
@@ -113,7 +134,7 @@ bool Profiler::Write(CpuProfile *cpuProfile)
113134

114135
char filename[256];
115136
auto profileName = ConvertToString(cpuProfile->GetTitle());
116-
snprintf(filename, sizeof(filename), "/sdcard/%s-%s-%lu.%lu.cpuprofile", s_appName.c_str(), profileName.c_str(), sec, usec);
137+
snprintf(filename, sizeof(filename), "%s/%s-%s-%lu.%lu.cpuprofile", m_outputDir.c_str(), m_appName.c_str(), profileName.c_str(), sec, usec);
117138

118139
auto fp = fopen(filename, "w");
119140
if (nullptr == fp)
@@ -202,7 +223,10 @@ void Profiler::StartNDKProfilerCallback(const v8::FunctionCallbackInfo<v8::Value
202223
{
203224
try
204225
{
205-
StartNDKProfiler();
226+
auto isolate = args.GetIsolate();
227+
auto extData = args.Data().As<External>();
228+
auto thiz = static_cast<Profiler*>(extData->Value());
229+
thiz->StartNDKProfiler();
206230
}
207231
catch (NativeScriptException& e)
208232
{
@@ -224,7 +248,10 @@ void Profiler::StopNDKProfilerCallback(const v8::FunctionCallbackInfo<v8::Value>
224248
{
225249
try
226250
{
227-
StopNDKProfiler();
251+
auto isolate = args.GetIsolate();
252+
auto extData = args.Data().As<External>();
253+
auto thiz = static_cast<Profiler*>(extData->Value());
254+
thiz->StopNDKProfiler();
228255
}
229256
catch (NativeScriptException& e)
230257
{
@@ -292,30 +319,10 @@ void Profiler::HeapSnapshotMethodCallback(const v8::FunctionCallbackInfo<v8::Val
292319
{
293320
try
294321
{
295-
struct timespec nowt;
296-
clock_gettime(CLOCK_MONOTONIC, &nowt);
297-
uint64_t now = (int64_t) nowt.tv_sec * 1000000000LL + nowt.tv_nsec;
298-
299-
unsigned long sec = static_cast<unsigned long>(now / 1000000);
300-
unsigned long usec = static_cast<unsigned long>(now % 1000000);
301-
302-
char filename[256];
303-
snprintf(filename, sizeof(filename), "/sdcard/%s-heapdump-%lu.%lu.heapsnapshot", s_appName.c_str(), sec, usec);
304-
305-
FILE* fp = fopen(filename, "w");
306-
if (fp == nullptr)
307-
{
308-
return;
309-
}
310-
311322
auto isolate = args.GetIsolate();
312-
313-
const HeapSnapshot* snap = isolate->GetHeapProfiler()->TakeHeapSnapshot();
314-
315-
FileOutputStream stream(fp);
316-
snap->Serialize(&stream, HeapSnapshot::kJSON);
317-
fclose(fp);
318-
const_cast<HeapSnapshot*>(snap)->Delete();
323+
auto extData = args.Data().As<External>();
324+
auto thiz = static_cast<Profiler*>(extData->Value());
325+
thiz->HeapSnapshotMethodCallbackImpl(args);
319326
}
320327
catch (NativeScriptException& e)
321328
{
@@ -333,4 +340,31 @@ void Profiler::HeapSnapshotMethodCallback(const v8::FunctionCallbackInfo<v8::Val
333340
}
334341
}
335342

336-
string Profiler::s_appName;
343+
void Profiler::HeapSnapshotMethodCallbackImpl(const v8::FunctionCallbackInfo<v8::Value>& args)
344+
{
345+
struct timespec nowt;
346+
clock_gettime(CLOCK_MONOTONIC, &nowt);
347+
uint64_t now = (int64_t) nowt.tv_sec * 1000000000LL + nowt.tv_nsec;
348+
349+
unsigned long sec = static_cast<unsigned long>(now / 1000000);
350+
unsigned long usec = static_cast<unsigned long>(now % 1000000);
351+
352+
char filename[256];
353+
snprintf(filename, sizeof(filename), "%s/%s-heapdump-%lu.%lu.heapsnapshot", m_outputDir.c_str(), m_appName.c_str(), sec, usec);
354+
355+
FILE* fp = fopen(filename, "w");
356+
if (fp == nullptr)
357+
{
358+
return;
359+
}
360+
361+
auto isolate = args.GetIsolate();
362+
363+
const HeapSnapshot* snap = isolate->GetHeapProfiler()->TakeHeapSnapshot();
364+
365+
FileOutputStream stream(fp);
366+
snap->Serialize(&stream, HeapSnapshot::kJSON);
367+
fclose(fp);
368+
const_cast<HeapSnapshot*>(snap)->Delete();
369+
}
370+

src/jni/Profiler.h

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ namespace tns
1010
class Profiler
1111
{
1212
public:
13-
static void Init(const std::string& appName);
13+
Profiler();
14+
15+
void Init(v8::Isolate *isolate, const v8::Local<v8::Object>& globalObj, const std::string& appName, const std::string& outputDir);
1416

17+
private:
1518
static void StartCPUProfilerCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
1619

1720
static void StopCPUProfilerCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -22,20 +25,25 @@ namespace tns
2225

2326
static void HeapSnapshotMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
2427

25-
private:
26-
Profiler();
28+
void StartCPUProfilerCallbackImpl(const v8::FunctionCallbackInfo<v8::Value>& args);
29+
30+
void StopCPUProfilerCallbackImpl(const v8::FunctionCallbackInfo<v8::Value>& args);
31+
32+
void HeapSnapshotMethodCallbackImpl(const v8::FunctionCallbackInfo<v8::Value>& args);
33+
34+
void StartCPUProfiler(v8::Isolate *isolate, const v8::Local<v8::String>& name);
2735

28-
static void StartCPUProfiler(v8::Isolate *isolate, const v8::Local<v8::String>& name);
36+
bool StopCPUProfiler(v8::Isolate *isolate, const v8::Local<v8::String>& name);
2937

30-
static bool StopCPUProfiler(v8::Isolate *isolate, const v8::Local<v8::String>& name);
38+
void StartNDKProfiler();
3139

32-
static void StartNDKProfiler();
40+
void StopNDKProfiler();
3341

34-
static void StopNDKProfiler();
42+
bool Write(v8::CpuProfile *cpuProfile);
3543

36-
static bool Write(v8::CpuProfile *cpuProfile);
44+
std::string m_appName;
3745

38-
static std::string s_appName;
46+
std::string m_outputDir;
3947
};
4048
}
4149

src/jni/Runtime.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include "Version.h"
1414
#include "JEnv.h"
1515
#include "WeakRef.h"
16-
#include "Profiler.h"
1716
#include "NativeScriptAssert.h"
1817
#include "JsDebugger.h"
1918
#include "SimpleProfiler.h"
@@ -135,11 +134,12 @@ void Runtime::Init(jstring filesPath, bool verboseLoggingEnabled, jstring packag
135134
Constants::V8_HEAP_SNAPSHOT = (bool)snapshot;
136135
JniLocalRef snapshotScript(m_env.GetObjectArrayElement(args, 3));
137136
Constants::V8_HEAP_SNAPSHOT_SCRIPT = ArgConverter::jstringToString(snapshotScript);
137+
JniLocalRef profilerOutputDir(m_env.GetObjectArrayElement(args, 4));
138138

139139
DEBUG_WRITE("Initializing Telerik NativeScript");
140140

141141
NativeScriptException::Init(m_objectManager);
142-
m_isolate = PrepareV8Runtime(filesRoot, packageName, jsDebugger);
142+
m_isolate = PrepareV8Runtime(filesRoot, packageName, jsDebugger, profilerOutputDir);
143143

144144
s_isolate2RuntimesCache.insert(make_pair(m_isolate, this));
145145
}
@@ -335,7 +335,7 @@ void Runtime::PassUncaughtExceptionToJsNative(JNIEnv *env, jobject obj, jthrowab
335335
}
336336
}
337337

338-
Isolate* Runtime::PrepareV8Runtime(const string& filesPath, jstring packageName, jobject jsDebugger)
338+
Isolate* Runtime::PrepareV8Runtime(const string& filesPath, jstring packageName, jobject jsDebugger, jstring profilerOutputDir)
339339
{
340340
auto platform = v8::platform::CreateDefaultPlatform();
341341
V8::InitializePlatform(platform);
@@ -384,11 +384,6 @@ Isolate* Runtime::PrepareV8Runtime(const string& filesPath, jstring packageName,
384384

385385
const auto readOnlyFlags = static_cast<PropertyAttribute>(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
386386

387-
globalTemplate->Set(ConvertToV8String("__startNDKProfiler"), FunctionTemplate::New(isolate, Profiler::StartNDKProfilerCallback));
388-
globalTemplate->Set(ConvertToV8String("__stopNDKProfiler"), FunctionTemplate::New(isolate, Profiler::StopNDKProfilerCallback));
389-
globalTemplate->Set(ConvertToV8String("__startCPUProfiler"), FunctionTemplate::New(isolate, Profiler::StartCPUProfilerCallback));
390-
globalTemplate->Set(ConvertToV8String("__stopCPUProfiler"), FunctionTemplate::New(isolate, Profiler::StopCPUProfilerCallback));
391-
globalTemplate->Set(ConvertToV8String("__heapSnapshot"), FunctionTemplate::New(isolate, Profiler::HeapSnapshotMethodCallback));
392387
globalTemplate->Set(ConvertToV8String("__log"), FunctionTemplate::New(isolate, CallbackHandlers::LogMethodCallback));
393388
globalTemplate->Set(ConvertToV8String("__dumpReferenceTables"), FunctionTemplate::New(isolate, CallbackHandlers::DumpReferenceTablesMethodCallback));
394389
globalTemplate->Set(ConvertToV8String("__debugbreak"), FunctionTemplate::New(isolate, JsDebugger::DebugBreakCallback));
@@ -428,8 +423,9 @@ Isolate* Runtime::PrepareV8Runtime(const string& filesPath, jstring packageName,
428423

429424
CallbackHandlers::Init(isolate, m_objectManager);
430425

431-
string pckName = ArgConverter::jstringToString(packageName);
432-
Profiler::Init(pckName);
426+
auto pckName = ArgConverter::jstringToString(packageName);
427+
auto outputDir = ArgConverter::jstringToString(profilerOutputDir);
428+
m_profiler.Init(isolate, global, pckName, outputDir);
433429
JsDebugger::Init(isolate, pckName, jsDebugger);
434430

435431
MetadataNode::BuildMetadata(filesPath);

src/jni/Runtime.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "ObjectManager.h"
77
#include "SimpleAllocator.h"
88
#include "WeakRef.h"
9+
#include "Profiler.h"
910

1011
jobject ConvertJsValueToJavaObject(tns::JEnv& env, const v8::Local<v8::Value>& value, int classReturnType);
1112

@@ -51,8 +52,10 @@ namespace tns
5152

5253
WeakRef m_weakRef;
5354

55+
Profiler m_profiler;
56+
5457
static void PrepareExtendFunction(v8::Isolate *isolate, jstring filesPath);
55-
v8::Isolate* PrepareV8Runtime(const std::string& filesPath, jstring packageName, jobject jsDebugger);
58+
v8::Isolate* PrepareV8Runtime(const std::string& filesPath, jstring packageName, jobject jsDebugger, jstring profilerOutputDir);
5659
jobject ConvertJsValueToJavaObject(JEnv& env, const v8::Local<v8::Value>& value, int classReturnType);
5760

5861
static std::map<int, Runtime*> s_id2RuntimeCache;

src/src/com/tns/V8Config.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class V8Config
1010
private static final String CodeCacheKey = "codeCache";
1111
private static final String HeapSnapshotKey = "heapSnapshot";
1212
private static final String HeapSnapshotScriptKey = "heapSnapshotScript";
13+
private static final String ProfilerOutputDirKey = "profilerOutputDir";
1314

1415
public static Object[] fromPackageJSON(File appDir)
1516
{
@@ -44,6 +45,10 @@ public static Object[] fromPackageJSON(File appDir)
4445
String value = androidObject.getString(HeapSnapshotScriptKey);
4546
result[3] = FileSystem.resolveRelativePath(appDir.getPath(), value, appDir + "/app/");
4647
}
48+
if(androidObject.has(ProfilerOutputDirKey))
49+
{
50+
result[4] = androidObject.getString(ProfilerOutputDirKey);
51+
}
4752
}
4853
}
4954
catch (Exception e)
@@ -64,6 +69,8 @@ private static Object[] makeDefaultOptions()
6469
// enable v8 heap snapshot, false by default
6570
false,
6671
// arbitrary script to be included in the snapshot
72+
"",
73+
// V8 profiler output directory
6774
""
6875
};
6976

test-app/assets/app/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"main": "boot.js",
33
"android": {
4-
"v8Flags": "--expose_gc"
4+
"v8Flags": "--expose_gc",
5+
"profilerOutputDir": "/sdcard"
56
}
67
}

0 commit comments

Comments
 (0)