Realm은 어떻게 효율적인
 데이터베이스를 만들었나?

https://deview.kr/2017/schedule/206


Realm은 SQLite만 사용되던 모바일 데이터베이스 시장에서 혁신적인 대안으로 평가받고있는 오픈소스 데이터베이스 입니다. 현재 10만명 이상의 개발자들이 개발에 사용하고있고, 20억대 이상의 디바이스에 설치되어 있습니다. 


Realm을 빠르고 효율적인 데이터베이스로 만들기 위해 사용되었던 여러 기술과 고려되었던 여러 사안들이 있습니다. Realm이 이슈들을 어떤 방법으로 대처해왔는지를 살피고 거기에서 응용과 프레임워크 개발에서 얻을 수 있는 교훈을 살펴봅시다.




how can realm_make_efficient_mobile_database

1. Realm은 어떻게 효율적인 데이터베이스를 만들었나? Leonardo YongUk Kim Java team

2. GreenDao ORMLite SQLite Realm

3. 첫번째 비결 Zero copy

4. Zero copy “최대한 복제를 미루는 것입니 다.”

5. 왜 Zero copy인가? 

public class City { private String name; private long votes; 

public String getName() { return name; } 

public void setName(String name) { this.name = name; } 

public long getVotes() { return votes; } 

public void setVotes(long votes) { this.votes = votes; } } 

제로 카피 없는 세상을 생각해 봅시다.

6. 왜 Zero copy인가? 

public class City { 

private String name; private long votes; 

public String getName() { return name; } 

public void setName(String name) { this.name = name; } 

public long getVotes() { return votes; } 

public void setVotes(long votes) { this.votes = votes; }

 }

ORM이나 JSON 파서가 채워줘야 해요. 

ORM이나 JSON 파서가 채워줘야 해요.

7. 왜 Zero copy인가? public class City { private String name; private long votes; public String getName() { return name; } public void setName(String name) { this.name = name; } public long getVotes() { return votes; } public void setVotes(long votes) { this.votes = votes; } } public List<City> hydrate() { List<City> results = new ArrayList<>(); while (hasNextItem) { City c = new City(); c.setName(name); c.setVotes(votes); results.add(c); } return results; } 너가 뭘 쓸지 몰라서 다 준비했어요.

8. 왜 Zero copy인가? public List<City> hydrate() { List<City> results = new ArrayList<>(); while (hasNextItem) { City c = new City(); c.setName(name); c.setVotes(votes); /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ results.add(c); } return results; } 너가 뭘 쓸지 몰라서 다 준비했어요. 수화라고 번역합니다. 객체의 필드를 채우는 일입니다.

9. 왜 Zero copy인가? public List<City> hydrate() { List<City> results = new ArrayList<>(); while (hasNextItem) { City c = new City(); c.setName(String.valueOf(name)); c.setVotes(Integer.parseInt(votes)); /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ results.add(c); } return results; } 어쩌면 매번 변환이 필요할지 몰라Yo~!

10. 왜 Zero copy인가? public class City { private String name; private long votes; public String getName() { return name; } public void setName(String name) { this.name = name; } public long getVotes() { return votes; } public void setVotes(long votes) { this.votes = votes; } } 만약에 사용자가 getName만 필요하면? votes값의 변환과 설정은 필요없는 것 아닌가?

11. 왜 Zero copy인가? public class City { private String name; private long votes; private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } public long getVotes() { return votes; } public void setVotes(long votes) { this.votes = votes; } } row에서 해당 column만 이제 가져옵시다. name을 채우지 맙시다. row의 해당 column에 기록합니다. “사용하지 않을지 모르는 항목을 위한 작업을 최대한 뒤로 미루자.”

12. 보일러플레이트

