정보실

웹학교

정보실

javascript V8이 V8 정규 표현식을 개선하는 방법

본문

V8 정규식 개선 


기본 구성에서 V8은 첫 번째 실행시 정규식을 원시 코드로 컴파일합니다. JIT-less V8에 대한 작업의 일환으로 정규 표현식에 대한 인터프리터를 도입했습니다. 정규식을 해석하면 메모리를 적게 사용한다는 이점이 있지만 성능이 저하됩니다. 이 블로그 게시물에서 우리는 정규식을 해석하면서 단점을 완화하면서 장점을 활용하는 방법을 설명합니다.


https://v8.dev/blog/regexp-tier-up 


RegExp의 계층화 전략 


우리는 정규식에 '두 세계의 최고'를 사용하고 싶습니다. 이를 위해 먼저 모든 정규식을 바이트 코드로 컴파일하고 해석합니다. 이런 식으로, 우리는 많은 메모리를 절약하고, 전반적으로 (그리고 새로운 빠른 인터프리터로) 성능 저하를 수용 할 수 있습니다. 동일한 패턴의 정규 표현식을 다시 사용하는 경우 '핫'으로 간주하여 기본 코드로 다시 컴파일합니다. 이 시점부터 우리는 가능한 한 빨리 실행을 계속합니다.


V8의 정규 표현식 코드를 통해 호출되는 메소드, 글로벌 또는 비 글로벌 정규 표현식인지 여부 및 빠른 경로 또는 느린 경로를 사용하는지 여부에 따라 여러 가지 경로가 있습니다. 즉, 계층화 결정을 가능한 한 중앙 집중화 하기를 원합니다. 런타임시 특정 값으로 초기화되는 V8의 RegExp 객체에 틱 필드를 추가했습니다. 이 값은 컴파일러에 계층화 하기 전에 정규식이 해석되는 횟수를 나타냅니다. 정규식이 해석 될 때마다 틱 필드가 1 씩 감소합니다. 모든 정규식에 대해 호출되는 CodeStubAssembler로 작성된 내장 기능에서 모든 실행에서 틱 플래그를 확인합니다. 틱이 0에 도달하면 정규 표현식을 기본 코드로 다시 컴파일 해야 한다는 것을 알게 되고 런타임으로 점프합니다.


우리는 정규 표현식이 다른 실행 경로를 가질 수 있다고 언급했습니다. 전역 대체가 매개 변수로 함수로 대체되는 경우 기본 코드 및 바이트 코드의 구현이 다릅니다. 네이티브 코드는 배열이 모든 일치 항목을 미리 저장하고 바이트 코드는 한 번에 하나씩 일치해야 합니다. 이로 인해, 우리는 이 사용 사례를 위해 항상 네이티브 코드를 열심히 사용하기로 결정했습니다.


RegExp 인터프리터 속도 향상 


런타임 오버 헤드 제거 


정규식이 실행될 때 CodeStubAssembler로 작성된 내장 함수가 호출됩니다. 이 내장은 JSRegExp 객체의 코드 필드에 직접 실행될 수 있는 JITted 네이티브 코드가 포함되어 있는지 확인하고, 그렇지 않으면 RegExp를 컴파일 (또는 JIT-less 모드에서 해석)하기 위해 런타임 메소드라고 합니다. JIT-less 모드에서는 정규 표현식을 실행할 때마다 V8 런타임이 실행되었는데, 이는 실행 스택에서 JavaScript와 C ++ 코드 사이를 전환해야 하기 때문에 상당히 비쌉니다.


V8 v7.8부터는 정규 표현식을 해석하기 위해 RegExp 컴파일러가 바이트 코드를 생성 할 때마다 RegExp 인터프리터에 대한 트램폴린이 생성 된 바이트 코드와 함께 JSRegExp 오브젝트의 코드 필드에 저장됩니다. 이런 식으로 이제 인터프리터가 런타임을 우회 하지 않고 내장에서 직접 호출됩니다.


New dispatch method 


RegExp 인터프리터는 이전에 간단한 스위치 기반 디스패치 방법을 사용했습니다. 이 방법의 주요 단점은 CPU가 다음 바이트 코드 실행을 예측하기가 매우 어려워 많은 분기 오류를 초래하여 실행 속도가 느려진다는 것입니다.


V8 v7.8에서는 디스패치 메소드를 스레드 코드로 변경했습니다. 이 방법을 사용하면 CPU의 분기 예측기가 현재 실행 된 바이트 코드를 기반으로 다음 바이트 코드를 예측할 수 있어 오판 수가 줄어 듭니다. 더 자세하게, 각 바이트 코드 ID와 바이트 코드를 구현하는 핸들러의 주소 사이의 맵핑을 저장하는 디스패치 테이블을 사용합니다. V8의 통역사 Ignition도 이 접근법을 사용합니다. 그러나 Ignition과 RegExp 인터프리터의 큰 차이점은 Ignition의 바이트 코드 핸들러는 CodeStubAssembler로 작성되고 전체 RegExp 인터프리터는 계산 된 gotos (clang에서 지원하는 GNU 확장)를 사용하여 C ++로 작성되므로 읽기 및 유지 관리가 더 쉽다는 것입니다 CSA보다. 계산 된 gotos를 지원하지 않는 컴파일러의 경우 이전 스위치 기반 디스패치 방법으로 돌아갑니다.


