diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc index a61038398dde4a2caf40b949197f3c2fbf4108b5..1a82ef5eed3f0fe59365580f0f17d406ff8f8609 100644 --- a/src/js_native_api_v8.cc +++ b/src/js_native_api_v8.cc @@ -16,6 +16,7 @@ #include "js_native_api_v8.h" #include "js_native_api_v8_inspector.h" #include "libplatform/libplatform.h" +#include "libplatform/v8-tracing.h" #include "util-inl.h" #include "util.h" #include "sourcemap.def" @@ -24,6 +25,10 @@ #include "hisysevent.h" #endif +#ifdef V8_USE_PERFETTO +#error Unsupported Perfetto. +#endif // V8_USE_PERFETTO + #define SECARGCNT 2 #define CHECK_MAYBE_NOTHING(env, maybe, status) \ @@ -239,6 +244,23 @@ static v8::ArrayBuffer::Allocator *GetOrCreateDefaultArrayBufferAllocator() { return defaultArrayBufferAllocator.get(); } +static std::unique_ptr g_trace_stream; + +constexpr uint32_t g_trace_catrgory_count = 7; +static constexpr const char* g_internal_trace_categories[] = { + "v8", + TRACE_DISABLED_BY_DEFAULT("v8.compile"), + "v8.execute", + TRACE_DISABLED_BY_DEFAULT("v8.runtime"), + TRACE_DISABLED_BY_DEFAULT("v8.stack_trace"), + "v8.wasm", + TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"), +}; + +constexpr uint32_t g_default_catrgory_count = 4; +static constexpr JSVM_TraceCategory g_default_categories[] = { + JSVM_TRACE_VM, JSVM_TRACE_EXECUTE, JSVM_TRACE_COMPILE, JSVM_TRACE_RUNTIME }; + static void SetFileToSourceMapMapping(std::string &&file, std::string &&sourceMapUrl) { auto it = sourceMapUrlMap.find(file); if (it == sourceMapUrlMap.end()) { @@ -2323,6 +2345,86 @@ OH_JSVM_DefineClass(JSVM_Env env, return GET_RETURN_STATUS(env); } +JSVM_EXTERN JSVM_Status OH_JSVM_TraceStart(size_t count, + const JSVM_TraceCategory* categories, + const char* tag, + size_t eventsCount) { + if (count > v8impl::g_trace_catrgory_count || + ((count != 0) != (categories != nullptr))) { + return JSVM_INVALID_ARG; + } + + for (size_t i = 0; i < count; ++i) { + if (categories[i] >= v8impl::g_trace_catrgory_count) { + return JSVM_INVALID_ARG; + } + } + + using namespace v8::platform::tracing; + TraceConfig* trace_config = new TraceConfig(); + + if (count == 0) { + count = v8impl::g_default_catrgory_count; + categories = v8impl::g_default_categories; + } + + for (size_t i = 0; i < count; ++i) { + trace_config->AddIncludedCategory( + v8impl::g_internal_trace_categories[categories[i]]); + } + + v8::Platform* platform = v8impl::g_platform.get(); + TracingController* controller = + static_cast(platform->GetTracingController()); + v8impl::g_trace_stream.reset(new std::stringstream()); + auto stream = v8impl::g_trace_stream.get(); + + TraceWriter* writer = nullptr; + if (tag != nullptr) { + writer = TraceWriter::CreateJSONTraceWriter(*stream, tag); + } else { + writer = TraceWriter::CreateJSONTraceWriter(*stream); + } + + size_t max_chunks; + if (eventsCount != 0) { + size_t chunk_size = TraceBufferChunk::kChunkSize; + max_chunks = (eventsCount + chunk_size - 1) / chunk_size; + } else { + max_chunks = TraceBuffer::kRingBufferChunks; + } + + TraceBuffer* ring_buffer = + TraceBuffer::CreateTraceBufferRingBuffer(max_chunks, writer); + controller->Initialize(ring_buffer); + controller->StartTracing(trace_config); + return JSVM_OK; +} + +JSVM_Status JSVM_CDECL OH_JSVM_TraceStop(JSVM_OutputStream stream, + void* streamData) { + if (stream == nullptr || streamData == nullptr || + v8impl::g_trace_stream.get() == nullptr) { + return JSVM_INVALID_ARG; + } + + using namespace v8::platform::tracing; + v8::Platform* platform = v8impl::g_platform.get(); + auto controller = + static_cast(platform->GetTracingController()); + DCHECK(controller != nullptr); + controller->StopTracing(); + + // Call the destructor of TraceBuffer to print the JSON end. + controller->Initialize(nullptr); + + std::string output = v8impl::g_trace_stream.get()->rdbuf()->str(); + stream(output.c_str(), output.size(), streamData); + + v8impl::g_trace_stream.reset(nullptr); + return JSVM_OK; +} + JSVM_Status JSVM_CDECL OH_JSVM_GetPropertyNames(JSVM_Env env, JSVM_Value object, JSVM_Value* result) { diff --git a/src/jsvm.h b/src/jsvm.h index 41a7f81f32df13a16233bcaffd4f2f419929a7ea..f2530c9f1a523afdd83457e3d40ad52a7ee656d9 100644 --- a/src/jsvm.h +++ b/src/jsvm.h @@ -2850,6 +2850,34 @@ JSVM_EXTERN JSVM_Status OH_JSVM_ReleaseCache(JSVM_Env env, const uint8_t* cacheData, JSVM_CacheType cacheType); +/** + * @brief Trace start with specified categories for all JSVM VM.(Non-thread-safe) + * + * @param count The count of trace categories. + * @param categories Select internal trace events for tracing by categories. + * @param tag User-defined tag of trace data. + * @param eventsCount Number of trace events. + * @return Returns JSVM funtions result code. + * {@link JSVM_OK } if the function executed successfully.\n + * {@link JSVM_INVALID_ARG } if categories or count is illegal.\n + * + * @since 16 + */ +JSVM_EXTERN JSVM_Status OH_JSVM_TraceStart(size_t count, const JSVM_TraceCategory* categories, + const char* tag, size_t eventsCount); + +/** + * @brief Trace stop for specified categories for all JSVM VM.(Non-thread-safe) + * + * @param stream The output stream callback for receiving the data. + * @param streamData Data passed to the stream callback. + * @return Returns JSVM funtions result code. + * {@link JSVM_OK } if the function executed successfully.\n + * {@link JSVM_INVALID_ARG } if stream or streamData is NULL\n + * + * @since 16 + */ +JSVM_EXTERN JSVM_Status OH_JSVM_TraceStop(JSVM_OutputStream stream, void* streamData); EXTERN_C_END /** @} */ diff --git a/src/jsvm_types.h b/src/jsvm_types.h index 139fec1b6568546217b6b611ca6f6ef18d8d163e..1befc9d02e634aee17fe35952f3e090eb4f1eabe 100644 --- a/src/jsvm_types.h +++ b/src/jsvm_types.h @@ -768,4 +768,27 @@ typedef enum { JSVM_UNINITIALIZED, } JSVM_InitializedFlag; /** @} */ + + +/** + * @brief Trace category for jsvm internal trace events. + * + * @since 16 + */ +typedef enum { + /** Tracing main interface invoking of JSVM, such as run scripts. */ + JSVM_TRACE_VM, + /** Tracing interface invoking about compilation, such as CompileCodeBackground. */ + JSVM_TRACE_COMPILE, + /** Tracing interface invoking about execution status, such as Interrupts and Microtasks. */ + JSVM_TRACE_EXECUTE, + /** Tracing external callback */ + JSVM_TRACE_RUNTIME, + /** Tracing stack trace in JSVM. */ + JSVM_TRACE_STACK_TRACE, + /** Tracing main interface invoking of WASM, such as Compile Wasm Module and Instantiate. */ + JSVM_TRACE_WASM, + /** Tracing more detailed interface invoking of WASM, such as background compilation and wrappers. */ + JSVM_TRACE_WASM_DETAILED +} JSVM_TraceCategory; #endif /* ARK_RUNTIME_JSVM_JSVM_TYPE_H */