Skip to content

Commit

Permalink
Optimize val::array for numeric types (#17292)
Browse files Browse the repository at this point in the history
The val::array(const std::vector<T>&) is implemented by pushing items one
by one to val and is pretty slow for numeric types.

A new library function is added, which accepts memory_view and then copy
the typed array in JS side one-off. It's about 20x times faster.
  • Loading branch information
xbcnn committed Jun 29, 2022
1 parent e91ea21 commit e9b628c
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 1 deletion.
10 changes: 10 additions & 0 deletions src/embind/emval.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,16 @@ var LibraryEmVal = {
return Emval.toHandle([]);
},

_emval_new_array_from_memory_view__sig: 'pp',
_emval_new_array_from_memory_view__deps: ['$Emval'],
_emval_new_array_from_memory_view: function(view) {
view = Emval.toValue(view);
// using for..loop is faster than Array.from
var a = new Array(view.length);
for (i = 0; i < view.length; i++) a[i] = view[i];
return Emval.toHandle(a);
},

_emval_new_object__sig: 'p',
_emval_new_object__deps: ['$Emval'],
_emval_new_object: function() {
Expand Down
9 changes: 8 additions & 1 deletion system/include/emscripten/val.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ void _emval_decref(EM_VAL value);
void _emval_run_destructors(EM_DESTRUCTORS handle);

EM_VAL _emval_new_array();
EM_VAL _emval_new_array_from_memory_view(EM_VAL mv);
EM_VAL _emval_new_object();
EM_VAL _emval_new_cstring(const char*);
EM_VAL _emval_new_u8string(const char*);
Expand Down Expand Up @@ -335,7 +336,13 @@ class val {

template<typename T>
static val array(const std::vector<T>& vec) {
return array(vec.begin(), vec.end());
if constexpr (internal::typeSupportsMemoryView<T>()) {
// for numeric types, pass memory view and copy in JS side one-off
val view{ typed_memory_view(vec.size(), vec.data()) };
return val(internal::_emval_new_array_from_memory_view(view.as_handle()));
} else {
return array(vec.begin(), vec.end());
}
}

static val object() {
Expand Down
28 changes: 28 additions & 0 deletions tests/embind/embind_benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,33 @@ void __attribute__((noinline)) pass_gameobject_ptr_benchmark()
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("val::array: %lf\n", emscripten_get_now() - t);

t = emscripten_get_now();
for (int i = 0; i < kLoopTimes; i++) {
val v = val::array(vec);
}
printf("val::array opt numeric types: %lf\n", emscripten_get_now() - t);

// It's about 20x times faster.
// val::array: 1021.525756
// val::array opt numeric types: 50.600682
}

int EMSCRIPTEN_KEEPALIVE main()
{
for(int i = 1000; i <= 100000; i *= 10)
Expand Down Expand Up @@ -506,4 +533,5 @@ int EMSCRIPTEN_KEEPALIVE main()
call_through_interface1();
call_through_interface2();
returns_val_benchmark();
numeric_val_array_benchmark();
}

0 comments on commit e9b628c

Please sign in to comment.