Bytecode peephole optimization 


바이트 코드 들여다 보는 구멍 최적화에 대해 이야기하기 전에 동기 부여 예제를 살펴 보겠습니다.


const re = /[^_]*/;
const str = 'a0b*c_ef';
re.exec(str);
// → matches 'a0b*c'

이 간단한 패턴을 위해 RegExp 컴파일러는 모든 문자에 대해 실행되는 3 바이트 코드를 작성합니다. 높은 수준에서 다음과 같습니다.

  1. 현재 문자를 로드하십시오.
  2. 문자가 '_'와 같은지 확인하십시오.
  3. 그렇지 않은 경우 주제 문자열에서 현재 위치를 진행하고 1로 이동하십시오.

제목 문자열에서 일치하지 않는 문자를 찾을 때까지 17 바이트 코드를 해석합니다. 들여다 보는 구멍 최적화의 아이디어는 바이트 코드 시퀀스를 여러 바이트 코드의 기능을 결합한 새로운 최적화 된 바이트 코드로 대체한다는 것입니다. 이 예에서는 새로운 바이트 코드에서 goto에 의해 생성 된 암시 적 루프를 처리 할 수 ​​있으므로 단일 바이트 코드는 일치하는 모든 문자를 처리하여 16 개의 디스패치를 ​​저장합니다.


예제는 구성되었지만 여기에 설명 된 일련의 바이트 코드는 실제 웹 사이트에서 자주 발생합니다. 실제 웹 사이트를 분석하고 가장 빈번한 바이트 코드 시퀀스에 대해 최적화 된 새로운 바이트 코드를 만들었습니다.


results-memory.svg 

그림 1 : 다른 계층 값에 대한 메모리 절약


그림 1은 Facebook, Reddit, Twitter 및 Tumblr 브라우징 스토리를 위한 다양한 계층화 전략의 메모리에 미치는 영향을 보여줍니다. 기본값은 JITted 코드의 크기이며, 1, 10 및 100으로 초기화 된 틱에 대해 (계층화 되지 않은 경우 바이트 코드 크기, 기본 코드 크기 인 경우) 사용하는 정규 표현식 코드 크기가 있습니다. 마지막으로 정규 표현식을 모두 해석하면 정규 표현식 코드의 크기가 됩니다. 이 결과 및 기타 벤치 마크를 사용하여 진드기가 1로 초기화 된 티 어업 (즉, 정규식을 한 번 해석 한 다음 티 어업)으로 설정하기로 결정했습니다.


이 계층화 전략을 적용하여 실제 사이트에서 V8의 힙 코드 크기를 4 ~ 7 %, V8의 유효 크기를 1 ~ 2 %로 줄였습니다.


results-speed.svg 

그림 2 : RegExp 성능 비교


그림 2는 RexBench 벤치 마크 제품군에 대한이 블로그 게시물에 설명 된 모든 개선 사항에 대한 RegExp 인터프리터의 성능에 미치는 영향을 보여줍니다. 참고로 JIT 컴파일 된 RegExp의 성능도 표시됩니다 (기본).


새로운 통역사는 기존 통역사보다 최대 2 배 빠르며 평균 약 1.45 배입니다. 우리는 심지어 대부분의 벤치 마크에서 JITted RegExp의 성능에 매우 근접해 있으며, Regex DNA가 유일한 예외입니다. RegExp를 해석 한 이유는 이 벤치 마크에서 JITted RegExp보다 훨씬 느리기 때문에 사용 된 긴 주제 문자열 (~ 300,000 자) 때문입니다. 디스패치 오버 헤드를 최소로 줄였지만 오버 헤드는 1,000자를 초과하는 문자열에서 합산되어 실행 속도가 느려집니다. 긴 문자열에서는 인터프리터가 너무 느리기 때문에 이러한 문자열에 대해 계층을 강화하는 휴리스틱을 추가했습니다.


결론 


V8 v7.9 (Chrome 79)부터는 정규 표현식을 열심히 컴파일하는 대신 계층화 합니다. 따라서 이전에 JIT-less V8에서만 사용되었던 인터프리터는 이제 모든 곳에서 사용됩니다. 결과적으로 우리는 메모리를 절약합니다. 우리는 이것을 가능하게 하기 위해 통역사를 가속화했습니다. 그러나 이것은 이야기의 끝이 아닙니다. 앞으로 더 많은 개선이 있을 것으로 예상됩니다.


이번 기회를 통해 V8 팀의 모든 사람들이 인턴십 기간 동안 지원해 주셔서 감사합니다. 멋진 경험이었습니다!





페이지 정보

조회 62회 ]  작성일19-10-22 17:14

웹학교