Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ include(FetchContent)
# --------------------------------------------------
FetchContent_Declare(arcana.cpp
GIT_REPOSITORY https://github.com/microsoft/arcana.cpp.git
GIT_TAG c726dbe58713eda65bfb139c257093c43479b894)
GIT_TAG c02527c32d51b6b3ffeda36f8cf140d2e1c60bb9)
FetchContent_Declare(AndroidExtensions
GIT_REPOSITORY https://github.com/BabylonJS/AndroidExtensions.git
GIT_TAG f7ed149b5360cc8a4908fece66607c5ce1e6095b)
GIT_TAG f7ed149b5360cc8a4908fece66607c5ce1e6095b)
FetchContent_Declare(asio
GIT_REPOSITORY https://github.com/chriskohlhoff/asio.git
GIT_TAG f693a3eb7fe72a5f19b975289afc4f437d373d9c)
Expand Down
13 changes: 11 additions & 2 deletions Core/Foundation/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
set(SOURCES
"Include/Babylon/Api.h"
"Include/Babylon/DebugTrace.h"
"Source/DebugTrace.cpp")
"Include/Babylon/PerfTrace.h"
"Source/DebugTrace.cpp"
"Source/PerfTrace.cpp")

add_library(Foundation ${SOURCES})

target_include_directories(Foundation INTERFACE "Include")
target_include_directories(Foundation
PRIVATE "Include/Babylon"
INTERFACE "Include")

target_link_libraries(Foundation
PUBLIC napi
PRIVATE napi-extensions
PRIVATE arcana)

set_property(TARGET Foundation PROPERTY FOLDER Core)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES})
49 changes: 49 additions & 0 deletions Core/Foundation/Include/Babylon/PerfTrace.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#pragma once
#include <memory>
#include <napi/env.h>


namespace Babylon
{
namespace PerfTrace
{
enum class Level
{
// Tracing is a no-op.
None,
// Traces time intervals with platform specific profiling APIs.
Mark,
// Traces time intervals and also performas platform specific logging.
Log,
};

// Controls a perf trace interval. When the handle is destructed, the perf interval ends.
class Handle
{
public:
~Handle();
Handle(const Handle&) = delete;
Handle& operator=(const Handle&) = delete;
Handle(Handle&&) noexcept;
Handle& operator=(Handle&&) noexcept;

// Transfers ownership of the handle to a napi value. After this call, destructing the passed in handle has no effect.
static Napi::Value ToNapi(Napi::Env env, Handle handle);

// Transfers ownership of the handle from a napi value. After this call, destructing the returned handle will end the perf trace interval.
static Handle FromNapi(Napi::Value napiValue);

private:
friend Handle Trace(const char* name);
Handle(const char* name);
class Impl;
std::unique_ptr<Impl> m_impl;
};

// Sets the trace level. It is None by default.
void SetLevel(Level level);

// Starts a perf trace interval. Destructing the returned handle ends the perf trace interval.
Handle Trace(const char* name);
}
}
76 changes: 76 additions & 0 deletions Core/Foundation/Source/PerfTrace.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include "PerfTrace.h"
#include <arcana/tracing/trace_region.h>
#include <cstdint>
#include <unordered_map>

namespace
{
std::unordered_map<std::uint32_t, Babylon::PerfTrace::Handle> g_traceHandles;
std::uint32_t g_nextTraceId = 0;
}

namespace Babylon
{
namespace PerfTrace
{
void SetLevel(Level level)
{
switch(level)
{
case Level::None:
arcana::trace_region::disable();
break;
case Level::Mark:
arcana::trace_region::enable(arcana::trace_level::mark);
break;
case Level::Log:
arcana::trace_region::enable(arcana::trace_level::log);
break;
}
}

// Private implementation to hide arcana::trace_region
class Handle::Impl
{
public:
Impl(const char* name) : m_region(name) {}
private:
arcana::trace_region m_region;
};

Handle::Handle(const char* name)
: m_impl(std::make_unique<Impl>(name))
{
}

Handle::~Handle() = default;
Handle::Handle(Handle&&) noexcept = default;
Handle& Handle::operator=(Handle&&) noexcept = default;

Handle Trace(const char* name)
{
return Handle(name);
}

Napi::Value Handle::ToNapi(Napi::Env env, Handle traceHandle)
{
g_nextTraceId++;
g_traceHandles.emplace(g_nextTraceId, std::move(traceHandle));
return Napi::Value::From(env, g_nextTraceId);
}

Handle Handle::FromNapi(Napi::Value napiValue)
{
const std::uint32_t traceId = napiValue.As<Napi::Number>().Uint32Value();
auto it = g_traceHandles.find(traceId);
if (it == g_traceHandles.end())
{
throw std::runtime_error("Invalid TraceHandle ID");
}

Handle traceHandle = std::move(it->second);
g_traceHandles.erase(it);
return traceHandle;
}
}
}
41 changes: 26 additions & 15 deletions Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "XMLHttpRequest.h"
#include <Babylon/JsRuntime.h>
#include <Babylon/Polyfills/XMLHttpRequest.h>
#include <arcana/tracing/trace_region.h>
#include <sstream>

