SlideShare a Scribd company logo
1 of 115
Chromium Binding 기술을
Node.js에 적용해보자!
Name: Jinho Bang
E-Mail: zino@chromium.org
0.
요약
이 세션에서 다룰 내용은..
Node.js에서 Native Module을
바인딩 하는 방법이다.
그런데 이미 Node.js에는 바인딩을 위한
방법들이 제공되고 있다.
그러나 그 방법이 아름답지 않다.
이 세션에서는 그러한 문제를 분석하고
좀 더 아름답게 해결하는 방안을 모색해본다.
1.
JS에서 왜 Native Module을
사용하는가?
성능(Performance)
Low Level APIs
기존에 잘 만들어진 코드가 Native 일때
어쨌든 Node.js를 사용한다면
사용중인 패키지의 30%는 Native이다.
2.
예제를 통해 알아보는
기존의 Native Module
연동 방식
sum()함수를 구현해보자(JS 호출)
let s = sum([1, 2, 3, 4, 5, 6, 7, 8, 9]);
JS
JS
function sum(elements) {
let s = 0;
elements.forEach(element => { s += element; });
return s;
}
sum()함수를 구현해보자(Native 호출)
let s = sum([1, 2, 3, 4, 5, 6, 7, 8, 9]);
JS
Native
int sum(std::vector<int> elements) {
int s = 0;
for (int i = 0; i < elements.size(); i++)
s += elements[i];
return s;
}
?
그런데 Javascript에서 어떻게 호출할까?
기존의 Native Module 연동 방식
var spawn = require('child_process').spawn;
var sum = spawn('sum', [...]);
sum.stdout.on('data', result => {
process(result);
...
});
아마 우리가 원한게 이런것은 아니지 말입니다..
기존의 Native Module 연동 방식
• Node.js C++ Addon
• https://nodejs.org/dist/latest-v8.x/docs/api/addons.html
• NAN(Native Abstraction for Node)
• Node.js C++ Addon이 V8 Public API를 사용하기 때문에 V8 변화에 민감하다.
• Node.js를 업데이트 할때마다 문제가 발생하는 것을 해결.
• https://github.com/nodejs/nan
• N-API ß Latest!
• Node.js 8.0이후부터 지원, 8.6에서 Stable Release
• NAN과 유사한 방식이지만, ABI-Stable을 보장. (즉, 재컴파일 불필요)
• V8 Public API가 아닌 Node.js에서 한번 Wrapping하여 제공하므로 다른 엔진으로 교체도 가능.
• https://nodejs.org/dist/latest-v8.x/docs/api/n-api.html
N-API에 이르기까지 많은 개선이 있었지만,
Binding 코드를 작성하는 것을 위한 개선은 없었다.
N-API를 사용하여 Binding 해보자
napi_value Sum(napi_env, napi_callback_info info) {
napi_status status;
size_t args = 1;
napi_value args[1];
napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
if (argc < 1) {
napi_throw_type_error(env, nullptr, "…");
return nullptr;
}
uint32_t length = 0;
napi_get_array_length(env, args[0], &length);
double sum = 0;
for (int i = 0; i < length; i++) {
napi_value element;
napi_get_element(env, i, &element);
napi_valuetype valuetype;
napi_typeof(env, element, &valuetype);
if (napi_valuetype != napi_number) {
napi_throw_type_error(env, nullptr, "…");
return nullptr;
}
double value;
napi_get_value_double(env, element, &value);
sum += value;
}
napi_value js_sum;
napi_create_double(env, sum, &js_sum);
return js_sum;
}
다음의 예제는 N-API를 사용하여 Native Binding을 하고 있다.
그러나..
6줄 짜리 sum()함수가 35줄이 된다.
N-API를 사용하여 Binding 해보자
const sum = require(‘sum’);
let s = sum([1, 2, 3, 4, 5, 6, 7, 8, 9]);
N-API를 사용하여 Binding을 하면 Javascript에서 호출 할 수 있다.
3.
기존의 문제점 파헤치기
지금부터 코드가 많이 나오는데..
굳이 그 코드들을 이해하실 필요는 없습니다!
문제점1: Argument Check
napi_value Sum(napi_env, napi_callback_info info) {
napi_status status;
size_t args = 1;
napi_value args[1];
napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
// 문제점1. JS argument는 Runtime에 결정되므로 개발자가 직접 체크해야한다.
if (argc < 1) {
napi_throw_type_error(env, nullptr, "…");
return nullptr;
}
문제점2: Type Checking
for (int i = 0; i < length; i++) {
napi_value element;
napi_get_element(env, i, &element);
// 문제점2. 각 Array Element의 Type Checking도 직접해야한다.
napi_valuetype valuetype;
napi_typeof(env, element, &valuetype);
if (napi_valuetype != napi_number) {
napi_throw_type_error(env, nullptr, "…");
return nullptr;
}
문제점3: Type Converting
// 문제점3. JS에서 Native Type Converting을 직접해야한다.
double value;
napi_get_value_double(env, element, &value);
sum += value;
}
// 문제점3. Native에서 JS Type Converting을 직접해야한다.
napi_value js_sum;
napi_create_double(env, sum, &js_sum);
return js_sum;
uint32_t length = 10000;
for (int i = 0; i < length; i++) {
napi_value element;
napi_get_element(env, i, &element);
...
}
문제점4: Memory Management
napi_value
length
. . .
…
내가 아는 Stack
Pop
Push
uint32_t length = 10000;
for (int i = 0; i < length; i++) {
// napi_get_element()를 호출할 때마다
// 새로운 object를 생성하고 HandleScope에
// 쌓이게 됨.
napi_value element;
napi_get_element(env, i, &element);
...
}
문제점4: Memory Management
napi_value
napi_value
napi_value
napi_value
napi_value
napi_value
…
napi_value
i = 9999
i = 9998
i = 4
i = 3
i = 2
i = 1
i = 0
HandleScopeStack Heap
문제점4: Memory Management
for (int i = 0; i < length; i++) {
napi_handle_scope scope;
napi_status status = napi_open_handle_scope(env, &scope);
napi_value element;
napi_get_element(env, i, &element);
...
napi_close_handle_scope(env, scope);
}
문제점5: Readability
napi_value Sum(napi_env, napi_callback_info info) {
napi_status status;
size_t args = 1;
napi_value args[1];
napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
if (argc < 1) {
napi_throw_type_error(env, nullptr, "…");
return nullptr;
}
uint32_t length = 0;
napi_get_array_length(env, args[0], &length);
double sum = 0;
for (int i = 0; i < length; i++) {
napi_value element;
napi_get_element(env, i, &element);
napi_valuetype valuetype;
napi_typeof(env, element, &valuetype);
if (napi_valuetype != napi_number) {
napi_throw_type_error(env, nullptr, "…");
return nullptr;
}
double value;
napi_get_value_double(env, element, &value);
sum += value;
}
napi_value js_sum;
napi_create_double(env, sum, &js_sum);
return js_sum;
}
int sum(std::vector<int> elements) {
int s = 0;
for (int i = 0; i < elements.size(); i++)
s += elements[i];
return s;
}
// 문제점5. Binding 코드가 많이 삽입되면서 가독성이 떨어진다.
요약
• 기존의 방법은 TypeChecking/Converting과 같은 노가다를 반복해야 한다.
• Memory 관리 Mechanism이 다르고 Binding을 위해 사용되는 API를 다룰 줄 알아야
하므로 V8, N-API, JS, C++과 같은 지식 모두를 필요로 한다.
• 전체적인 코드의 복잡도가 증가한다.
4.
Chromium에서 Blink와 V8은
어떻게 연결되나?
왜 Chromium을 살펴보나?
Chromium은 V8의 또 다른 Embedder이다.
♥ ≡ ♥
Blink
(Rendering Engine)
V8
(Javascript Engine)
Node.js
Native Module
V8
(Javascript Engine)
document.getElementById();
<div id="hello"></div>
<script>
let div = document.getElementById(‘hello’);
</script>
V8 Engine과 Blink Engine의 관계
V8 Engine
Chromium
Loader
<div id="hello"></div>
<script>
let div = document.getElementById(‘hello’);
</script>
V8 Engine과 Blink Engine의 관계
V8 Engine
Blink Engine
V8 Engine
Chromium
Loader
DOM Parsing
<div id="hello"></div>
<script>
let div = document.getElementById(‘hello’);
</script>
V8 Engine과 Blink Engine의 관계
V8 Engine
Blink Engine
V8 Engine
Chromium
Loader
V8 Engine
DOM Parsing
<script>
document.getElementById(‘hello’);
</script>
JS Evaluate
<div id="hello"></div>
<script>
let div = document.getElementById(‘hello’);
</script>
V8 Engine과 Blink Engine의 관계
V8 Engine
Blink Engine
V8 Engine
Chromium
Loader
V8 Engine
DOM Parsing
JS Evaluate
Actually, called
document.getElementById();
<div id="hello"></div>
<script>
let div = document.getElementById(‘hello’);
</script>
<script>
document.getElementById(‘hello’);
</script>
V8 Engine과 Blink Engine의 관계
V8 Engine
Blink Engine
V8 Engine
Chromium
Loader
V8 Engine
DOM Parsing
JS Evaluate
Actually, called
document.getElementById();
Return JS Wrapper Object
let div = document.getElementById(‘hello’);
<div id="hello"></div>
<script>
let div = document.getElementById(‘hello’);
</script>
<script>
document.getElementById(‘hello’);
</script>
<script>
document.getElementById(‘hello’);
</script>
V8 Engine과 Blink Engine의 관계
V8 Engine
Blink Engine
V8 Engine
Chromium
Loader
V8 Engine
DOM Parsing
JS Evaluate
V8 Binding
Actually, called
document.getElementById();
Return JS Wrapper Object
let div = document.getElementById(‘hello’);
Type Checking/Converting
Manage Isolate and Context
<div id="hello"></div>
<script>
let div = document.getElementById(‘hello’);
</script>
<script>
document.getElementById(‘hello’);
</script>
V8 Engine과 Blink Engine의 관계
V8 Engine
Blink Engine
V8 Engine
Chromium
Loader
V8 Engine
DOM Parsing
JS Evaluate
WebIDL
Binding
Actually, called
document.getElementById();
Return JS Wrapper Object
let div = document.getElementById(‘hello’);
Auto-generated!!
<div id="hello"></div>
<script>
let div = document.getElementById(‘hello’);
</script>
V8 Binding이란?
• Chromium에서 V8과 Blink를 연결하는 코드이다.
• 사용자가 직접 짜지 않고 WebIDL으로부터 자동 생성(auto-generation)된다.
• WebIDL은 JS Engine과 Web Engine을 연결하는 Web 표준에 의해 정의된다.
• https://heycam.github.io/webidl/
• https://www.w3.org/TR/api-design/
코드레벨로 살펴보는 WebIDL
// WebIDL
[Constructor]
interface Calculator {
double sum(sequence<long> elements);
};
코드레벨로 살펴보는 WebIDL
// WebIDL
[Constructor]
interface Calculator {
double sum(sequence<long> elements);
};
napi_value Sum(napi_env, napi_callback_info info) {
napi_status status;
size_t args = 1;
napi_value args[1];
napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
if (argc < 1) {
napi_throw_type_error(env, nullptr, "…");
return nullptr;
}
uint32_t length = 0;
napi_get_array_length(env, args[0], &length);
double sum = 0;
for (int i = 0; i < length; i++) {
napi_value element;
napi_get_element(env, i, &element);
napi_valuetype valuetype;
napi_typeof(env, element, &valuetype);
if (napi_valuetype != napi_number) {
napi_throw_type_error(env, nullptr, "…");
return nullptr;
}
double value;
napi_get_value_double(env, element, &value);
sum += value;
}
napi_value js_sum;
napi_create_double(env, sum, &js_sum);
return js_sum;
}
VS
코드레벨로 살펴보는 WebIDL
// User’s Native Code
class Calculator {
public:
double Sum(std::vector<int> elements) {
int sum = 0;
for (int i = 0; i < elements.size(); i++)
sum += elements[i];
return sum;
}
};
코드레벨로 살펴보는 WebIDL
// User’s JS code
var calculator = new Calculator();
console.log(calculator.sum([1, 2, 3, 4, 5, 6, 7, 8, 9]));
요약
• Chromium에서 V8과 Blink의 관계는 Node.js에서 V8과 Native Module의 관계와 동
등하다.
• V8과 Blink를 연결하는 Layer를 V8 Binding(WebIDL Binding)이라고 부른다.
• V8 Binding(WebIDL Binding)은 WebIDL을 이용해 Auto-generated 된다.
5.
Node.js Native Module과
V8은 어떻게 연결되나?
const fs = require('fs');
let contents = fs.readFileSync('temp.txt', 'utf8');
V8 Engine과 Native Module의 관계
V8 Engine
Node
Runtime
const fs = require('fs');
let contents = fs.readFileSync('temp.txt', 'utf8');
V8 Engine과 Native Module의 관계
V8 Engine
V8 Engine
Node
Runtime
JS Evaluate
const fs = require('fs');
let contents = fs.readFileSync('temp.txt', 'utf8');
V8 Engine과 Native Module의 관계
V8 Engine
Native Module
V8 Engine
V8 Engine
Node
Runtime
JS Evaluate
Actually, called
open() and read()
const fs = require('fs');
let contents = fs.readFileSync('temp.txt', 'utf8');
V8 Engine과 Native Module의 관계
V8 Engine
Native Module
V8 Engine
V8 Engine
Node
Runtime
JS Evaluate
Return JS Wrapper Object
const fs = require('fs');
let contents = fs.readFileSync('temp.txt', 'utf8');
Actually, called
open() and read()
V8 Engine과 Native Module의 관계
V8 Engine
Native Module
V8 Engine
V8 Engine
Node
Runtime
JS Evaluate
Return JS Wrapper Object
V8 Binding
Type Checking/Converting
Manage Isolate and Context
const fs = require('fs');
let contents = fs.readFileSync('temp.txt', 'utf8');
Actually, called
open() and read()
복습: N-API를 사용하여 Binding 해보자
napi_value Sum(napi_env, napi_callback_info info) {
napi_status status;
size_t args = 1;
napi_value args[1];
napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
if (argc < 1) {
napi_throw_type_error(env, nullptr, "…");
return nullptr;
}
uint32_t length = 0;
napi_get_array_length(env, args[0], &length);
double sum = 0;
for (int i = 0; i < length; i++) {
napi_value element;
napi_get_element(env, i, &element);
napi_valuetype valuetype;
napi_typeof(env, element, &valuetype);
if (napi_valuetype != napi_number) {
napi_throw_type_error(env, nullptr, "…");
return nullptr;
}
double value;
napi_get_value_double(env, element, &value);
sum += value;
}
napi_value js_sum;
napi_create_double(env, sum, &js_sum);
return js_sum;
}
이미 우리가 여러번 말했듯이 이러한 과정을 반복한다.
이런식으로 장인 정신을 발휘하면
잘 만들 수 있다!
<script>
document.getElementById(‘hello’);
</script>
복습: V8 Engine과 Blink Engine의 관계
V8 Engine
Blink Engine
V8 Engine
Chromium
Loader
V8 Engine
DOM Parsing
JS Evaluate
WebIDL
Binding
Actually, called
document.getElementById();
Return JS Wrapper Object
let div = document.getElementById(‘hello’);
Auto-generated!!
<div id="hello"></div>
<script>
let div = document.getElementById(‘hello’);
</script>
Node.js에 Auto Binding을 적용한다면..
• IDL을 제외하고는 추가적인 Binding 코드를 직접 작성하지 않아도 된다.
• 바인딩 코드와 실제 User Implementation이 완벽히 분리된다.
• V8(또는 N-API)을 이해하지 않아도 된다.
• 안전하고 빠르게 바인딩할 수 있다.
실제 사례: Open CV Binding
// Open CV Matrix를 생성하는 5개의 함수 오버로딩..
let m1 = new Matrix();
let m2 = new Matrix(rows, cols);
let m3 = new Matrix(10, 20, CV_32F);
let m4 = new Matrix(10, 20, CV_32F, [1, 2, 3]);
let m5 = new Matrix(m4, 10, 20, 30, 40);
실제 사례: Open CV Binding
// 이 Matrix의 실제 Binding 구현은 다음과 유사하다.
// https://github.com/peterbraden/node-opencv/blob/master/src/Matrix.cc#L132
Matrix* mat;
if (info.Length() == 0) {
mat = new Matrix;
} else if (info.Length() == 2 && info[0]->IsInt32() && info[1]->IsInt32()) {
mat = new Matrix(info[0]->IntegerValue(), info[1]->IntegerValue());
} else if (info.Length() == 3 && info[0]->IsInt32() && info[1]->IsInt32() && info[2]->IsInt32()) {
mat = new Matrix(info[0]->IntegerValue(), info[1]->IntegerValue(), info[2]->IntegerValue());
} else if (info.Length() == 4 && info[0]->IsInt32() && info[1]->IsInt32() &&
info[2]->IsInt32() && info[3]->IsArray()) {
mat = new Matrix(info[0]->IntegerValue(), info[1]->IntegerValue(),
info[2]->IntegerValue(), info[3]->ToObject());
else { // if (info.Length() == 5) {
...
}
실제 사례: Open CV Binding
// 만약 WebIDL Binding을 사용했다면..
[
Constructor(),
Constructor(long rows, long cols),
Constructor(long rows, long cols, long type),
Constructor(long rows, long cols, long type, sequence<long> scalar),
Constructor(Matrix m, long x, long y, long z, long w)
]
interface Matrix {
...
};
실제 사례: Open CV Binding
// 만약 당신이 WebIDL 고수였다면..
[
Constructor(),
Constructor(long rows, long cols,
optional long type, optional sequence<long> scalar),
Constructor(Matrix m, long x, long y, long z, long w)
]
interface Matrix {
...
};
요약
• Node.js에서 V8과 Native Module 사이의 Binding은 개발자가 직접 한땀 한땀 개발해
야만 했다.
• Chromium에서 사용되는 WebIDL Binding을 도입한다면, 그러한 장인정신을 발휘하
지 않고도 쉽고 빠르게 개발할 수 있다.
6.
Node.js를 위한
WebIDL Auto Binding
구현하기
What should we do?
• WebIDL을 해석한 후 N-API를 사용하는 적절한 Binding 코드를 생성한다.
Blink에서 WebIDL이 처리 되는 과정
WebIDL
User Native
Implementation
Blink에서 WebIDL이 처리 되는 과정
WebIDL IDL Parser
User Native
Implementation
Input
Blink에서 WebIDL이 처리 되는 과정
WebIDL IDL Parser
Binding Code
GeneratorInput
User Native
Implementation
Blink에서 WebIDL이 처리 되는 과정
WebIDL
Code
Template
IDL Parser
Binding Code
GeneratorInput Input
User Native
Implementation
Blink에서 WebIDL이 처리 되는 과정
WebIDL
Generated Code
Based on V8
Code
Template
IDL Parser
Binding Code
GeneratorInput Input
Build
User Native
Implementation
Blink에서 WebIDL이 처리 되는 과정
WebIDL
Generated Code
Based on V8
Code
Template
IDL Parser
Binding Code
Generator
User Native
Implementation
Input Input
Build
Reference
Blink에서 WebIDL이 처리 되는 과정
WebIDL
Generated Code
Based on V8
Code
Template
IDL Parser
Binding Code
Generator
Output
Binary
User Native
Implementation
Input Input
Build
Build
Reference
Build
What should we do?
• IDL Parser를 구현한다. (Front End)
• Code Generator를 구현한다. (Back End)
How to implement
• IDL Parser를 구현한다. (Front End)
• 이미 잘 구현 된 WebIDL Parser가 있다: https://github.com/w3c/webidl2.js
• 우리는 AST(Abstract Syntax Tree)를 IDL Definitions로 만들어 주는 것만 하면 된다.
• Code Generator를 구현한다. (Back End)
How to implement
• IDL Parser를 구현한다. (Front End)
• 이미 잘 구현 된 WebIDL Parser가 있다: https://github.com/w3c/webidl2.js
• 우리는 AST(Abstract Syntax Tree)를 IDL Definitions로 만들어 주는 것만 하면 된다.
• Code Generator를 구현한다. (Back End)
• Python의 Jinja2를 JS로 포팅 한 Nunjucks가 있다: https://github.com/mozilla/nunjucks
• 우리는 C++ Binding Code (N-API를 사용한)를 잘 생성해주는 로직을 짜기만 하면 된다.
IR
(IDL Definitions)
• Compiler의 FrontEnd의 역할. IR(Intermediate Representation)을 생성.
• Constructing 단계에서 다음의 두가지 요소가 추가적으로 필요함.
• Extended attribute validation
• Dependency resolution.
IDL Parser (Front End)
IDL Tokens
AST
(Abstract Syntax Tree)
Lexing Parsing Constructing
IDL Parser (Front End)
[Constructor]
interface Hello {
double test(World world);
};
[{
type: 'interface',
name: 'Hello',
partial: false,
members: [ [...] ],
inheritance: null,
extAttrs: [ [...] ]
}]
[Constructor]
interface World {
readonly attribute value;
};
Dependency Resolution
Constructing
Parsing
[{
...
name: 'Hello',
members: [ [{
idlType: 'World’,
...
}] ],
}]
Code Generator (Back End)
V8 Engine
Native
Binding Code
IR
(IDL Definitions)
Contexts
Logic
Processing
Template
Processing
Code
Template
• Compiler의 BackEnd의 역할. IR을 Input으로 최종 결과물(binding code) 생성.
• 코드 생성을 위해 Nunjucks Template Engine을 사용.
Code Generator (Back End)
{% for argument in member.arguments %}
auto {{argument.name}} = NativeTypeTraits<IDL{{argument.type | camelcase-}}
>::NativeValue(info.Env(), info[{{loop.index - 1}}]);
{% endfor %}
{% if member.type != "void" %}auto return_value = {% endif %}
{% if member.is_static -%} {{name}}::{% else %} impl_->{% endif %}
{{member.name | camelcase}}({{-member.arguments[0].name-}}
{%- for i in range(1, member.arguments.length) -%}
, {{member.arguments[i].name-}}
{% endfor %});
return JSTypeTraits(info.Env(), return_value);
Code Generator (Back End)
{% for argument in member.arguments %}
auto {{argument.name}} = NativeTypeTraits<IDL{{argument.type | camelcase-}}
>::NativeValue(info.Env(), info[{{loop.index - 1}}]);
{% endfor %}
{% if member.type != "void" %}auto return_value = {% endif %}
{% if member.is_static -%} {{name}}::{% else %} impl_->{% endif %}
{{member.name | camelcase}}({{-member.arguments[0].name-}}
{%- for i in range(1, member.arguments.length) -%}
, {{member.arguments[i].name-}}
{% endfor %});
return JSTypeTraits(info.Env(), return_value);
Code Generator (Back End)
if (info.Length() != 2) {
Napi::RangeError::New(info.Env(), "Invalid").ThrowAsJavaScriptException();
return Napi::Value();
}
// 복잡한 Type Mapping 및 Converting은 개발자에게 노출하지 않는다.
double number1 = NativeTypeTraits<IDLDouble>::NativeValue(info.Env(), info[0]);
double number2 = NativeTypeTraits<IDLDouble>::NativeValue(info.Env(), info[1]);
// 사용자가 작성한 User Native Implementation을 여기서 호출한다.
auto return_value = impl_->Add(number1, number2);
return JSTypeTraits(info.Env(), return_value);
Code Generator (Back End)
class Calculator {
public:
Calculator() {}
// 개발자는 JS Engine의 public API가 어떻게 동작하는지 알 필요가 없다.
// WebIDL Spec에 따라 IDL type이 정확한 platform object type과 mapping된다.
double Add(double number1, double number2) {
return number1 + number2;
}
}
요약
• Node.js에 WebIDL Binding을 구현하기 위해서는 IDL Parser와 Code Generator 두
가지를 구현해야 한다.
7.
Bacardi Project
Introduce Bacardi Project
• Node.js에서 Chromium이 사용하는 WebIDL Auto Binding을 적용하기 위한 오픈소
스 프로젝트입니다.
• https://github.com/lunchclass/bacardi
Introduce Bacardi Project
• Node.js에서 Chromium이 사용하는 WebIDL Auto Binding을 적용하기 위한 오픈소
스 프로젝트입니다.
• https://github.com/lunchclass/bacardi
• Chromium Committer들이 주축으로 만들어 갑니다.
zino@chromium.org hwanseung@chromium.org
How to test Bacardi
# Git clone repository
$ git clone https://github.com/lunchclass/bacardi
How to test Bacardi
# Git clone repository
$ git clone https://github.com/lunchclass/bacardi
# If you are using MacOS
$ xcode-select –install
# If you are using Linux
$ sudo apt-get install g++ git make python wget
How to test Bacardi
# Git clone repository
$ git clone https://github.com/lunchclass/bacardi
# If you are using MacOS
$ xcode-select –install
# If you are using Linux
$ sudo apt-get install g++ git make python wget
# Build & Test
$ ./bacardi build && ./bacardi test
Details
• 자세한 것은 Repository를 참조.
• https://github.com/lunchclass/bacardi
• 테스트가 아닌 간단한 예제는 examples 디렉토리를 참조.
• https://github.com/lunchclass/bacardi/tree/master/examples
Bacardi with Electron
# Build for Electron & Run Electron app
$ ./bacardi build_electron && ./bacardi electron
Bacardi with Electron - SimRank
두 객체의 유사도를 구하는 알고리즘.
Bacardi with Electron - SimRank
만약 여러분이 사용하고 싶은 구현이 Node.js에 존재하지 않는다면..
Bacardi with Electron - SimRank
구글링(Googling)을 해보니 SimRank의 C++ 구현은 존재한다.
• https://github.com/roukaour/simrank
Bacardi with Electron - SimRank
Bacardi with Electron - SimRank
이것을 그대로 Javascript로 binding하여 Electron app에 출력해보자.
• https://github.com/lunchclass/bacardi/pull/135
[
Constructor(),
Constructor(long k, double c)
]
interface ElectronNative {
void addEdge(string head, string tail);
void calculateSimRank();
double similarity(string node1, string node2);
};
Bacardi with Electron - SimRank
Bacardi with Electron - SimRank
Bacardi의 향후 계획
• 2017년 4분기까지 C++ Binding 구현 완료 - NPM 배포
• OpenCV & Tensor Flow Binding Bacardi로 옮기기
• Cross Platform Build 지원
• Welcome to contribution (https://github.com/lunchclass/bacardi)
요약
• Node.js에 WebIDL Binding을 구현하기 위해서는 IDL Parser와 Code Generator 두
가지를 구현해야 한다.
• 모두가 같은 노력을 할 필요 없으므로 오픈소스 프로젝트(Bacardi Project)로 진행중이
며, 이를 Node.js Native Module 개발에 활용할 수 있다.
8.
Binding 성능에 관한 이야기
Native가 JS보다 느릴 수도 있다
• V8은 매우 빠르다.
• V8과 Native Addon을 연결하는 Binding은 생각보다 Overhead가 있다.
• Chromium에서 하드웨어 가속을 써서 ASM + C++을 사용한 Matrix의 구현보다 Pure JS의 구현이 10배
이상 더 빠르다. (관련링크: https://groups.google.com/a/chromium.org/d/msg/blink-dev/V_bJNtOg0oM/lECG9SikFwEJ)
V8 Engine
Native ModuleV8 Engine V8 Binding
Standalone JS Implementation
Native Implementation
Native가 JS보다 느릴 수도 있다
Native가 JS보다 느릴 수도 있다
• Matrix 계산이 Binding Layer를 지나기 위한 Overhead보다 작기 때문에 발생
• 어떤 연산이 Binding Layer의 Overhead보다 작고 빈번히 호출이 된다면 JS가 더 빠를
수도 있다.
V8 Engine
Native ModuleV8 Engine V8 Binding
Standalone JS Implementation
Native Implementation
이 Layer를 많이 지나다닐 수록 성능은 떨어집니다!
이것을 개선하려면?
• 가능하면 한 쪽 World에서 머무르도록 한다.
• uftrace와 같은 프로파일링 툴을 통해 실제 빈번하게 호출되는 지점을 찾을 수 있음.
• https://github.com/namhyung/uftrace
V8 Engine
Native ModuleV8 Engine V8 Binding
Standalone JS Implementation
Native Implementation
이 Layer를 가능하면 적게 지나다니는 것이 Key Point
uftrace를 사용한 call-graph 추적
uftrace를 사용한 call-graph 추적
Native Type
Converting을 위해
Type Checking을 반
복적으로 하고 있음을
알 수 있음.
No Type Checking
// Binding Overhead를 줄이기 위해 NoTypeChecking이라는 Extended Attribute를 추가할 수 있다.
interface PerformanceTest {
[NoTypeChecking] long fibonacci(long n);
};
No Type Checking
// 그러면 Native Code를 생성할 때 TypeChecking을 생략할 수 있다.
// 어떤 Input이 들어올지가 명확하고 예상가능한 경우에 사용할 수 있다.
if (!js_value.IsNumber()) {
Napi::TypeError::New(env, "Invalid").ThrowAsJavaScriptException();
return Napi::Value();
}
ASSERT(info[0].isNumber());
long n = js_value.ToNumber().DoubleValue();
Dictionary Key Caching
• JSObject에 Value를 읽거나 Key값을 체크할 때, napi_has_named_property() 또는
napi_has_property()를 사용할 수 있다.
• https://nodejs.org/dist/latest-v8.x/docs/api/n-api.html#n_api_napi_has_property
• https://nodejs.org/dist/latest-v8.x/docs/api/n-api.html#n_api_napi_has_named_property
• napi_has_named_property() 함수는 napi_has_property()와는 달리 Native
String을 JS String으로 변환해야 하므로 상대적으로 비싼 연산이다.
• 이 문제를 개선하기 위해서 어떤 Object에 Value를 읽거나 Key값을 체크할 때 생성한
JSString을 Native World에서 Caching할 수 있다.
Q & A
Thank you

More Related Content

What's hot

객체지향적인 도메인 레이어 구축하기
객체지향적인 도메인 레이어 구축하기객체지향적인 도메인 레이어 구축하기
객체지향적인 도메인 레이어 구축하기
Young-Ho Cho
 
How to Build a High Performance Application with PHP and Swoole?
How to Build a High Performance Application with PHP and Swoole?How to Build a High Performance Application with PHP and Swoole?
How to Build a High Performance Application with PHP and Swoole?
Albert Chen
 
Spring test mvc 발표자료
Spring test mvc 발표자료Spring test mvc 발표자료
Spring test mvc 발표자료
수홍 이
 

What's hot (20)

고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
 
인프콘 2022 - Rust 크로스 플랫폼 프로그래밍
인프콘 2022 - Rust 크로스 플랫폼 프로그래밍인프콘 2022 - Rust 크로스 플랫폼 프로그래밍
인프콘 2022 - Rust 크로스 플랫폼 프로그래밍
 
객체지향적인 도메인 레이어 구축하기
객체지향적인 도메인 레이어 구축하기객체지향적인 도메인 레이어 구축하기
객체지향적인 도메인 레이어 구축하기
 
Sonatype nexus 로 docker registry 관리하기
Sonatype nexus 로 docker registry 관리하기Sonatype nexus 로 docker registry 관리하기
Sonatype nexus 로 docker registry 관리하기
 
DDD 구현기초 (거의 Final 버전)
DDD 구현기초 (거의 Final 버전)DDD 구현기초 (거의 Final 버전)
DDD 구현기초 (거의 Final 버전)
 
Doxygen 사용법
Doxygen 사용법Doxygen 사용법
Doxygen 사용법
 
심성환 개발자 포트폴리오
심성환 개발자 포트폴리오심성환 개발자 포트폴리오
심성환 개발자 포트폴리오
 
Angular の紹介
Angular の紹介Angular の紹介
Angular の紹介
 
성능 최대화를 위한 CloudFront 설정 Best Practice
성능 최대화를 위한 CloudFront 설정 Best Practice성능 최대화를 위한 CloudFront 설정 Best Practice
성능 최대화를 위한 CloudFront 설정 Best Practice
 
삶이편해지는_백엔드_개발자_지식.pdf
삶이편해지는_백엔드_개발자_지식.pdf삶이편해지는_백엔드_개발자_지식.pdf
삶이편해지는_백엔드_개발자_지식.pdf
 
How to Build a High Performance Application with PHP and Swoole?
How to Build a High Performance Application with PHP and Swoole?How to Build a High Performance Application with PHP and Swoole?
How to Build a High Performance Application with PHP and Swoole?
 
REST API Development with Spring
REST API Development with SpringREST API Development with Spring
REST API Development with Spring
 
스프링5 웹플럭스와 테스트 전략
스프링5 웹플럭스와 테스트 전략스프링5 웹플럭스와 테스트 전략
스프링5 웹플럭스와 테스트 전략
 
이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정
 
파이썬 플라스크 이해하기
파이썬 플라스크 이해하기 파이썬 플라스크 이해하기
파이썬 플라스크 이해하기
 
C# Game Server
C# Game ServerC# Game Server
C# Game Server
 
Explain it to Me Like I’m 5: Oauth2 and OpenID
Explain it to Me Like I’m 5: Oauth2 and OpenIDExplain it to Me Like I’m 5: Oauth2 and OpenID
Explain it to Me Like I’m 5: Oauth2 and OpenID
 
Spring test mvc 발표자료
Spring test mvc 발표자료Spring test mvc 발표자료
Spring test mvc 발표자료
 
初學者都該了解的 HTTP 通訊協定基礎
初學者都該了解的 HTTP 通訊協定基礎初學者都該了解的 HTTP 通訊協定基礎
初學者都該了解的 HTTP 通訊協定基礎
 
Rich domain model
Rich domain modelRich domain model
Rich domain model
 

Viewers also liked

Viewers also liked (20)

[141]네이버랩스의 로보틱스 연구 소개
[141]네이버랩스의 로보틱스 연구 소개[141]네이버랩스의 로보틱스 연구 소개
[141]네이버랩스의 로보틱스 연구 소개
 
[111]open, share, enjoy 네이버의 오픈소스 활동
[111]open, share, enjoy 네이버의 오픈소스 활동[111]open, share, enjoy 네이버의 오픈소스 활동
[111]open, share, enjoy 네이버의 오픈소스 활동
 
밑바닥부터시작하는360뷰어
밑바닥부터시작하는360뷰어밑바닥부터시작하는360뷰어
밑바닥부터시작하는360뷰어
 
[115]14일만에 깃헙 스타 1,000개 받은 차트 오픈소스 개발기
[115]14일만에 깃헙 스타 1,000개 받은 차트 오픈소스 개발기[115]14일만에 깃헙 스타 1,000개 받은 차트 오픈소스 개발기
[115]14일만에 깃헙 스타 1,000개 받은 차트 오픈소스 개발기
 
[143]알파글래스의 개발과정으로 알아보는 ar 스마트글래스 광학 시스템
[143]알파글래스의 개발과정으로 알아보는 ar 스마트글래스 광학 시스템 [143]알파글래스의 개발과정으로 알아보는 ar 스마트글래스 광학 시스템
[143]알파글래스의 개발과정으로 알아보는 ar 스마트글래스 광학 시스템
 
[132]웨일 브라우저 1년 그리고 미래
[132]웨일 브라우저 1년 그리고 미래[132]웨일 브라우저 1년 그리고 미래
[132]웨일 브라우저 1년 그리고 미래
 
[141] 오픈소스를 쓰려는 자, 리베이스의 무게를 견뎌라
[141] 오픈소스를 쓰려는 자, 리베이스의 무게를 견뎌라[141] 오픈소스를 쓰려는 자, 리베이스의 무게를 견뎌라
[141] 오픈소스를 쓰려는 자, 리베이스의 무게를 견뎌라
 
[124]자율주행과 기계학습
[124]자율주행과 기계학습[124]자율주행과 기계학습
[124]자율주행과 기계학습
 
[123]동네 커피샵도 사이렌 오더를 쓸 수 있을까
[123]동네 커피샵도 사이렌 오더를 쓸 수 있을까[123]동네 커피샵도 사이렌 오더를 쓸 수 있을까
[123]동네 커피샵도 사이렌 오더를 쓸 수 있을까
 
[112]clova platform 인공지능을 엮는 기술
[112]clova platform 인공지능을 엮는 기술[112]clova platform 인공지능을 엮는 기술
[112]clova platform 인공지능을 엮는 기술
 
what is_tabs_share
what is_tabs_sharewhat is_tabs_share
what is_tabs_share
 
[135] 오픈소스 데이터베이스, 은행 서비스에 첫발을 내밀다.
[135] 오픈소스 데이터베이스, 은행 서비스에 첫발을 내밀다.[135] 오픈소스 데이터베이스, 은행 서비스에 첫발을 내밀다.
[135] 오픈소스 데이터베이스, 은행 서비스에 첫발을 내밀다.
 
[142] 생체 이해에 기반한 로봇 – 고성능 로봇에게 인간의 유연함과 안전성 부여하기
[142] 생체 이해에 기반한 로봇 – 고성능 로봇에게 인간의 유연함과 안전성 부여하기[142] 생체 이해에 기반한 로봇 – 고성능 로봇에게 인간의 유연함과 안전성 부여하기
[142] 생체 이해에 기반한 로봇 – 고성능 로봇에게 인간의 유연함과 안전성 부여하기
 
웨일브라우저 성능 및 메모리 최적화
웨일브라우저 성능 및 메모리 최적화웨일브라우저 성능 및 메모리 최적화
웨일브라우저 성능 및 메모리 최적화
 
[125] 머신러닝으로 쏟아지는 유저 cs 답변하기
[125] 머신러닝으로 쏟아지는 유저 cs 답변하기[125] 머신러닝으로 쏟아지는 유저 cs 답변하기
[125] 머신러닝으로 쏟아지는 유저 cs 답변하기
 
[113]how can realm_make_efficient_mobile_database
[113]how can realm_make_efficient_mobile_database[113]how can realm_make_efficient_mobile_database
[113]how can realm_make_efficient_mobile_database
 
웨일 보안 이야기
웨일 보안 이야기웨일 보안 이야기
웨일 보안 이야기
 
유연하고 확장성 있는 빅데이터 처리
유연하고 확장성 있는 빅데이터 처리유연하고 확장성 있는 빅데이터 처리
유연하고 확장성 있는 빅데이터 처리
 
[244]네트워크 모니터링 시스템(nms)을 지탱하는 기술
[244]네트워크 모니터링 시스템(nms)을 지탱하는 기술[244]네트워크 모니터링 시스템(nms)을 지탱하는 기술
[244]네트워크 모니터링 시스템(nms)을 지탱하는 기술
 
[216]네이버 검색 사용자를 만족시켜라! 의도파악과 의미검색
[216]네이버 검색 사용자를 만족시켜라!   의도파악과 의미검색[216]네이버 검색 사용자를 만족시켜라!   의도파악과 의미검색
[216]네이버 검색 사용자를 만족시켜라! 의도파악과 의미검색
 

Similar to [131]chromium binging 기술을 node.js에 적용해보자

V8 add on with middleware modules
V8 add on with middleware modulesV8 add on with middleware modules
V8 add on with middleware modules
Jay Kim
 
테크데이 발표자료.pptx.pdf
테크데이 발표자료.pptx.pdf테크데이 발표자료.pptx.pdf
테크데이 발표자료.pptx.pdf
Jihoon Kim
 
Hacosa js study 4주차
Hacosa js study 4주차Hacosa js study 4주차
Hacosa js study 4주차
Seong Bong Ji
 

Similar to [131]chromium binging 기술을 node.js에 적용해보자 (20)

V8 add on with middleware modules
V8 add on with middleware modulesV8 add on with middleware modules
V8 add on with middleware modules
 
코드리뷰 짝 매칭 프로그램 구현기
코드리뷰 짝 매칭 프로그램 구현기코드리뷰 짝 매칭 프로그램 구현기
코드리뷰 짝 매칭 프로그램 구현기
 
막하는 스터디 네 번째 만남 AngularJs (20151108)
막하는 스터디 네 번째 만남 AngularJs (20151108)막하는 스터디 네 번째 만남 AngularJs (20151108)
막하는 스터디 네 번째 만남 AngularJs (20151108)
 
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010
온라인 게임에서 사례로 살펴보는 디버깅 in NDC2010
 
온라인 게임에서 사례로 살펴보는 디버깅 in NDC10
온라인 게임에서 사례로 살펴보는 디버깅 in NDC10온라인 게임에서 사례로 살펴보는 디버깅 in NDC10
온라인 게임에서 사례로 살펴보는 디버깅 in NDC10
 
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
 
HeadFisrt Servlet&JSP Chapter 5
HeadFisrt Servlet&JSP Chapter 5HeadFisrt Servlet&JSP Chapter 5
HeadFisrt Servlet&JSP Chapter 5
 
테크데이 발표자료.pptx.pdf
테크데이 발표자료.pptx.pdf테크데이 발표자료.pptx.pdf
테크데이 발표자료.pptx.pdf
 
Hacosa js study 4주차
Hacosa js study 4주차Hacosa js study 4주차
Hacosa js study 4주차
 
R.java가 사라졌어요 어떻하죠?:Aquery라이브러리와 안드로이드 개발팁
R.java가 사라졌어요 어떻하죠?:Aquery라이브러리와 안드로이드 개발팁R.java가 사라졌어요 어떻하죠?:Aquery라이브러리와 안드로이드 개발팁
R.java가 사라졌어요 어떻하죠?:Aquery라이브러리와 안드로이드 개발팁
 
Web_05_ jQuery
Web_05_ jQueryWeb_05_ jQuery
Web_05_ jQuery
 
[DevOn 2013] Backbone.js로 능동적 M-V 디자인 구현하기
[DevOn 2013] Backbone.js로 능동적  M-V 디자인 구현하기[DevOn 2013] Backbone.js로 능동적  M-V 디자인 구현하기
[DevOn 2013] Backbone.js로 능동적 M-V 디자인 구현하기
 
React native 개발 및 javascript 기본
React native 개발 및 javascript 기본React native 개발 및 javascript 기본
React native 개발 및 javascript 기본
 
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
 
안드로이드 개발자를 위한 스위프트
안드로이드 개발자를 위한 스위프트안드로이드 개발자를 위한 스위프트
안드로이드 개발자를 위한 스위프트
 
Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental system
 
Node.js
Node.jsNode.js
Node.js
 
Secrets of the JavaScript Ninja - Chapter 12. DOM modification
Secrets of the JavaScript Ninja - Chapter 12. DOM modificationSecrets of the JavaScript Ninja - Chapter 12. DOM modification
Secrets of the JavaScript Ninja - Chapter 12. DOM modification
 
Node.js 기본
Node.js 기본Node.js 기본
Node.js 기본
 
Javascript 조금 더 잘 알기
Javascript 조금 더 잘 알기Javascript 조금 더 잘 알기
Javascript 조금 더 잘 알기
 

More from NAVER D2

More from NAVER D2 (20)

[211] 인공지능이 인공지능 챗봇을 만든다
[211] 인공지능이 인공지능 챗봇을 만든다[211] 인공지능이 인공지능 챗봇을 만든다
[211] 인공지능이 인공지능 챗봇을 만든다
 
[233] 대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing: Maglev Hashing Scheduler i...
[233] 대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing: Maglev Hashing Scheduler i...[233] 대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing: Maglev Hashing Scheduler i...
[233] 대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing: Maglev Hashing Scheduler i...
 
[215] Druid로 쉽고 빠르게 데이터 분석하기
[215] Druid로 쉽고 빠르게 데이터 분석하기[215] Druid로 쉽고 빠르게 데이터 분석하기
[215] Druid로 쉽고 빠르게 데이터 분석하기
 
[245]Papago Internals: 모델분석과 응용기술 개발
[245]Papago Internals: 모델분석과 응용기술 개발[245]Papago Internals: 모델분석과 응용기술 개발
[245]Papago Internals: 모델분석과 응용기술 개발
 
[236] 스트림 저장소 최적화 이야기: 아파치 드루이드로부터 얻은 교훈
[236] 스트림 저장소 최적화 이야기: 아파치 드루이드로부터 얻은 교훈[236] 스트림 저장소 최적화 이야기: 아파치 드루이드로부터 얻은 교훈
[236] 스트림 저장소 최적화 이야기: 아파치 드루이드로부터 얻은 교훈
 
[235]Wikipedia-scale Q&A
[235]Wikipedia-scale Q&A[235]Wikipedia-scale Q&A
[235]Wikipedia-scale Q&A
 
[244]로봇이 현실 세계에 대해 학습하도록 만들기
[244]로봇이 현실 세계에 대해 학습하도록 만들기[244]로봇이 현실 세계에 대해 학습하도록 만들기
[244]로봇이 현실 세계에 대해 학습하도록 만들기
 
[243] Deep Learning to help student’s Deep Learning
[243] Deep Learning to help student’s Deep Learning[243] Deep Learning to help student’s Deep Learning
[243] Deep Learning to help student’s Deep Learning
 
[234]Fast & Accurate Data Annotation Pipeline for AI applications
[234]Fast & Accurate Data Annotation Pipeline for AI applications[234]Fast & Accurate Data Annotation Pipeline for AI applications
[234]Fast & Accurate Data Annotation Pipeline for AI applications
 
Old version: [233]대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing
Old version: [233]대형 컨테이너 클러스터에서의 고가용성 Network Load BalancingOld version: [233]대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing
Old version: [233]대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing
 
[226]NAVER 광고 deep click prediction: 모델링부터 서빙까지
[226]NAVER 광고 deep click prediction: 모델링부터 서빙까지[226]NAVER 광고 deep click prediction: 모델링부터 서빙까지
[226]NAVER 광고 deep click prediction: 모델링부터 서빙까지
 
[225]NSML: 머신러닝 플랫폼 서비스하기 & 모델 튜닝 자동화하기
[225]NSML: 머신러닝 플랫폼 서비스하기 & 모델 튜닝 자동화하기[225]NSML: 머신러닝 플랫폼 서비스하기 & 모델 튜닝 자동화하기
[225]NSML: 머신러닝 플랫폼 서비스하기 & 모델 튜닝 자동화하기
 
[224]네이버 검색과 개인화
[224]네이버 검색과 개인화[224]네이버 검색과 개인화
[224]네이버 검색과 개인화
 
[216]Search Reliability Engineering (부제: 지진에도 흔들리지 않는 네이버 검색시스템)
[216]Search Reliability Engineering (부제: 지진에도 흔들리지 않는 네이버 검색시스템)[216]Search Reliability Engineering (부제: 지진에도 흔들리지 않는 네이버 검색시스템)
[216]Search Reliability Engineering (부제: 지진에도 흔들리지 않는 네이버 검색시스템)
 
[214] Ai Serving Platform: 하루 수 억 건의 인퍼런스를 처리하기 위한 고군분투기
[214] Ai Serving Platform: 하루 수 억 건의 인퍼런스를 처리하기 위한 고군분투기[214] Ai Serving Platform: 하루 수 억 건의 인퍼런스를 처리하기 위한 고군분투기
[214] Ai Serving Platform: 하루 수 억 건의 인퍼런스를 처리하기 위한 고군분투기
 
[213] Fashion Visual Search
[213] Fashion Visual Search[213] Fashion Visual Search
[213] Fashion Visual Search
 
[232] TensorRT를 활용한 딥러닝 Inference 최적화
[232] TensorRT를 활용한 딥러닝 Inference 최적화[232] TensorRT를 활용한 딥러닝 Inference 최적화
[232] TensorRT를 활용한 딥러닝 Inference 최적화
 
[242]컴퓨터 비전을 이용한 실내 지도 자동 업데이트 방법: 딥러닝을 통한 POI 변화 탐지
[242]컴퓨터 비전을 이용한 실내 지도 자동 업데이트 방법: 딥러닝을 통한 POI 변화 탐지[242]컴퓨터 비전을 이용한 실내 지도 자동 업데이트 방법: 딥러닝을 통한 POI 변화 탐지
[242]컴퓨터 비전을 이용한 실내 지도 자동 업데이트 방법: 딥러닝을 통한 POI 변화 탐지
 
[212]C3, 데이터 처리에서 서빙까지 가능한 하둡 클러스터
[212]C3, 데이터 처리에서 서빙까지 가능한 하둡 클러스터[212]C3, 데이터 처리에서 서빙까지 가능한 하둡 클러스터
[212]C3, 데이터 처리에서 서빙까지 가능한 하둡 클러스터
 
[223]기계독해 QA: 검색인가, NLP인가?
[223]기계독해 QA: 검색인가, NLP인가?[223]기계독해 QA: 검색인가, NLP인가?
[223]기계독해 QA: 검색인가, NLP인가?
 

Recently uploaded

Grid Layout (Kitworks Team Study 장현정 발표자료)
Grid Layout (Kitworks Team Study 장현정 발표자료)Grid Layout (Kitworks Team Study 장현정 발표자료)
Grid Layout (Kitworks Team Study 장현정 발표자료)
Wonjun Hwang
 

Recently uploaded (7)

MOODv2 : Masked Image Modeling for Out-of-Distribution Detection
MOODv2 : Masked Image Modeling for Out-of-Distribution DetectionMOODv2 : Masked Image Modeling for Out-of-Distribution Detection
MOODv2 : Masked Image Modeling for Out-of-Distribution Detection
 
A future that integrates LLMs and LAMs (Symposium)
A future that integrates LLMs and LAMs (Symposium)A future that integrates LLMs and LAMs (Symposium)
A future that integrates LLMs and LAMs (Symposium)
 
캐드앤그래픽스 2024년 5월호 목차
캐드앤그래픽스 2024년 5월호 목차캐드앤그래픽스 2024년 5월호 목차
캐드앤그래픽스 2024년 5월호 목차
 
Grid Layout (Kitworks Team Study 장현정 발표자료)
Grid Layout (Kitworks Team Study 장현정 발표자료)Grid Layout (Kitworks Team Study 장현정 발표자료)
Grid Layout (Kitworks Team Study 장현정 발표자료)
 
도심 하늘에서 시속 200km로 비행할 수 있는 미래 항공 모빌리티 'S-A2'
도심 하늘에서 시속 200km로 비행할 수 있는 미래 항공 모빌리티 'S-A2'도심 하늘에서 시속 200km로 비행할 수 있는 미래 항공 모빌리티 'S-A2'
도심 하늘에서 시속 200km로 비행할 수 있는 미래 항공 모빌리티 'S-A2'
 
[Terra] Terra Money: Stability and Adoption
[Terra] Terra Money: Stability and Adoption[Terra] Terra Money: Stability and Adoption
[Terra] Terra Money: Stability and Adoption
 
Continual Active Learning for Efficient Adaptation of Machine LearningModels ...
Continual Active Learning for Efficient Adaptation of Machine LearningModels ...Continual Active Learning for Efficient Adaptation of Machine LearningModels ...
Continual Active Learning for Efficient Adaptation of Machine LearningModels ...
 

[131]chromium binging 기술을 node.js에 적용해보자

  • 1. Chromium Binding 기술을 Node.js에 적용해보자! Name: Jinho Bang E-Mail: zino@chromium.org
  • 5. 그런데 이미 Node.js에는 바인딩을 위한 방법들이 제공되고 있다.
  • 6. 그러나 그 방법이 아름답지 않다.
  • 7. 이 세션에서는 그러한 문제를 분석하고
  • 8. 좀 더 아름답게 해결하는 방안을 모색해본다.
  • 9. 1. JS에서 왜 Native Module을 사용하는가?
  • 12. 기존에 잘 만들어진 코드가 Native 일때
  • 13. 어쨌든 Node.js를 사용한다면 사용중인 패키지의 30%는 Native이다.
  • 14. 2. 예제를 통해 알아보는 기존의 Native Module 연동 방식
  • 15. sum()함수를 구현해보자(JS 호출) let s = sum([1, 2, 3, 4, 5, 6, 7, 8, 9]); JS JS function sum(elements) { let s = 0; elements.forEach(element => { s += element; }); return s; }
  • 16. sum()함수를 구현해보자(Native 호출) let s = sum([1, 2, 3, 4, 5, 6, 7, 8, 9]); JS Native int sum(std::vector<int> elements) { int s = 0; for (int i = 0; i < elements.size(); i++) s += elements[i]; return s; } ?
  • 18. 기존의 Native Module 연동 방식 var spawn = require('child_process').spawn; var sum = spawn('sum', [...]); sum.stdout.on('data', result => { process(result); ... }); 아마 우리가 원한게 이런것은 아니지 말입니다..
  • 19. 기존의 Native Module 연동 방식 • Node.js C++ Addon • https://nodejs.org/dist/latest-v8.x/docs/api/addons.html • NAN(Native Abstraction for Node) • Node.js C++ Addon이 V8 Public API를 사용하기 때문에 V8 변화에 민감하다. • Node.js를 업데이트 할때마다 문제가 발생하는 것을 해결. • https://github.com/nodejs/nan • N-API ß Latest! • Node.js 8.0이후부터 지원, 8.6에서 Stable Release • NAN과 유사한 방식이지만, ABI-Stable을 보장. (즉, 재컴파일 불필요) • V8 Public API가 아닌 Node.js에서 한번 Wrapping하여 제공하므로 다른 엔진으로 교체도 가능. • https://nodejs.org/dist/latest-v8.x/docs/api/n-api.html
  • 20. N-API에 이르기까지 많은 개선이 있었지만, Binding 코드를 작성하는 것을 위한 개선은 없었다.
  • 21. N-API를 사용하여 Binding 해보자 napi_value Sum(napi_env, napi_callback_info info) { napi_status status; size_t args = 1; napi_value args[1]; napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); if (argc < 1) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } uint32_t length = 0; napi_get_array_length(env, args[0], &length); double sum = 0; for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); if (napi_valuetype != napi_number) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; } 다음의 예제는 N-API를 사용하여 Native Binding을 하고 있다. 그러나.. 6줄 짜리 sum()함수가 35줄이 된다.
  • 22. N-API를 사용하여 Binding 해보자 const sum = require(‘sum’); let s = sum([1, 2, 3, 4, 5, 6, 7, 8, 9]); N-API를 사용하여 Binding을 하면 Javascript에서 호출 할 수 있다.
  • 24. 지금부터 코드가 많이 나오는데.. 굳이 그 코드들을 이해하실 필요는 없습니다!
  • 25. 문제점1: Argument Check napi_value Sum(napi_env, napi_callback_info info) { napi_status status; size_t args = 1; napi_value args[1]; napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); // 문제점1. JS argument는 Runtime에 결정되므로 개발자가 직접 체크해야한다. if (argc < 1) { napi_throw_type_error(env, nullptr, "…"); return nullptr; }
  • 26. 문제점2: Type Checking for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); // 문제점2. 각 Array Element의 Type Checking도 직접해야한다. napi_valuetype valuetype; napi_typeof(env, element, &valuetype); if (napi_valuetype != napi_number) { napi_throw_type_error(env, nullptr, "…"); return nullptr; }
  • 27. 문제점3: Type Converting // 문제점3. JS에서 Native Type Converting을 직접해야한다. double value; napi_get_value_double(env, element, &value); sum += value; } // 문제점3. Native에서 JS Type Converting을 직접해야한다. napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum;
  • 28. uint32_t length = 10000; for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); ... } 문제점4: Memory Management napi_value length . . . … 내가 아는 Stack Pop Push
  • 29. uint32_t length = 10000; for (int i = 0; i < length; i++) { // napi_get_element()를 호출할 때마다 // 새로운 object를 생성하고 HandleScope에 // 쌓이게 됨. napi_value element; napi_get_element(env, i, &element); ... } 문제점4: Memory Management napi_value napi_value napi_value napi_value napi_value napi_value … napi_value i = 9999 i = 9998 i = 4 i = 3 i = 2 i = 1 i = 0 HandleScopeStack Heap
  • 30. 문제점4: Memory Management for (int i = 0; i < length; i++) { napi_handle_scope scope; napi_status status = napi_open_handle_scope(env, &scope); napi_value element; napi_get_element(env, i, &element); ... napi_close_handle_scope(env, scope); }
  • 31. 문제점5: Readability napi_value Sum(napi_env, napi_callback_info info) { napi_status status; size_t args = 1; napi_value args[1]; napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); if (argc < 1) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } uint32_t length = 0; napi_get_array_length(env, args[0], &length); double sum = 0; for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); if (napi_valuetype != napi_number) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; } int sum(std::vector<int> elements) { int s = 0; for (int i = 0; i < elements.size(); i++) s += elements[i]; return s; } // 문제점5. Binding 코드가 많이 삽입되면서 가독성이 떨어진다.
  • 32. 요약 • 기존의 방법은 TypeChecking/Converting과 같은 노가다를 반복해야 한다. • Memory 관리 Mechanism이 다르고 Binding을 위해 사용되는 API를 다룰 줄 알아야 하므로 V8, N-API, JS, C++과 같은 지식 모두를 필요로 한다. • 전체적인 코드의 복잡도가 증가한다.
  • 35. Chromium은 V8의 또 다른 Embedder이다.
  • 36. ♥ ≡ ♥ Blink (Rendering Engine) V8 (Javascript Engine) Node.js Native Module V8 (Javascript Engine)
  • 38. <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>
  • 39. V8 Engine과 Blink Engine의 관계 V8 Engine Chromium Loader <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>
  • 40. V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader DOM Parsing <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>
  • 41. V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing <script> document.getElementById(‘hello’); </script> JS Evaluate <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>
  • 42. V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing JS Evaluate Actually, called document.getElementById(); <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script> <script> document.getElementById(‘hello’); </script>
  • 43. V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing JS Evaluate Actually, called document.getElementById(); Return JS Wrapper Object let div = document.getElementById(‘hello’); <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script> <script> document.getElementById(‘hello’); </script>
  • 44. <script> document.getElementById(‘hello’); </script> V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing JS Evaluate V8 Binding Actually, called document.getElementById(); Return JS Wrapper Object let div = document.getElementById(‘hello’); Type Checking/Converting Manage Isolate and Context <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>
  • 45. <script> document.getElementById(‘hello’); </script> V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing JS Evaluate WebIDL Binding Actually, called document.getElementById(); Return JS Wrapper Object let div = document.getElementById(‘hello’); Auto-generated!! <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>
  • 46. V8 Binding이란? • Chromium에서 V8과 Blink를 연결하는 코드이다. • 사용자가 직접 짜지 않고 WebIDL으로부터 자동 생성(auto-generation)된다. • WebIDL은 JS Engine과 Web Engine을 연결하는 Web 표준에 의해 정의된다. • https://heycam.github.io/webidl/ • https://www.w3.org/TR/api-design/
  • 47. 코드레벨로 살펴보는 WebIDL // WebIDL [Constructor] interface Calculator { double sum(sequence<long> elements); };
  • 48. 코드레벨로 살펴보는 WebIDL // WebIDL [Constructor] interface Calculator { double sum(sequence<long> elements); }; napi_value Sum(napi_env, napi_callback_info info) { napi_status status; size_t args = 1; napi_value args[1]; napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); if (argc < 1) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } uint32_t length = 0; napi_get_array_length(env, args[0], &length); double sum = 0; for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); if (napi_valuetype != napi_number) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; } VS
  • 49. 코드레벨로 살펴보는 WebIDL // User’s Native Code class Calculator { public: double Sum(std::vector<int> elements) { int sum = 0; for (int i = 0; i < elements.size(); i++) sum += elements[i]; return sum; } };
  • 50. 코드레벨로 살펴보는 WebIDL // User’s JS code var calculator = new Calculator(); console.log(calculator.sum([1, 2, 3, 4, 5, 6, 7, 8, 9]));
  • 51. 요약 • Chromium에서 V8과 Blink의 관계는 Node.js에서 V8과 Native Module의 관계와 동 등하다. • V8과 Blink를 연결하는 Layer를 V8 Binding(WebIDL Binding)이라고 부른다. • V8 Binding(WebIDL Binding)은 WebIDL을 이용해 Auto-generated 된다.
  • 52. 5. Node.js Native Module과 V8은 어떻게 연결되나?
  • 53. const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8');
  • 54. V8 Engine과 Native Module의 관계 V8 Engine Node Runtime const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8');
  • 55. V8 Engine과 Native Module의 관계 V8 Engine V8 Engine Node Runtime JS Evaluate const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8');
  • 56. V8 Engine과 Native Module의 관계 V8 Engine Native Module V8 Engine V8 Engine Node Runtime JS Evaluate Actually, called open() and read() const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8');
  • 57. V8 Engine과 Native Module의 관계 V8 Engine Native Module V8 Engine V8 Engine Node Runtime JS Evaluate Return JS Wrapper Object const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8'); Actually, called open() and read()
  • 58. V8 Engine과 Native Module의 관계 V8 Engine Native Module V8 Engine V8 Engine Node Runtime JS Evaluate Return JS Wrapper Object V8 Binding Type Checking/Converting Manage Isolate and Context const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8'); Actually, called open() and read()
  • 59. 복습: N-API를 사용하여 Binding 해보자 napi_value Sum(napi_env, napi_callback_info info) { napi_status status; size_t args = 1; napi_value args[1]; napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); if (argc < 1) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } uint32_t length = 0; napi_get_array_length(env, args[0], &length); double sum = 0; for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); if (napi_valuetype != napi_number) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; } 이미 우리가 여러번 말했듯이 이러한 과정을 반복한다. 이런식으로 장인 정신을 발휘하면 잘 만들 수 있다!
  • 60. <script> document.getElementById(‘hello’); </script> 복습: V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing JS Evaluate WebIDL Binding Actually, called document.getElementById(); Return JS Wrapper Object let div = document.getElementById(‘hello’); Auto-generated!! <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>
  • 61. Node.js에 Auto Binding을 적용한다면.. • IDL을 제외하고는 추가적인 Binding 코드를 직접 작성하지 않아도 된다. • 바인딩 코드와 실제 User Implementation이 완벽히 분리된다. • V8(또는 N-API)을 이해하지 않아도 된다. • 안전하고 빠르게 바인딩할 수 있다.
  • 62. 실제 사례: Open CV Binding // Open CV Matrix를 생성하는 5개의 함수 오버로딩.. let m1 = new Matrix(); let m2 = new Matrix(rows, cols); let m3 = new Matrix(10, 20, CV_32F); let m4 = new Matrix(10, 20, CV_32F, [1, 2, 3]); let m5 = new Matrix(m4, 10, 20, 30, 40);
  • 63. 실제 사례: Open CV Binding // 이 Matrix의 실제 Binding 구현은 다음과 유사하다. // https://github.com/peterbraden/node-opencv/blob/master/src/Matrix.cc#L132 Matrix* mat; if (info.Length() == 0) { mat = new Matrix; } else if (info.Length() == 2 && info[0]->IsInt32() && info[1]->IsInt32()) { mat = new Matrix(info[0]->IntegerValue(), info[1]->IntegerValue()); } else if (info.Length() == 3 && info[0]->IsInt32() && info[1]->IsInt32() && info[2]->IsInt32()) { mat = new Matrix(info[0]->IntegerValue(), info[1]->IntegerValue(), info[2]->IntegerValue()); } else if (info.Length() == 4 && info[0]->IsInt32() && info[1]->IsInt32() && info[2]->IsInt32() && info[3]->IsArray()) { mat = new Matrix(info[0]->IntegerValue(), info[1]->IntegerValue(), info[2]->IntegerValue(), info[3]->ToObject()); else { // if (info.Length() == 5) { ... }
  • 64. 실제 사례: Open CV Binding // 만약 WebIDL Binding을 사용했다면.. [ Constructor(), Constructor(long rows, long cols), Constructor(long rows, long cols, long type), Constructor(long rows, long cols, long type, sequence<long> scalar), Constructor(Matrix m, long x, long y, long z, long w) ] interface Matrix { ... };
  • 65. 실제 사례: Open CV Binding // 만약 당신이 WebIDL 고수였다면.. [ Constructor(), Constructor(long rows, long cols, optional long type, optional sequence<long> scalar), Constructor(Matrix m, long x, long y, long z, long w) ] interface Matrix { ... };
  • 66. 요약 • Node.js에서 V8과 Native Module 사이의 Binding은 개발자가 직접 한땀 한땀 개발해 야만 했다. • Chromium에서 사용되는 WebIDL Binding을 도입한다면, 그러한 장인정신을 발휘하 지 않고도 쉽고 빠르게 개발할 수 있다.
  • 67. 6. Node.js를 위한 WebIDL Auto Binding 구현하기
  • 68. What should we do? • WebIDL을 해석한 후 N-API를 사용하는 적절한 Binding 코드를 생성한다.
  • 69. Blink에서 WebIDL이 처리 되는 과정 WebIDL User Native Implementation
  • 70. Blink에서 WebIDL이 처리 되는 과정 WebIDL IDL Parser User Native Implementation Input
  • 71. Blink에서 WebIDL이 처리 되는 과정 WebIDL IDL Parser Binding Code GeneratorInput User Native Implementation
  • 72. Blink에서 WebIDL이 처리 되는 과정 WebIDL Code Template IDL Parser Binding Code GeneratorInput Input User Native Implementation
  • 73. Blink에서 WebIDL이 처리 되는 과정 WebIDL Generated Code Based on V8 Code Template IDL Parser Binding Code GeneratorInput Input Build User Native Implementation
  • 74. Blink에서 WebIDL이 처리 되는 과정 WebIDL Generated Code Based on V8 Code Template IDL Parser Binding Code Generator User Native Implementation Input Input Build Reference
  • 75. Blink에서 WebIDL이 처리 되는 과정 WebIDL Generated Code Based on V8 Code Template IDL Parser Binding Code Generator Output Binary User Native Implementation Input Input Build Build Reference Build
  • 76. What should we do? • IDL Parser를 구현한다. (Front End) • Code Generator를 구현한다. (Back End)
  • 77. How to implement • IDL Parser를 구현한다. (Front End) • 이미 잘 구현 된 WebIDL Parser가 있다: https://github.com/w3c/webidl2.js • 우리는 AST(Abstract Syntax Tree)를 IDL Definitions로 만들어 주는 것만 하면 된다. • Code Generator를 구현한다. (Back End)
  • 78. How to implement • IDL Parser를 구현한다. (Front End) • 이미 잘 구현 된 WebIDL Parser가 있다: https://github.com/w3c/webidl2.js • 우리는 AST(Abstract Syntax Tree)를 IDL Definitions로 만들어 주는 것만 하면 된다. • Code Generator를 구현한다. (Back End) • Python의 Jinja2를 JS로 포팅 한 Nunjucks가 있다: https://github.com/mozilla/nunjucks • 우리는 C++ Binding Code (N-API를 사용한)를 잘 생성해주는 로직을 짜기만 하면 된다.
  • 79. IR (IDL Definitions) • Compiler의 FrontEnd의 역할. IR(Intermediate Representation)을 생성. • Constructing 단계에서 다음의 두가지 요소가 추가적으로 필요함. • Extended attribute validation • Dependency resolution. IDL Parser (Front End) IDL Tokens AST (Abstract Syntax Tree) Lexing Parsing Constructing
  • 80. IDL Parser (Front End) [Constructor] interface Hello { double test(World world); }; [{ type: 'interface', name: 'Hello', partial: false, members: [ [...] ], inheritance: null, extAttrs: [ [...] ] }] [Constructor] interface World { readonly attribute value; }; Dependency Resolution Constructing Parsing [{ ... name: 'Hello', members: [ [{ idlType: 'World’, ... }] ], }]
  • 81. Code Generator (Back End) V8 Engine Native Binding Code IR (IDL Definitions) Contexts Logic Processing Template Processing Code Template • Compiler의 BackEnd의 역할. IR을 Input으로 최종 결과물(binding code) 생성. • 코드 생성을 위해 Nunjucks Template Engine을 사용.
  • 82. Code Generator (Back End) {% for argument in member.arguments %} auto {{argument.name}} = NativeTypeTraits<IDL{{argument.type | camelcase-}} >::NativeValue(info.Env(), info[{{loop.index - 1}}]); {% endfor %} {% if member.type != "void" %}auto return_value = {% endif %} {% if member.is_static -%} {{name}}::{% else %} impl_->{% endif %} {{member.name | camelcase}}({{-member.arguments[0].name-}} {%- for i in range(1, member.arguments.length) -%} , {{member.arguments[i].name-}} {% endfor %}); return JSTypeTraits(info.Env(), return_value);
  • 83. Code Generator (Back End) {% for argument in member.arguments %} auto {{argument.name}} = NativeTypeTraits<IDL{{argument.type | camelcase-}} >::NativeValue(info.Env(), info[{{loop.index - 1}}]); {% endfor %} {% if member.type != "void" %}auto return_value = {% endif %} {% if member.is_static -%} {{name}}::{% else %} impl_->{% endif %} {{member.name | camelcase}}({{-member.arguments[0].name-}} {%- for i in range(1, member.arguments.length) -%} , {{member.arguments[i].name-}} {% endfor %}); return JSTypeTraits(info.Env(), return_value);
  • 84. Code Generator (Back End) if (info.Length() != 2) { Napi::RangeError::New(info.Env(), "Invalid").ThrowAsJavaScriptException(); return Napi::Value(); } // 복잡한 Type Mapping 및 Converting은 개발자에게 노출하지 않는다. double number1 = NativeTypeTraits<IDLDouble>::NativeValue(info.Env(), info[0]); double number2 = NativeTypeTraits<IDLDouble>::NativeValue(info.Env(), info[1]); // 사용자가 작성한 User Native Implementation을 여기서 호출한다. auto return_value = impl_->Add(number1, number2); return JSTypeTraits(info.Env(), return_value);
  • 85. Code Generator (Back End) class Calculator { public: Calculator() {} // 개발자는 JS Engine의 public API가 어떻게 동작하는지 알 필요가 없다. // WebIDL Spec에 따라 IDL type이 정확한 platform object type과 mapping된다. double Add(double number1, double number2) { return number1 + number2; } }
  • 86. 요약 • Node.js에 WebIDL Binding을 구현하기 위해서는 IDL Parser와 Code Generator 두 가지를 구현해야 한다.
  • 88. Introduce Bacardi Project • Node.js에서 Chromium이 사용하는 WebIDL Auto Binding을 적용하기 위한 오픈소 스 프로젝트입니다. • https://github.com/lunchclass/bacardi
  • 89. Introduce Bacardi Project • Node.js에서 Chromium이 사용하는 WebIDL Auto Binding을 적용하기 위한 오픈소 스 프로젝트입니다. • https://github.com/lunchclass/bacardi • Chromium Committer들이 주축으로 만들어 갑니다. zino@chromium.org hwanseung@chromium.org
  • 90. How to test Bacardi # Git clone repository $ git clone https://github.com/lunchclass/bacardi
  • 91. How to test Bacardi # Git clone repository $ git clone https://github.com/lunchclass/bacardi # If you are using MacOS $ xcode-select –install # If you are using Linux $ sudo apt-get install g++ git make python wget
  • 92. How to test Bacardi # Git clone repository $ git clone https://github.com/lunchclass/bacardi # If you are using MacOS $ xcode-select –install # If you are using Linux $ sudo apt-get install g++ git make python wget # Build & Test $ ./bacardi build && ./bacardi test
  • 93. Details • 자세한 것은 Repository를 참조. • https://github.com/lunchclass/bacardi • 테스트가 아닌 간단한 예제는 examples 디렉토리를 참조. • https://github.com/lunchclass/bacardi/tree/master/examples
  • 94. Bacardi with Electron # Build for Electron & Run Electron app $ ./bacardi build_electron && ./bacardi electron
  • 95. Bacardi with Electron - SimRank 두 객체의 유사도를 구하는 알고리즘.
  • 96. Bacardi with Electron - SimRank 만약 여러분이 사용하고 싶은 구현이 Node.js에 존재하지 않는다면..
  • 97. Bacardi with Electron - SimRank 구글링(Googling)을 해보니 SimRank의 C++ 구현은 존재한다. • https://github.com/roukaour/simrank
  • 99. Bacardi with Electron - SimRank 이것을 그대로 Javascript로 binding하여 Electron app에 출력해보자. • https://github.com/lunchclass/bacardi/pull/135 [ Constructor(), Constructor(long k, double c) ] interface ElectronNative { void addEdge(string head, string tail); void calculateSimRank(); double similarity(string node1, string node2); };
  • 100. Bacardi with Electron - SimRank
  • 101. Bacardi with Electron - SimRank
  • 102. Bacardi의 향후 계획 • 2017년 4분기까지 C++ Binding 구현 완료 - NPM 배포 • OpenCV & Tensor Flow Binding Bacardi로 옮기기 • Cross Platform Build 지원 • Welcome to contribution (https://github.com/lunchclass/bacardi)
  • 103. 요약 • Node.js에 WebIDL Binding을 구현하기 위해서는 IDL Parser와 Code Generator 두 가지를 구현해야 한다. • 모두가 같은 노력을 할 필요 없으므로 오픈소스 프로젝트(Bacardi Project)로 진행중이 며, 이를 Node.js Native Module 개발에 활용할 수 있다.
  • 105. Native가 JS보다 느릴 수도 있다 • V8은 매우 빠르다. • V8과 Native Addon을 연결하는 Binding은 생각보다 Overhead가 있다. • Chromium에서 하드웨어 가속을 써서 ASM + C++을 사용한 Matrix의 구현보다 Pure JS의 구현이 10배 이상 더 빠르다. (관련링크: https://groups.google.com/a/chromium.org/d/msg/blink-dev/V_bJNtOg0oM/lECG9SikFwEJ) V8 Engine Native ModuleV8 Engine V8 Binding Standalone JS Implementation Native Implementation
  • 106. Native가 JS보다 느릴 수도 있다
  • 107. Native가 JS보다 느릴 수도 있다 • Matrix 계산이 Binding Layer를 지나기 위한 Overhead보다 작기 때문에 발생 • 어떤 연산이 Binding Layer의 Overhead보다 작고 빈번히 호출이 된다면 JS가 더 빠를 수도 있다. V8 Engine Native ModuleV8 Engine V8 Binding Standalone JS Implementation Native Implementation 이 Layer를 많이 지나다닐 수록 성능은 떨어집니다!
  • 108. 이것을 개선하려면? • 가능하면 한 쪽 World에서 머무르도록 한다. • uftrace와 같은 프로파일링 툴을 통해 실제 빈번하게 호출되는 지점을 찾을 수 있음. • https://github.com/namhyung/uftrace V8 Engine Native ModuleV8 Engine V8 Binding Standalone JS Implementation Native Implementation 이 Layer를 가능하면 적게 지나다니는 것이 Key Point
  • 110. uftrace를 사용한 call-graph 추적 Native Type Converting을 위해 Type Checking을 반 복적으로 하고 있음을 알 수 있음.
  • 111. No Type Checking // Binding Overhead를 줄이기 위해 NoTypeChecking이라는 Extended Attribute를 추가할 수 있다. interface PerformanceTest { [NoTypeChecking] long fibonacci(long n); };
  • 112. No Type Checking // 그러면 Native Code를 생성할 때 TypeChecking을 생략할 수 있다. // 어떤 Input이 들어올지가 명확하고 예상가능한 경우에 사용할 수 있다. if (!js_value.IsNumber()) { Napi::TypeError::New(env, "Invalid").ThrowAsJavaScriptException(); return Napi::Value(); } ASSERT(info[0].isNumber()); long n = js_value.ToNumber().DoubleValue();
  • 113. Dictionary Key Caching • JSObject에 Value를 읽거나 Key값을 체크할 때, napi_has_named_property() 또는 napi_has_property()를 사용할 수 있다. • https://nodejs.org/dist/latest-v8.x/docs/api/n-api.html#n_api_napi_has_property • https://nodejs.org/dist/latest-v8.x/docs/api/n-api.html#n_api_napi_has_named_property • napi_has_named_property() 함수는 napi_has_property()와는 달리 Native String을 JS String으로 변환해야 하므로 상대적으로 비싼 연산이다. • 이 문제를 개선하기 위해서 어떤 Object에 Value를 읽거나 Key값을 체크할 때 생성한 JSString을 Native World에서 Caching할 수 있다.
  • 114. Q & A