Skip to content

Commit

Permalink
Merge pull request #1942 from tangrams/javascriptcontext
Browse files Browse the repository at this point in the history
JavaScript context abstraction
  • Loading branch information
matteblair authored Dec 6, 2018
2 parents e1bcdcc + dc1beae commit b4db37e
Show file tree
Hide file tree
Showing 20 changed files with 1,328 additions and 376 deletions.
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.2)
project(tangram)

# Options
option(TANGRAM_USE_JSCORE "Use system libraries for JavaScriptCore and enable it on iOS and macOS" OFF)
option(TANGRAM_USE_JSCORE_STATIC "Build with pre-compiled static libraries for JavaScriptCore" OFF)

option(TANGRAM_USE_SYSTEM_FONT_LIBS "Use system libraries Freetype, ICU and Harfbuzz via pkgconfig" OFF)
option(TANGRAM_USE_SYSTEM_GLFW_LIBS "Use system libraries for GLFW3 via pkgconfig" OFF)

Expand Down Expand Up @@ -62,6 +65,14 @@ set(TANGRAM_PLATFORM ${TANGRAM_PLATFORM} CACHE INTERNAL "Tangram platform target
# Include the platform config file.
include(${TANGRAM_PLATFORM_CONFIG_FILE})

# Choose JavaScript implementation.
if (TANGRAM_IOS OR TANGRAM_OSX OR TANGRAM_USE_JSCORE_STATIC)
set(TANGRAM_JSCORE_AVAILABLE ON)
endif()
if (TANGRAM_JSCORE_AVAILABLE AND TANGRAM_USE_JSCORE)
set(TANGRAM_JSCORE_ENABLED ON)
endif()

# Add core library.
add_subdirectory(core)

Expand Down
10 changes: 9 additions & 1 deletion bench/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,15 @@ foreach(_src_file_path ${BENCH_SOURCES})
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bench"
)

add_resources(${EXECUTABLE_NAME} "${PROJECT_SOURCE_DIR}/scenes" "res")
if(TANGRAM_JSCORE_ENABLED)
target_compile_definitions(${EXECUTABLE_NAME} PRIVATE TANGRAM_USE_JSCORE=1)
endif()

