Skip to content

Commit e98367c

Browse files
authored
feat: performance api (#1838)
1 parent c9a2a86 commit e98367c

File tree

4 files changed

+54
-1
lines changed

4 files changed

+54
-1
lines changed

test-app/app/src/main/assets/app/mainpage.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,5 @@ require('./tests/testNativeTimers');
7171
require("./tests/testPostFrameCallback");
7272
require("./tests/console/logTests.js");
7373
require('./tests/testURLImpl.js');
74-
require('./tests/testURLSearchParamsImpl.js');
74+
require('./tests/testURLSearchParamsImpl.js');
75+
require('./tests/testPerformanceNow');
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
describe('performance.now()', () => {
2+
it('returns increasing high-resolution time', () => {
3+
const t1 = performance.now();
4+
const t2 = performance.now();
5+
expect(typeof t1).toBe('number');
6+
expect(isNaN(t1)).toBe(false);
7+
expect(t2).not.toBeLessThan(t1); // non-decreasing
8+
// Should be relative (well below 1h after startup)
9+
expect(t1).toBeLessThan(60 * 60 * 1000);
10+
});
11+
12+
it('advances over real time', (done) => {
13+
const t1 = performance.now();
14+
setTimeout(() => {
15+
const t2 = performance.now();
16+
// 8ms threshold accounts for timer clamping on some devices
17+
expect(t2 - t1).not.toBeLessThan(8);
18+
done();
19+
}, 10);
20+
});
21+
});

test-app/runtime/src/main/cpp/Runtime.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "URLImpl.h"
3535
#include "URLSearchParamsImpl.h"
3636
#include "URLPatternImpl.h"
37+
#include <chrono>
3738

3839
#ifdef APPLICATION_IN_DEBUG
3940
// #include "NetworkDomainCallbackHandlers.h"
@@ -487,6 +488,10 @@ Isolate* Runtime::PrepareV8Runtime(const string& filesPath, const string& native
487488

488489
tns::instrumentation::Frame isolateFrame;
489490
auto isolate = Isolate::New(create_params);
491+
// Capture start and realtime origin
492+
// MonotonicallyIncreasingTime returns seconds as double; store for performance.now()
493+
m_startTime = platform->MonotonicallyIncreasingTime();
494+
m_realtimeOrigin = platform->CurrentClockTimeMillis();
490495
isolateFrame.log("Isolate.New");
491496

492497
s_isolate2RuntimesCache[isolate] = this;
@@ -523,6 +528,15 @@ Isolate* Runtime::PrepareV8Runtime(const string& filesPath, const string& native
523528
globalTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__exit"), FunctionTemplate::New(isolate, CallbackHandlers::ExitMethodCallback));
524529
globalTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__runtimeVersion"), ArgConverter::ConvertToV8String(isolate, NATIVE_SCRIPT_RUNTIME_VERSION), readOnlyFlags);
525530
globalTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__time"), FunctionTemplate::New(isolate, CallbackHandlers::TimeCallback));
531+
532+
// performance object (performance.now() + timeOrigin)
533+
{
534+
auto performanceTemplate = ObjectTemplate::New(isolate);
535+
auto nowFunc = FunctionTemplate::New(isolate, Runtime::PerformanceNowCallback);
536+
performanceTemplate->Set(ArgConverter::ConvertToV8String(isolate, "now"), nowFunc);
537+
performanceTemplate->Set(ArgConverter::ConvertToV8String(isolate, "timeOrigin"), Number::New(isolate, m_realtimeOrigin));
538+
globalTemplate->Set(ArgConverter::ConvertToV8String(isolate, "performance"), performanceTemplate);
539+
}
526540
globalTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__releaseNativeCounterpart"), FunctionTemplate::New(isolate, CallbackHandlers::ReleaseNativeCounterpartCallback));
527541
globalTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__markingMode"), Number::New(isolate, m_objectManager->GetMarkingMode()), readOnlyFlags);
528542
globalTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__runOnMainThread"), FunctionTemplate::New(isolate, CallbackHandlers::RunOnMainThreadCallback));
@@ -741,6 +755,14 @@ void Runtime::SetManualInstrumentationMode(jstring mode) {
741755
}
742756
}
743757

758+
void Runtime::PerformanceNowCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
759+
auto isolate = args.GetIsolate();
760+
auto runtime = Runtime::GetRuntime(isolate);
761+
// Difference in seconds * 1000 for ms
762+
double ms = (platform->MonotonicallyIncreasingTime() - runtime->m_startTime) * 1000.0;
763+
args.GetReturnValue().Set(ms);
764+
}
765+
744766
void Runtime::DestroyRuntime() {
745767
s_id2RuntimeCache.erase(m_id);
746768
s_isolate2RuntimesCache.erase(m_isolate);

test-app/runtime/src/main/cpp/Runtime.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,15 @@ class Runtime {
108108

109109
bool m_isMainThread;
110110

111+
// High resolution timing origin values
112+
// m_startTime: monotonic clock time captured at isolate creation
113+
// m_realtimeOrigin: wall-clock time origin (milliseconds) captured at isolate creation
114+
double m_startTime {0};
115+
double m_realtimeOrigin {0};
116+
117+
// performance.now() callback
118+
static void PerformanceNowCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
119+
111120
v8::Isolate* PrepareV8Runtime(const std::string& filesPath, const std::string& nativeLibsDir, const std::string& packageName, bool isDebuggable, const std::string& callingDir, const std::string& profilerOutputDir, const int maxLogcatObjectSize, const bool forceLog);
112121
jobject ConvertJsValueToJavaObject(JEnv& env, const v8::Local<v8::Value>& value, int classReturnType);
113122
static int GetAndroidVersion();

0 commit comments

Comments
 (0)