Buckets:
| // Copyright 2013 The Emscripten Authors. All rights reserved. | |
| // Emscripten is available under two separate licenses, the MIT license and the | |
| // University of Illinois/NCSA Open Source License. Both these licenses can be | |
| // found in the LICENSE file. | |
| int counter = 0; | |
| extern "C" { | |
| int __attribute__((noinline)) EMSCRIPTEN_KEEPALIVE get_counter() { | |
| return counter; | |
| } | |
| void __attribute__((noinline)) EMSCRIPTEN_KEEPALIVE increment_counter() { | |
| ++counter; | |
| } | |
| int __attribute__((noinline)) EMSCRIPTEN_KEEPALIVE sum_int(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int v9) { | |
| return v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9; | |
| } | |
| float __attribute__((noinline)) EMSCRIPTEN_KEEPALIVE sum_float(float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8, float v9) { | |
| return v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9; | |
| } | |
| int __attribute__((noinline)) EMSCRIPTEN_KEEPALIVE returns_input(int i) { | |
| return i; | |
| } | |
| extern void increment_counter_benchmark_js(int N); | |
| extern void returns_input_benchmark_js(); | |
| extern void sum_int_benchmark_js(); | |
| extern void sum_float_benchmark_js(); | |
| extern void increment_counter_benchmark_embind_js(int N); | |
| extern void returns_input_benchmark_embind_js(); | |
| extern void sum_int_benchmark_embind_js(); | |
| extern void sum_float_benchmark_embind_js(); | |
| extern void increment_class_counter_benchmark_embind_js(int N); | |
| extern void move_gameobjects_benchmark_embind_js(); | |
| extern void pass_gameobject_ptr_benchmark(); | |
| extern void pass_gameobject_ptr_benchmark_embind_js(); | |
| extern void call_through_interface0(); | |
| extern void call_through_interface1(); | |
| extern void call_through_interface2(); | |
| extern void returns_val_benchmark(); | |
| } | |
| emscripten::val returns_val(emscripten::val value) { | |
| return emscripten::val(value.as<unsigned>() + 1); | |
| } | |
| class Vec3 { | |
| public: | |
| Vec3():x(0),y(0),z(0) {} | |
| Vec3(float x_, float y_, float z_):x(x_),y(y_),z(z_) {} | |
| float x,y,z; | |
| }; | |
| Vec3 add(const Vec3 &lhs, const Vec3 &rhs) { return Vec3(lhs.x+rhs.x, lhs.y+rhs.y, lhs.z+rhs.z); } | |
| class Transform { | |
| public: | |
| Transform():scale(1) {} | |
| Vec3 pos; | |
| Vec3 rot; | |
| float scale; | |
| Vec3 __attribute__((noinline)) GetPosition() const { return pos; } | |
| Vec3 __attribute__((noinline)) GetRotation() const { return rot; } | |
| float __attribute__((noinline)) GetScale() const { return scale; } | |
| void __attribute__((noinline)) SetPosition(const Vec3 &pos_) { pos = pos_; } | |
| void __attribute__((noinline)) SetRotation(const Vec3 &rot_) { rot = rot_; } | |
| void __attribute__((noinline)) SetScale(float scale_) { scale = scale_; } | |
| }; | |
| typedef std::shared_ptr<Transform> TransformPtr; | |
| class GameObject { | |
| public: | |
| GameObject() { | |
| transform = std::make_shared<Transform>(); | |
| } | |
| std::shared_ptr<Transform> transform; | |
| TransformPtr __attribute__((noinline)) GetTransform() const { return transform; } | |
| }; | |
| typedef std::shared_ptr<GameObject> GameObjectPtr; | |
| GameObjectPtr create_game_object() { | |
| return std::make_shared<GameObject>(); | |
| } | |
| GameObjectPtr __attribute__((noinline)) pass_gameobject_ptr(GameObjectPtr p) { | |
| return p; | |
| } | |
| class Foo { | |
| public: | |
| Foo() : class_counter(0) {} | |
| void __attribute__((noinline)) incr_global_counter() { | |
| ++counter; | |
| } | |
| void __attribute__((noinline)) incr_class_counter() { | |
| ++class_counter; | |
| } | |
| int class_counter_val() const { | |
| return class_counter; | |
| } | |
| int class_counter; | |
| }; | |
| class Interface { | |
| public: | |
| virtual ~Interface() {} | |
| virtual void call0() = 0; | |
| virtual std::wstring call1(const std::wstring& str1, const std::wstring& str2) = 0; | |
| virtual void call_with_typed_array(size_t size, const void*) = 0; | |
| virtual void call_with_memory_view(size_t size, const unsigned int*) = 0; | |
| }; | |
| EMSCRIPTEN_SYMBOL(HEAP8); | |
| EMSCRIPTEN_SYMBOL(buffer); | |
| EMSCRIPTEN_SYMBOL(call0); | |
| EMSCRIPTEN_SYMBOL(call1); | |
| EMSCRIPTEN_SYMBOL(call_with_typed_array); | |
| EMSCRIPTEN_SYMBOL(call_with_memory_view); | |
| EMSCRIPTEN_SYMBOL(Uint8Array); | |
| class InterfaceWrapper : public emscripten::wrapper<Interface> | |
| { | |
| public: | |
| EMSCRIPTEN_WRAPPER(InterfaceWrapper); | |
| void call0() override { | |
| return call<void>(call0_symbol); | |
| } | |
| std::wstring call1(const std::wstring& str1, const std::wstring& str2) override { | |
| return call<std::wstring>(call1_symbol, str1, str2); | |
| } | |
| void call_with_typed_array(size_t size, const void* data) override { | |
| return call<void>( | |
| call_with_typed_array_symbol, | |
| emscripten::val::global(Uint8Array_symbol).new_( | |
| emscripten::val::module_property(HEAP8_symbol)[buffer_symbol], | |
| reinterpret_cast<uintptr_t>(data), | |
| size)); | |
| } | |
| void call_with_memory_view(size_t size, const unsigned int* data) override { | |
| return call<void>( | |
| call_with_memory_view_symbol, | |
| emscripten::typed_memory_view(size, data)); | |
| } | |
| }; | |
| void callInterface0(unsigned N, Interface& o) { | |
| for (unsigned i = 0; i < N; i += 8) { | |
| o.call0(); | |
| o.call0(); | |
| o.call0(); | |
| o.call0(); | |
| o.call0(); | |
| o.call0(); | |
| o.call0(); | |
| o.call0(); | |
| } | |
| } | |
| void callInterface1(unsigned N, Interface& o) { | |
| static std::wstring foo(L"foo"); | |
| static std::wstring bar(L"bar"); | |
| static std::wstring baz(L"baz"); | |
| static std::wstring qux(L"qux"); | |
| for (unsigned i = 0; i < N; i += 7) { | |
| o.call1( | |
| o.call1( | |
| o.call1(foo, bar), | |
| o.call1(baz, qux)), | |
| o.call1( | |
| o.call1(qux, foo), | |
| o.call1(bar, baz))); | |
| } | |
| } | |
| void callInterface2(unsigned N, Interface& o) { | |
| int i = 0; | |
| for (unsigned i = 0; i < N; i += 8) { | |
| o.call_with_typed_array(sizeof(int), &i); | |
| o.call_with_typed_array(sizeof(int), &i); | |
| o.call_with_typed_array(sizeof(int), &i); | |
| o.call_with_typed_array(sizeof(int), &i); | |
| o.call_with_typed_array(sizeof(int), &i); | |
| o.call_with_typed_array(sizeof(int), &i); | |
| o.call_with_typed_array(sizeof(int), &i); | |
| o.call_with_typed_array(sizeof(int), &i); | |
| } | |
| } | |
| void callInterface3(unsigned N, Interface& o) { | |
| for (unsigned i = 0; i < N; i += 8) { | |
| o.call_with_memory_view(sizeof(int), &i); | |
| o.call_with_memory_view(sizeof(int), &i); | |
| o.call_with_memory_view(sizeof(int), &i); | |
| o.call_with_memory_view(sizeof(int), &i); | |
| o.call_with_memory_view(sizeof(int), &i); | |
| o.call_with_memory_view(sizeof(int), &i); | |
| o.call_with_memory_view(sizeof(int), &i); | |
| o.call_with_memory_view(sizeof(int), &i); | |
| } | |
| } | |
| EMSCRIPTEN_BINDINGS(benchmark) { | |
| using namespace emscripten; | |
| class_<GameObject>("GameObject") | |
| .smart_ptr<GameObjectPtr>("GameObjectPtr") | |
| .function("GetTransform", &GameObject::GetTransform); | |
| class_<Transform>("Transform") | |
| .smart_ptr<TransformPtr>("TransformPtr") | |
| .function("GetPosition", &Transform::GetPosition) | |
| .function("GetRotation", &Transform::GetRotation) | |
| .function("GetScale", &Transform::GetScale) | |
| .function("SetPosition", &Transform::SetPosition) | |
| .function("SetRotation", &Transform::SetRotation) | |
| .function("SetScale", &Transform::SetScale); | |
| value_array<Vec3>("Vec3") | |
| .element(&Vec3::x) | |
| .element(&Vec3::y) | |
| .element(&Vec3::z); | |
| function("create_game_object", &create_game_object); | |
| function("pass_gameobject_ptr", &pass_gameobject_ptr); | |
| function("add", &add); | |
| function("get_counter", &get_counter); | |
| function("increment_counter", &increment_counter); | |
| function("returns_input", &returns_input); | |
| function("sum_int", &sum_int); | |
| function("sum_float", &sum_float); | |
| class_<Foo>("Foo") | |
| .constructor<>() | |
| .function("incr_global_counter", &Foo::incr_global_counter) | |
| .function("incr_class_counter", &Foo::incr_class_counter) | |
| .function("class_counter_val", &Foo::class_counter_val) | |
| ; | |
| class_<Interface>("Interface") | |
| .allow_subclass<InterfaceWrapper>("InterfaceWrapper") | |
| ; | |
| function("callInterface0", &callInterface0); | |
| function("callInterface1", &callInterface1); | |
| function("callInterface2", &callInterface2); | |
| function("callInterface3", &callInterface3); | |
| function("returns_val", &returns_val); | |
| } | |
| void __attribute__((noinline)) emscripten_get_now_benchmark(int N) { | |
| volatile float t = emscripten_get_now(); | |
| for (int i = 0; i < N; ++i) { | |
| emscripten_get_now(); | |
| emscripten_get_now(); | |
| emscripten_get_now(); | |
| emscripten_get_now(); | |
| emscripten_get_now(); | |
| emscripten_get_now(); | |
| emscripten_get_now(); | |
| emscripten_get_now(); | |
| emscripten_get_now(); | |
| emscripten_get_now(); | |
| } | |
| volatile float t2 = emscripten_get_now(); | |
| printf("C++ emscripten_get_now %d iters: %f msecs.\n", N, (t2-t)); | |
| } | |
| void __attribute__((noinline)) increment_counter_benchmark(int N) { | |
| volatile float t = emscripten_get_now(); | |
| for ( int i = 0; i < N; ++i) { | |
| increment_counter(); | |
| increment_counter(); | |
| increment_counter(); | |
| increment_counter(); | |
| increment_counter(); | |
| increment_counter(); | |
| increment_counter(); | |
| increment_counter(); | |
| increment_counter(); | |
| increment_counter(); | |
| } | |
| volatile float t2 = emscripten_get_now(); | |
| printf("C++ increment_counter %d iters: %f msecs.\n", N, (t2-t)); | |
| } | |
| void __attribute__((noinline)) increment_class_counter_benchmark(int N) { | |
| Foo foo; | |
| volatile float t = emscripten_get_now(); | |
| for (int i = 0; i < N; ++i) { | |
| foo.incr_class_counter(); | |
| foo.incr_class_counter(); | |
| foo.incr_class_counter(); | |
| foo.incr_class_counter(); | |
| foo.incr_class_counter(); | |
| foo.incr_class_counter(); | |
| foo.incr_class_counter(); | |
| foo.incr_class_counter(); | |
| foo.incr_class_counter(); | |
| foo.incr_class_counter(); | |
| } | |
| volatile float t2 = emscripten_get_now(); | |
| printf("C++ increment_class_counter %d iters: %f msecs. result: %d\n", N, (t2-t), foo.class_counter); | |
| } | |
| void __attribute__((noinline)) returns_input_benchmark() { | |
| volatile int r = 0; | |
| volatile float t = emscripten_get_now(); | |
| for (int i = 0; i < 100000; ++i) { | |
| r += returns_input(i); | |
| r += returns_input(i); | |
| r += returns_input(i); | |
| r += returns_input(i); | |
| r += returns_input(i); | |
| r += returns_input(i); | |
| r += returns_input(i); | |
| r += returns_input(i); | |
| r += returns_input(i); | |
| r += returns_input(i); | |
| } | |
| volatile float t2 = emscripten_get_now(); | |
| printf("C++ returns_input 100000 iters: %f msecs.\n", (t2-t)); | |
| } | |
| void __attribute__((noinline)) sum_int_benchmark() { | |
| volatile float t = emscripten_get_now(); | |
| volatile int r = 0; | |
| for (int i = 0; i < 100000; ++i) { | |
| r += sum_int(i,2,3,4,5,6,7,8,9); | |
| r += sum_int(i,2,3,4,5,6,7,8,9); | |
| r += sum_int(i,2,3,4,5,6,7,8,9); | |
| r += sum_int(i,2,3,4,5,6,7,8,9); | |
| r += sum_int(i,2,3,4,5,6,7,8,9); | |
| r += sum_int(i,2,3,4,5,6,7,8,9); | |
| r += sum_int(i,2,3,4,5,6,7,8,9); | |
| r += sum_int(i,2,3,4,5,6,7,8,9); | |
| r += sum_int(i,2,3,4,5,6,7,8,9); | |
| r += sum_int(i,2,3,4,5,6,7,8,9); | |
| } | |
| volatile float t2 = emscripten_get_now(); | |
| printf("C++ sum_int 100000 iters: %f msecs.\n", (t2-t)); | |
| } | |
| void __attribute__((noinline)) sum_float_benchmark() { | |
| volatile float f = 0.f; | |
| volatile float t = emscripten_get_now(); | |
| for (int i = 0; i < 100000; ++i) { | |
| f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); | |
| f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); | |
| f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); | |
| f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); | |
| f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); | |
| f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); | |
| f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); | |
| f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); | |
| f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); | |
| f += sum_float((float)i,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f); | |
| } | |
| volatile float t2 = emscripten_get_now(); | |
| printf("C++ sum_float 100000 iters: %f msecs.\n", (t2-t)); | |
| } | |
| void __attribute__((noinline)) move_gameobjects_benchmark() | |
| { | |
| const int N = 10000; | |
| GameObjectPtr objects[N]; | |
| for (int i = 0; i < N; ++i) { | |
| objects[i] = create_game_object(); | |
| } | |
| volatile float t = emscripten_get_now(); | |
| for (int i = 0; i < N; ++i) { | |
| TransformPtr t = objects[i]->GetTransform(); | |
| Vec3 pos = add(t->GetPosition(), Vec3(2.f, 0.f, 1.f)); | |
| Vec3 rot = add(t->GetRotation(), Vec3(0.1f, 0.2f, 0.3f)); | |
| t->SetPosition(pos); | |
| t->SetRotation(rot); | |
| } | |
| volatile float t2 = emscripten_get_now(); | |
| Vec3 accum; | |
| for (int i = 0; i < N; ++i) { | |
| accum = add(add(accum, objects[i]->GetTransform()->GetPosition()), objects[i]->GetTransform()->GetRotation()); | |
| } | |
| printf("C++ move_gameobjects %d iters: %f msecs. Result: %f\n", N, (t2-t), accum.x+accum.y+accum.z); | |
| } | |
| void __attribute__((noinline)) pass_gameobject_ptr_benchmark() | |
| { | |
| const int N = 100000; | |
| GameObjectPtr objects[N]; | |
| for (int i = 0; i < N; ++i) { | |
| objects[i] = create_game_object(); | |
| } | |
| volatile float t = emscripten_get_now(); | |
| for (int i = 0; i < N; ++i) { | |
| objects[i] = pass_gameobject_ptr(objects[i]); | |
| } | |
| volatile float t2 = emscripten_get_now(); | |
| printf("C++ pass_gameobject_ptr %d iters: %f msecs.\n", N, (t2-t)); | |
| } | |
| void __attribute__((noinline)) numeric_val_array_benchmark() { | |
| using emscripten::val; | |
| std::vector<int> vec = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, | |
| 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, | |
| 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, | |
| 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, | |
| 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; | |
| const int kLoopTimes = 100000; | |
| double t = emscripten_get_now(); | |
| for (int i = 0; i < kLoopTimes; i++) { | |
| val v = val::array(vec.begin(), vec.end()); | |
| } | |
| printf("\nval::array(Iter begin, Iter end): %lf msecs.\n", emscripten_get_now() - t); | |
| t = emscripten_get_now(); | |
| for (int i = 0; i < kLoopTimes; i++) { | |
| val v = val::array(vec); | |
| } | |
| printf("val::array(const std::vector<T>& vec) with opt numeric types: %lf msecs.\n", emscripten_get_now() - t); | |
| // It's about 20x times faster. | |
| // val::array(Iter begin, Iter end): 727.300000 msecs. | |
| // val::array(const std::vector<T>& vec) with opt numeric types: 29.700000 msecs. | |
| // If compile with `--std=c++20`, the result is very close. | |
| // val::array(Iter begin, Iter end): 30.400000 msecs. | |
| // val::array(const std::vector<T>& vec) with opt numeric types: 27.500000 msecs. | |
| } | |
| int main() { | |
| for (int i = 1000; i <= 100000; i *= 10) { | |
| emscripten_get_now_benchmark(i); | |
| } | |
| printf("\n"); | |
| for (int i = 1000; i <= 100000; i *= 10) { | |
| increment_counter_benchmark(i); | |
| increment_counter_benchmark_js(i); | |
| increment_counter_benchmark_embind_js(i); | |
| printf("\n"); | |
| } | |
| for (int i = 1000; i <= 100000; i *= 10) { | |
| increment_class_counter_benchmark(i); | |
| increment_class_counter_benchmark_embind_js(i); | |
| printf("\n"); | |
| } | |
| returns_input_benchmark(); | |
| returns_input_benchmark_js(); | |
| returns_input_benchmark_embind_js(); | |
| printf("\n"); | |
| sum_int_benchmark(); | |
| sum_int_benchmark_js(); | |
| sum_int_benchmark_embind_js(); | |
| printf("\n"); | |
| sum_float_benchmark(); | |
| sum_float_benchmark_js(); | |
| sum_float_benchmark_embind_js(); | |
| printf("\n"); | |
| move_gameobjects_benchmark(); | |
| move_gameobjects_benchmark_embind_js(); | |
| printf("\n"); | |
| pass_gameobject_ptr_benchmark(); | |
| pass_gameobject_ptr_benchmark_embind_js(); | |
| emscripten_get_now(); | |
| call_through_interface0(); | |
| call_through_interface1(); | |
| call_through_interface2(); | |
| returns_val_benchmark(); | |
| numeric_val_array_benchmark(); | |
| } | |
Xet Storage Details
- Size:
- 16.4 kB
- Xet hash:
- 474daea28882db87747e036b35fd234792583595d2c05b1bd840403dc83009bc
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.