add_custom_command(TARGET ${EXECUTABLE_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/scenes ${CMAKE_BINARY_DIR}/bench/res
COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/bench/test_tile_10_301_384.mvt ${CMAKE_BINARY_DIR}/bench/res/tile.mvt
)

endforeach()

168 changes: 151 additions & 17 deletions bench/src/benchStyleContext.cpp
Original file line number Diff line number Diff line change
@@ -1,42 +1,176 @@
#include "benchmark/benchmark.h"

#include "scene/styleContext.h"
#include "data/tileData.h"
#include "js/JavaScript.h"
#include "scene/styleContext.h"

#include "mockPlatform.h"
#include "log.h"
#include "data/tileSource.h"
#include "scene/importer.h"
#include "scene/scene.h"
#include "scene/dataLayer.h"
#include "scene/sceneLayer.h"
#include "scene/sceneLoader.h"
#include "text/fontContext.h"
#include "tile/tile.h"
#include "tile/tileTask.h"
#include "util/yamlUtil.h"

#include <functional>

#define RUN(FIXTURE, NAME) \
BENCHMARK_DEFINE_F(FIXTURE, NAME)(benchmark::State& st) { while (st.KeepRunning()) { run(); } } \
BENCHMARK_REGISTER_F(FIXTURE, NAME); //->Iterations(10000);

using namespace Tangram;

class JSGetPropertyBenchFixture : public benchmark::Fixture {
//const char scene_file[] = "bubble-wrap-style.zip";
const char scene_file[] = "res/scene.yaml";
const char tile_file[] = "res/tile.mvt";

std::shared_ptr<Scene> scene;
std::shared_ptr<TileSource> source;
std::shared_ptr<TileData> tileData;

void globalSetup() {
static std::atomic<bool> initialized{false};
if (initialized.exchange(true)) { return; }

std::shared_ptr<MockPlatform> platform = std::make_shared<MockPlatform>();
Url sceneUrl(scene_file);
platform->putMockUrlContents(sceneUrl, MockPlatform::getBytesFromFile(scene_file));
scene = std::make_shared<Scene>(platform, sceneUrl);
Importer importer(scene);
try {
scene->config() = importer.applySceneImports(platform);
}
catch (const YAML::ParserException& e) {
LOGE("Parsing scene config '%s'", e.what());
exit(-1);
}
if (!scene->config()) {
LOGE("Invalid scene file '%s'", scene_file);
exit(-1);
}
SceneLoader::applyConfig(platform, scene);
scene->fontContext()->loadFonts();
for (auto& s : scene->tileSources()) {
source = s;
if (source->generateGeometry()) { break; }
}
Tile tile({0,0,10,10});
auto task = source->createTask(tile.getID());
auto& t = dynamic_cast<BinaryTileTask&>(*task);

auto rawTileData = MockPlatform::getBytesFromFile(tile_file);
t.rawTileData = std::make_shared<std::vector<char>>(rawTileData);
tileData = source->parse(*task);
if (!tileData) {
LOGE("Invalid tile file '%s'", tile_file);
exit(-1);
}
}


template<class Context>
class JSGetPropertyFixture : public benchmark::Fixture {
public:
StyleContext ctx;
Context ctx;
Feature feature;
void SetUp(const ::benchmark::State& state) override {
feature.props.set("message", "Hello World!");

ctx.setFeature(feature);
ctx.setFunctions({R"(function () { return feature.message; })"});
JavaScriptScope<Context> jsScope(ctx);
ctx.setGlobalValue("language", jsScope.newString("en"));
feature.props.set("name:en", "Ozymandias");
feature.props.set("title", "King of Kings");
feature.props.set("number", 17);
ctx.setCurrentFeature(&feature);
ctx.setFunction(0, "function () { return (language && feature['name:' + language]) || title; }");
ctx.setFunction(1, "function () { return feature.order || feature.number; }");
}
void TearDown(const ::benchmark::State& state) override {}
__attribute__ ((noinline)) void run() {
StyleParam::Value value;
benchmark::DoNotOptimize(value);
JavaScriptScope<Context> jsScope(ctx);
value = jsScope.getFunctionResult(0).toString();
value = (float)jsScope.getFunctionResult(1).toDouble();
}
};
BENCHMARK_DEFINE_F(JSGetPropertyBenchFixture, JSGetPropertyBench)(benchmark::State& st) {
StyleParam::Value value;

while (st.KeepRunning()) {
ctx.evalStyle(0, StyleParamKey::text_source, value);
#ifdef TANGRAM_USE_JSCORE
using JSCoreGetPropertyFixture = JSGetPropertyFixture<JSCoreContext>;
RUN(JSCoreGetPropertyFixture, JSCoreGetPropertyBench)
#else
using DuktapeGetPropertyFixture = JSGetPropertyFixture<DuktapeContext>;
RUN(DuktapeGetPropertyFixture, DuktapeGetPropertyBench)
#endif

struct JSTileStyleFnFixture : public benchmark::Fixture {
StyleContext ctx;
Feature feature;
uint32_t numFunctions = 0;
uint32_t evalCnt = 0;

void SetUp(const ::benchmark::State& state) override {
globalSetup();
ctx.initFunctions(*scene);
ctx.setKeywordZoom(10);
}
}
BENCHMARK_REGISTER_F(JSGetPropertyBenchFixture, JSGetPropertyBench)->Iterations(10000);
void TearDown(const ::benchmark::State& state) override {
LOG(">>> %d", evalCnt);
}
__attribute__ ((noinline)) void run() {
StyleParam::Value styleValue;
benchmark::DoNotOptimize(styleValue);

for (const auto& datalayer : scene->layers()) {
for (const auto& collection : tileData->layers) {
if (!collection.name.empty()) {
const auto& dlc = datalayer.collections();
bool layerContainsCollection =
std::find(dlc.begin(), dlc.end(), collection.name) != dlc.end();

if (!layerContainsCollection) { continue; }
}

for (const auto& feat : collection.features) {
ctx.setFeature(feat);

std::function<void(const SceneLayer& layer)> filter;
filter = [&](const auto& layer) {
if (layer.filter().eval(feature, ctx)) {
for (auto& r : layer.rules()) {
for (auto& sp : r.parameters) {
if (sp.function >= 0) {
evalCnt++;
ctx.evalStyle(sp.function, sp.key, styleValue);
}
}
}

for (const auto& sublayer : layer.sublayers()) {
filter(sublayer);
}
}
};
filter(datalayer);
}
}
}
}
};

RUN(JSTileStyleFnFixture, TileStyleFnBench);

class DirectGetPropertyBenchFixture : public benchmark::Fixture {
class DirectGetPropertyFixture : public benchmark::Fixture {
public:
Feature feature;
void SetUp(const ::benchmark::State& state) override {
feature.props.set("message", "Hello World!");
}
void TearDown(const ::benchmark::State& state) override {}
};
BENCHMARK_DEFINE_F(DirectGetPropertyBenchFixture, DirectGetPropertyBench)(benchmark::State& st) {
BENCHMARK_DEFINE_F(DirectGetPropertyFixture, DirectGetPropertyBench)(benchmark::State& st) {
StyleParam::Value value;

while (st.KeepRunning()) {
Expand All @@ -48,6 +182,6 @@ BENCHMARK_DEFINE_F(DirectGetPropertyBenchFixture, DirectGetPropertyBench)(benchm
}
}
}
BENCHMARK_REGISTER_F(DirectGetPropertyBenchFixture, DirectGetPropertyBench);
BENCHMARK_REGISTER_F(DirectGetPropertyFixture, DirectGetPropertyBench);

BENCHMARK_MAIN();
23 changes: 13 additions & 10 deletions bench/src/benchTileBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
#include <iostream>
#include <vector>


#define RUN(FIXTURE, NAME) \
BENCHMARK_DEFINE_F(FIXTURE, NAME)(benchmark::State& st) { while (st.KeepRunning()) { run(); } } \
BENCHMARK_REGISTER_F(FIXTURE, NAME); //->Iterations(1)

using namespace Tangram;

//const char scene_file[] = "bubble-wrap-style.zip";
Expand All @@ -29,8 +34,8 @@ std::shared_ptr<TileSource> source;
std::shared_ptr<TileData> tileData;

void globalSetup() {
static bool initialized = false;
if (initialized) { return; }
static std::atomic<bool> initialized{false};
if (initialized.exchange(true)) { return; }

std::shared_ptr<MockPlatform> platform = std::make_shared<MockPlatform>();

Expand Down Expand Up @@ -69,28 +74,26 @@ void globalSetup() {
LOGE("Invalid tile file '%s'", tile_file);
exit(-1);
}
initialized = true;
}


class TileBuilderFixture : public benchmark::Fixture {
public:
std::unique_ptr<TileBuilder> tileBuilder;
std::shared_ptr<Tile> result;
void SetUp(const ::benchmark::State& state) override {
globalSetup();
tileBuilder = std::make_unique<TileBuilder>(scene);
tileBuilder = std::make_unique<TileBuilder>(scene, new StyleContext());
}
void TearDown(const ::benchmark::State& state) override {
result.reset();
}
};
BENCHMARK_DEFINE_F(TileBuilderFixture, TileBuilderBench)(benchmark::State& st) {
while (st.KeepRunning()) {

__attribute__ ((noinline)) void run() {
result = tileBuilder->build({0,0,10,10}, *tileData, *source);
}
}
BENCHMARK_REGISTER_F(TileBuilderFixture, TileBuilderBench);
};

RUN(TileBuilderFixture, TileBuilderBench);



Expand Down
22 changes: 19 additions & 3 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ target_include_directories(tangram-core
# TODO: These headers shouldn't be public, but Platform classes use them.
src
# TODO: This header shouldn't be public, but we use it in propertyItem.h
deps/glm
deps/variant/include
PRIVATE
generated
deps
deps/glm
deps/earcut/include
deps/isect2d/include
deps/hash-library
Expand All @@ -126,10 +126,23 @@ target_include_directories(tangram-core
deps/double-conversion/include
)

# Add JavaScript implementation.
if(TANGRAM_JSCORE_ENABLED)
target_sources(tangram-core PRIVATE src/js/JSCoreContext.cpp)
if (TANGRAM_USE_JSCORE_STATIC)
target_link_libraries(tangram-core PRIVATE jscore-static)
else()
target_link_libraries(tangram-core PRIVATE "-framework JavaScriptCore")
endif()
target_compile_definitions(tangram-core PRIVATE TANGRAM_USE_JSCORE=1)
else()
target_sources(tangram-core PRIVATE src/js/DuktapeContext.cpp)
target_link_libraries(tangram-core PRIVATE duktape)
endif()

# Link core library dependencies.
target_link_libraries(tangram-core
PRIVATE
duktape
css-color-parser-cpp
yaml-cpp
alfons
Expand All @@ -140,13 +153,16 @@ target_link_libraries(tangram-core
z
)


if(UNIX AND NOT APPLE)
# SQLite needs dl dynamic library loader when Linux
target_link_libraries(tangram-core PRIVATE dl)
endif()

if(TANGRAM_WARN_ON_RULE_CONFLICT)
add_definitions(-DTANGRAM_WARN_ON_RULE_CONFLICT)
target_compile_definitions(tangram-core
PRIVATE
TANGRAM_WARN_ON_RULE_CONFLICT)
endif()

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
Expand Down
Loading

0 comments on commit b4db37e

Please sign in to comment.