13. 보일러플레이트 public class City { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 프로그래머에게 직관적인 코드

14. 보일러플레이트 public class City { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class LazyCity { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 프로그래머에게 비관적인 코드 꼭 이렇게 짜야하나요?

15. 보일러플레이트 public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City{ private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 반복적인 작업은 기계에게 맡겨야 합니다. “Annotation Processing Tool (APT)” 생성된 클래스는 모두 RealmProxy가 붙습니다.Realm 객체는 RealmObject를 상속 받습니다.

16. 반복적인 작업은 기계에게 맡겨야 합니다.

 “Annotation Processing Tool (APT)” 

“어노테이션 프로세싱 툴은 어노테이션으로 부터 새로운 객체를 생성합니다.”


17. Man vs Code 

City CityRealmProx y 사용자의 원본 객체 (RealmObject) 기계가 생성한 객체 (RealmProxy) 어노테이션 프로세싱 툴 (APT)


18. Man vs Code Realm의 APT는 AbstractProcessor를 상속한 RealmProcessor로 구현됩니다. AbstractProcessor +process(annotations, roundEnv) RealmProcessor RealmObject RealmProxy RealmObject RealmProxy RealmObject RealmProxy

19. Man vs Code writer.emitAnnotation("Override") .beginMethod( "void", // return type "copy", // method name EnumSet.of(Modifier.PROTECTED, Modifier.FINAL), // modifiers "ColumnInfo", "rawSrc", "ColumnInfo", "rawDst"); // parameters writer.emitStatement("final %1$s src = (%1$s) rawSrc", columnInfoClassName()); writer.emitStatement("final %1$s dst = (%1$s) rawDst", columnInfoClassName()); for (VariableElement variableElement : metadata.getFields()) { writer.emitStatement("dst.%1$s = src.%1$s", columnIndexVarName(variableElement)); } writer.endMethod(); “마법은 없습니다. Java 코드를 생성하는 것은 고통스러운 일입니다.”

20. Man vs Code “마법은 없습니다. Java 코드를 생성하는 것은 고통스러운 일입니다.” 1. StringBuilder 2. Template engines 1. Apache Velocity (7년만에 부활) 2. Apache FreeMaker 3. Pebble Template Engine 4. Thymeleaf Template Engine 3. Code generators 1. JavaPoet 2. JavaWriter (개발 중단. Java Poet이 후속작) 3. jcodemodel (2005년 경부터 개발 중단) 당신은 용자 코드도 찍어내면 그만? 내가 코드를 짜는 건지 코드가 날 짜는 건지. 튜토리얼이 많은 애가 개발이 잘 안돼. 그래도 스퀘어가 제일 낫지 않나?

21. APT가 해법인가?

22. APT가 해법인가? public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } APT는 어떤 메서드가 어떤 역할인지 이해하지 못합니다.

23. APT가 해법인가? public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 암묵적인 컨벤션을 가정합니다. 구 버전의 Realm에서는 항상 표준적인 이름의 getter와 setter를 강제합니다. name이란 필드에 대해 getName과 setName을 쓰지 않을까요?

24. APT가 해법인가? public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 부모가 name 필드와 어떤 상호작용을 하고 있을지 예상할 수 없습니다. 구 버전의 Realm은 커스텀 동작을 금지하고 부모 클래스의 동작을 무시했습니다. City의 getName은 어떤 부가 작업을 하고 있을까요? City의 setName은 어떤 부가 작업을 하고 있을까요?

25. 바이트 코드 뒤집기

26. 바이트 코드 뒤집기 City name CityRealmProx y CityRealmProxyInterface +realmGet$name: String +realmSet$name(name) ZeroCopy관련 객체를 위한 인터페이스 name 필드에 접근하는 모든 코드 대신 realmGet$name과 realmSet$name이 호출되도록 변조합 니다. realmGet$name과 realmSet$name를 오버라이드해서 Zero copy 부분을 구현합니다. APT로 코드 생성 인터페이스 구현

27. 바이트 코드 뒤집기 public class CityRealmProxy extends City implements CityRealmProxyInterface { private final int COLUMN_NAME = 0; public String realmGet$name() { return (String) getRow().getSting(COLUMN_NAME); } public void realmSet$Name(String name) { getRow().setString(COLUMN_NAME, name); } } 내부용 게터와 세터는 RealmProxy 아래 생성됩니다.

28. 바이트 코드 뒤집기 public class City implements CityRealmProxyInterface { private String name; public String getName() { return (String) realmGet$name(); } public void setName(String name) { realmSet$name(name); } public String realmGet$name() { return name; } public void realmSet$Name(String name) { this.name = name; } } “바이트코드가 변조된 City객체 입니다.” public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }

29. 바이트 코드 뒤집기 public class City implements CityRealmProxyInterface { public String name; public String realmGet$name() { return name; } public void realmSet$Name(String name) { this.name = name; } } “이제는 getter와 setter가 없어도 됩니다.” public class City extends RealmObject { public String name; } name 필드에 대한 접근은 모두 게터와 세터 호출로 변경됩니다.

30. 바이트 코드 뒤집기 City CIty 사용자가 생성한 객체 바이트 코드 변조된 객체 Transformer “Transformer는 빌드된 결과를 변조합니다.”

31. 바이트 코드 뒤집기 class RealmTransformer extends Transform { @Override void transform(Context context, Collection<TransformInput> inputs, Collection<TransformInput> referencedInputs, TransformOutputProvider outputProvider, boolean isIncremental) throws IOException, TransformException, InterruptedException { … } } 이 트랜스포머가 필드에 대한 접근들을 모두 Realm의 게터와 세터로 변조합니다.

32. 바이트 코드 뒤집기 “마법은 없습니다. 바이트 코드를 변조하는 것은 고통스러운 일입니다.” 1. ASM 2. BCEL 3. CGLIB 4. Javassist 5. AspectJ 중간 정도 난이도의 도구. Realm이 사용.

33. 다른 DB도 Zero copy?

34. 다른 DB도 Zero copy? SQLite 시스템 적인 경계 Object Object Object Object Object Object ORM

35. 다른 DB도 Zero copy? SQLite 시스템 적인 경계 Object Object Object Object Object Object ORM 이 영역까지만 lazy하게 미룰 수 있음.

36. 다른 DB도 Zero copy? SQLite 시스템 적인 경계 Object Object Object Object Object Object ORM 경계를 넘어서 lazy한 처리는 어려움.

37. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; “Realm은 생각보다 더 게으릅니다.”

38. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; Realm 은 오프셋도 리미트도 없습니다.

39. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; 이 시점에서는 실제 데이터를 받아오지 않습니다. 실제 데이터를 가지고 있지 않기 때문에 특수한 리스트 구조를 가지고 있습 니다.

40. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; 이 시점에 첫 번째 사람에 대한 메타 데이터만 가지고 옵니다.

41. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; 이 시점에 첫 번째 사람의 정보 중 name만 접근합니다.

42. 더 많은 Zero copy 가능성 Realm은 lazy하게 동작하기 위해 특별한 클래스를 가집니다. 1. RealmObject 2. RealmResults 3. RealmList DB 엔진의 지원 때문에 전체적으로 게을러질 수 있습니다.

43. 조금 더 빨라지기 위 해

44. 조금 더 빨라지기 위해 final RealmResults<Person> people = realm.where(Person.class).findAll(); for (Person person : people) { final String name = person.name; } 객체의 전체 필드가 필요한 경우는 드뭅니다. 모바일 데이터베이스의 특징을 생각해봅시다.

45. 조금 더 빨라지기 위해 10 30 40 3 4 6 10 Row 3 전통적인 Row 우선 B-Tree리프가 10번째 Row까지 가진다는 것을 의미 nam e votes 패딩 리프는 보통 연속된 Array Row에 속한 모든 Column

46. 조금 더 빨라지기 위해 10 30 40 3 4 6 10 Row 3 연속된 name 검색 nam e votes 패딩 인접한 데이터는 name이 아니다.

47. 조금 더 빨라지기 위해 캐시를 생각해봅시다. (3회 적중) nam e votes 패딩 nam e votes 패딩 nam e votes 패딩 nam e votes 패딩 캐시 라인 캐시 히트 캐시 미스

48. 조금 더 빨라지기 위해 구조를 컬럼 기준으로 바꾸어봅시다. nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e 캐시 라인

49. 조금 더 빨라지기 위해 구조를 컬럼 기준으로 바꾸어봅시다. (12회 적중) nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e 캐시 라인 캐시 히트 캐시 미스

50. 조금 더 빨라지기 위해 4 8 12 Realm의 Column 우선 B-Tree nam e nam e nam e nam e 리프가 4번째 컬럼까지 가진다는 것을 의미 동질적인 데이터이기에 예측가능한 사이즈

51. 4 8 12 Realm의 전체 트리 nam e nam e nam e nam e nam e votes Perso n Group (DB와 같은 개념) Table Column B-tree 4 8 12 vote votes votes votes Ro ot

52. Root가 있는 이유?

53. Root가 있는 이유? 4 8 12 nam e nam e nam e nam e nam e votes Perso n 4 8 12 vote votes votes votes Ro ot 전체 Group을 하나의 스냅샷으로 인 지.

54. Root가 있는 이유? 현재 버전을 포인팅 Ro ot 현재 버전 삭제될 과거 버전 “Multi Version Concurrency Control” Git, 현대적인 DBMS에서 사용.

55. Root가 있는 이유? Ro ot 다른 사용자는 현재 버전에 Lock 없이 접근. 새 버전을 작성중 . 읽기는 언제나 비 배타적입니다.

56. Root가 있는 이유? Ro ot 새로 작성된 버전으로 옮겨가는 것만 락이 필요합 니다. Ro ot 쓰기만 배타적입니다. 다른 사용자는 여전히 이전 버전에 접근 중. 루트를 이동

57. Root가 있는 이유? "MVVC는 효율을 위해 사용성을 일부 희생합니다.” 1. 읽기는 Lock이 필요하지 않으며 언제나 가능합니다. 2. 쓰기는 Lock이 필요합니다. 3. 객체는 어떤 시점을 참고하고 있기 때문에 다른 스레드로 전달될 수 없습니 4. 다른 스레드에서 객체를 참고하는 것은 즉시 이루어집니다. 프로그래머에게 직관적이지는 않습니다.

58. 이전 버전을 읽을 가 능성?

59. 이전 버전을 읽을 가능성? Ro ot 다른 사용자는 현재 버전에 Lock 없이 접근. 새 버전을 작성중 . “다른 사용자는 여전히 구 버전을 접근하게 되지 않나요?”

60. 이전 버전을 읽을 가능성? Person 객체 (Leonardo) v1 Person 객체 (Leonardo) v1 스레드 A 스레드 B Person 객체 (Leonardo) v2 1. 스레드 A에서 Person 객체 업데이트. 2. 업데이트 내역이 전파. Person 객체 (Leonardo) v2 3. 스레드 B의 라이브 객체가 자동 업데이 트. 3. 스레드 B의 객체의 리스너에게 모두 업데이트 내용을 통보.

61. 추가적인 최적화

62. 추가적인 최적화 4 8 12 nam e nam e nam e nam e nam e votes Perso n 배열은 얼마나 많은 공간을 차지할까? 4 8 12 vote votes votes votes Ro ot

63. 추가적인 최적화 0 1 0 1 votes가 최대 1인 경우 “최대 값이 1인 경우 4개의 votes는 4bits를 차지합니다.” Boolean 타입이 가장 효율적으로 저장됩니다.

64. 추가적인 최적화 00 01 10 01 최대 값이 2로 변경되었습니다. “최대 값이 2인 경우 4개의 votes는 8bits를 차지합니다.”

65. 추가적인 최적화 000 101 010 001 최대 값이 5로 변경되었습니다. “최대 값이 5인 경우 4개의 votes는 12bits를 차지합니다.”

66. 추가적인 최적화 4 8 12 노드의 실제 구조 nam e nam e nam e nam e nam e votes Perso n 4 8 12 vote votes votes votes Ro ot 4 8 12 개별 노드는 3개의 배열을 사용합니 다. 유연하지만 오버헤드가 있습니다.

67. 추가적인 최적화 nam e votes Perso n vote votes votes votes 4 8 12 만약에 데이터가 뒤로만 추가된다면 더 최적화를 할 수 있습니 다. 모든 노드가 다 차있다면 처음과 마지막 인덱스만 있으면 됩 니다.

68. 추가적인 최적화 nam e votes Perso n vote votes votes votes 4 12 물론 이러한 꿈은 삽입과 삭제가 이뤄지면 물거품이 됩니다. 모든 노드가 다 차있다면 처음과 마지막 인덱스만 있으면 됩 니다.

69. 흥미로운가요?


70. 기회는 여러분에게 열려있습니다. “Realm은 오픈소스입니다.”

Realm Java https://github.com/realm/realm-java 

Realm Objective C & Swift https://github.com/realm/realm-cocoa 

Realm Xamarin https://github.com/realm/realm-dotnet 

Realm Reactive Native & Node.js https://github.com/realm/realm-js 

Realm Object Store 공통 모듈 https://github.com/realm/realm-object-store 

Realm Core 핵심 엔진 https://github.com/realm/realm-core


71. Realm을 바로 사용하실 수 있습니다. 

Realm Java 문서 https://realm.io/docs/java/latest/ 

Realm Swift 문서 https://realm.io/docs/swift/latest/ 

Realm Objective C 문서 https://realm.io/docs/objc/latest/ 

Realm React Native 문서 https://realm.io/docs/javascript/latest/ 

Realm Xamarin 문서 https://realm.io/docs/xamarin/latest/

72. 최신 모바일 기술은 Realm에서 https://realm.io

73. Thank you



...

저작자 표시 비영리
신고
Posted by 홍반장水 홍반장水

[Node.js] chromium binding 기술을 node.js에 적용해보자


https://deview.kr/2017/schedule/213


chromium binding 기술을 node.js에 적용해보자

1. Chromium Binding 기술을 Node.js에 적용해보자! Name: Jinho Bang E-Mail: zino@chromium.org

2. 0. 요약

3. 이 세션에서 다룰 내용은..

4. Node.js에서 Native Module을 바인딩 하는 방법이다.

5. 그런데 이미 Node.js에는 바인딩을 위한 방법들이 제공되고 있다.

6. 그러나 그 방법이 아름답지 않다.

7. 이 세션에서는 그러한 문제를 분석하고

8. 좀 더 아름답게 해결하는 방안을 모색해본다.

9. 1. JS에서 왜 Native Module을 사용하는가?

10. 성능(Performance)

11. Low Level APIs

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; } ?

17. 그런데 Javascript에서 어떻게 호출할까?

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에서 호출 할 수 있다.

23. 3. 기존의 문제점 파헤치기

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++과 같은 지식 모두를 필요로 한다. • 전체적인 코드의 복잡도가 증가한다.

33. 4. Chromium에서 Blink와 V8은 어떻게 연결되나?

34. 왜 Chromium을 살펴보나?

35. Chromium은 V8의 또 다른 Embedder이다.

36. ♥ ≡ ♥ Blink (Rendering Engine) V8 (Javascript Engine) Node.js Native Module V8 (Javascript Engine)

37. document.getElementById();

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 두 가지를 구현해야 한다.

87. 7. Bacardi Project

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

98. Bacardi with Electron - 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)

Bacardi project is an effort to provide multi-language binding for Node.js native layer.

103. 요약

 • Node.js에 WebIDL Binding을 구현하기 위해서는 IDL Parser와 Code Generator 두 가지를 구현해야 한다. 

• 모두가 같은 노력을 할 필요 없으므로 오픈소스 프로젝트(Bacardi Project)로 진행중이 며, 이를 Node.js Native Module 개발에 활용할 수 있다.

104. 8. Binding 성능에 관한 이야기

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

109. uftrace를 사용한 call-graph 추적

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

115. Thank you



...

저작자 표시 비영리
신고
Posted by 홍반장水 홍반장水

특별한 인생을 만드는 방법




<또 다른 특강 영상>


결과를 내는 법 - 3개월간 12kg감량 이야기

https://youtu.be/g2_SRdYL-ZE


행복을 찾아서

https://youtu.be/wsuvwF8OZDo


말하기를 잘하는 법

https://youtu.be/n_ij6Bi7OVM


4차 산업혁명의 허와 실

https://youtu.be/veRFjA5XHL0


당신이 바뀌지 않는 이유

https://youtu.be/2hIMd9JDWs8


노력이 재능을 이길 수 있을까?

https://youtu.be/2vn_QC2u8Zk


너 자신을 알라, 메타인지

https://youtu.be/3GaOHD2KMeM


당신에게 필요한, 진짜용기

https://youtu.be/A_UrJSp3D0c


멘토링프로젝트 - 완벽한 하루 만들기

https://youtu.be/R4TNKlIVdE8



...

저작자 표시 비영리
신고
Posted by 홍반장水 홍반장水

길을 '아는 것'과 길을 '걷는 것'은 엄연히 다르다

 - 자기개발


< 함께 보면 좋은 영상 >


왜 공부해도 남는 게 없는가 - 실질학습

- https://youtu.be/hhcyW1uIrEc


틀을 깨고 한 단계 성장하는 법

- https://youtu.be/XAXNDcbwz14


실천력을 높일 수 있는 2가지 꿀팁

- https://youtu.be/TjN1VSNwPAw


특별한 인생을 만드는 방법

- https://youtu.be/EpmWzikLgDg





...

저작자 표시 비영리
신고
Posted by 홍반장水 홍반장水

책 읽어주는 딥러닝: 배우 유인나가 해리포터를 읽어준다면 DEVIEW 2017

https://deview.kr/2017/schedule/192



코드 : https://github.com/devsisters/multi-speaker-tacotron-tensorflow 

음성 합성 데모 : http://carpedm20.github.io/tacotron 

발표 소개 : https://deview.kr/2017/schedule/182 



...

저작자 표시 비영리
신고
Posted by 홍반장水 홍반장水