namespace Babylon::Polyfills::Internal
{
Expand Down Expand Up @@ -216,11 +218,11 @@ namespace Babylon::Polyfills::Internal

void XMLHttpRequest::Open(const Napi::CallbackInfo& info)
{
const auto inputURL = info[1].As<Napi::String>();
m_url = info[1].As<Napi::String>();

try
{
m_request.Open(MethodType::StringToEnum(info[0].As<Napi::String>().Utf8Value()), inputURL);
m_request.Open(MethodType::StringToEnum(info[0].As<Napi::String>().Utf8Value()), m_url);
}
catch (const std::exception& e)
{
Expand Down Expand Up @@ -254,19 +256,26 @@ namespace Babylon::Polyfills::Internal
}
}

m_request.SendAsync().then(m_runtimeScheduler, arcana::cancellation::none(), [this]() {
SetReadyState(ReadyState::Done);
RaiseEvent(EventType::LoadEnd);

// Assume the XMLHttpRequest will only be used for a single request and clear the event handlers.
// Single use seems to be the standard pattern, and we need to release our strong refs to event handlers.
m_eventHandlerRefs.clear();
}).then(arcana::inline_scheduler, arcana::cancellation::none(), [env = info.Env()](arcana::expected<void, std::exception_ptr> result) {
if (result.has_error())
{
Napi::Error::New(env, result.error()).ThrowAsJavaScriptException();
}
});
std::string traceName = (std::ostringstream{} << "XMLHttpRequest::Send [" << m_url << "]").str();
auto sendRegion = std::make_optional<arcana::trace_region>(traceName.c_str());
m_request.SendAsync()
.then(arcana::inline_scheduler, arcana::cancellation::none(), [sendRegion{std::move(sendRegion)}]() mutable {
sendRegion.reset();
})
.then(m_runtimeScheduler, arcana::cancellation::none(), [this]() {
SetReadyState(ReadyState::Done);
RaiseEvent(EventType::LoadEnd);

// Assume the XMLHttpRequest will only be used for a single request and clear the event handlers.
// Single use seems to be the standard pattern, and we need to release our strong refs to event handlers.
m_eventHandlerRefs.clear();
})
.then(arcana::inline_scheduler, arcana::cancellation::none(), [env = info.Env()](arcana::expected<void, std::exception_ptr> result) {
if (result.has_error())
{
Napi::Error::New(env, result.error()).ThrowAsJavaScriptException();
}
});
}

void XMLHttpRequest::SetReadyState(ReadyState readyState)
Expand All @@ -277,6 +286,8 @@ namespace Babylon::Polyfills::Internal

void XMLHttpRequest::RaiseEvent(const char* eventType)
{
std::string traceName = (std::ostringstream{} << "XMLHttpRequest::RaiseEvent [" << eventType << "] [" << m_url << "]").str();
arcana::trace_region raiseEventRegion{traceName.c_str()};
const auto it = m_eventHandlerRefs.find(eventType);
if (it != m_eventHandlerRefs.end())
{
Expand Down
1 change: 1 addition & 0 deletions Polyfills/XMLHttpRequest/Source/XMLHttpRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ namespace Babylon::Polyfills::Internal
void SetReadyState(ReadyState readyState);
void RaiseEvent(const char* eventType);

std::string m_url{};
UrlLib::UrlRequest m_request{};
JsRuntimeScheduler m_runtimeScheduler;
ReadyState m_readyState{ReadyState::Unsent};
Expand Down