>백엔드 개발 >PHP 튜토리얼 >HHVM은 PHP 성능을 어떻게 향상합니까?

HHVM은 PHP 성능을 어떻게 향상합니까?

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB원래의
2016-07-27 16:56:201142검색
AMA의 Andrei Alexandrescu

배경

HHVM은 페이스북이 개발한 고성능 PHP 가상머신으로, 공식보다 9배 빠르다고 합니다. 너무 궁금해서 잠깐 알아보고 이 글을 작성했습니다. 두 가지 질문에 답할 수 있기를 바랍니다.

  • HHVM은 신뢰할 수 있나요? 제품에 사용해도 되나요?
  • 공식 PHP보다 왜 그렇게 빠른가요? 어떻게 최적화되나요?

어떻게 하시겠습니까?

HHVM의 구현 원리를 논의하기 전에 다른 사람의 입장에서 생각해 보겠습니다. PHP로 작성된 웹사이트가 있고 분석 후 리소스의 상당 부분이 PHP에서 소비되는 것을 발견했다고 가정해 보겠습니다. PHP 성능을 최적화하시겠습니까?

예를 들어 여러 가지 방법이 있습니다.

  • 옵션 1, Java, C, Go 등 성능이 더 좋은 언어로 마이그레이션합니다.
  • 옵션 2, RPC를 통해 기능을 분리하고 다른 언어로 구현하면 PHP가 수행할 수 있는 작업이 줄어듭니다. 예를 들어 Twitter는 Scala에 많은 비즈니스 로직을 넣고 프런트 엔드 Rails는 프레젠테이션만 담당합니다.
  • 옵션 3, PHP 확장을 작성하고 성능 병목 지점에서 C/C를 교체합니다.
  • 옵션 4, PHP 성능을 최적화합니다.

옵션 1은 10년 전 넷스케이프의 예를 들어, 특히 페이스북처럼 복잡한 비즈니스 로직과 PHP 코드를 갖춘 제품도 포기할 것이라고 경고했습니다. 많은 경우 2,000만 라인이 있다고 합니다([PHP on the Metal with HHVM]에서 인용). 수정 비용은 아마도 가상 머신을 작성하는 것보다 더 높으며, 수천 명의 팀이 처음부터 학습하는 경우도 있습니다. 받아들일 수 없다.

옵션 2는 가장 안전한 솔루션이며 점진적으로 마이그레이션할 수 있습니다. 실제로 Facebook도 이와 관련하여 열심히 노력하고 있으며 Facebook에서 주로 내부적으로 사용하는 또 다른 RPC 솔루션인 Thrift와 같은 RPC 솔루션도 개발했습니다. 언어는 C인데, 이는 초기 Thrift 코드에서 볼 수 있는데, 다른 언어의 구현이 매우 조잡하여 프로덕션 환경에서 사용할 수 없기 때문입니다.

현재 Facebook에서는 PHP:C가 9:1에서 7:3으로 늘어났다고 합니다. Andrei Alexandrescu의 등장으로 C가 Facebook에서 점점 인기를 얻고 있지만 이는 문제의 일부만 해결할 수 있습니다. 결국 C는 PHP에 비해 개발 비용이 훨씬 높으며, 자주 수정되는 곳에서는 사용하기 적합하지 않으며, RPC 호출이 너무 많으면 성능에 심각한 영향을 미치게 됩니다.

옵션 3좋아 보이지만 실제로 구현하기는 어렵습니다. 일반적으로 성능 병목 현상은 그다지 크지 않습니다. 또한 비용이 지속적으로 발생합니다. PHP 확장 개발 수준이 높습니다. 이러한 종류의 솔루션은 일반적으로 공개 및 거의 변경되지 않은 기본 라이브러리에서만 사용되므로 이 솔루션으로는 많은 문제를 해결할 수 없습니다.

보시다시피 처음 세 가지 해결책으로는 문제를 잘 해결할 수 없기 때문에 페이스북은 실제로 PHP 자체의 최적화를 고려할 수밖에 없습니다.

더 빠른 PHP

PHP를 최적화하고 싶은데 어떻게 최적화하나요? 제 생각에는 여러 가지 방법이 있습니다.

  • 옵션 1, PHP 언어 수준의 최적화.
  • 옵션 2, PHP의 공식 구현(즉, Zend)을 최적화합니다.
  • 옵션 3, PHP를 다른 언어의 바이트코드(바이트코드)로 컴파일하고 다른 언어의 가상 머신(예: JVM)의 도움으로 실행합니다.
  • 옵션 4, PHP를 C/C로 변환한 후 로컬 코드로 컴파일합니다.
  • 옵션 5, 더 빠른 PHP 가상 머신을 개발합니다.

PHP 언어 수준의 최적화는 가장 간단하고 실현 가능합니다. 물론 Facebook은 이를 고려했으며 성능 병목 현상을 찾는 데 매우 유용한 XHProf와 같은 성능 분석 도구도 개발했습니다.

그러나 XHProf는 여전히 Facebook의 문제를 잘 해결하지 못했기 때문에 계속해서 살펴보겠습니다. 다음은 옵션 2입니다. 간단히 말하면 Zend의 실행 프로세스는 PHP를 opcode로 컴파일하는 부분과 opcode를 실행하는 부분으로 나눌 수 있습니다. 따라서 Zend 최적화는 이 두 가지 측면에서 고려될 수 있습니다.

Opcode 최적화는 PHP의 반복적인 구문 분석을 피할 수 있는 일반적인 방법이며 Zend Optimizer Plus와 같은 일부 정적 컴파일 최적화도 수행할 수 있습니다. 그러나 PHP 언어의 동적 특성으로 인해 이 최적화 방법에는 제한이 있습니다. . 낙관적인 추정은 성능을 20%만 향상시킬 수 있습니다. 또 다른 고려 사항은 레지스터 기반 접근 방식과 같이 opcode 아키텍처 자체를 최적화하는 것이지만 이 접근 방식은 수정하기에는 너무 많은 작업이 필요하고 성능 향상은 특별히 눈에 띄지 않을 것이므로(아마도 30%?) 입출력 비율이 높지 않습니다.

또 다른 방법은 Opcode 실행을 최적화하는 것입니다. 먼저 Zend가 Opcode를 어떻게 실행하는지 간략하게 설명하겠습니다. Zend의 인터프리터(인터프리터라고도 함)는 서로 다른 Opcode에 따라 서로 다른 함수를 호출합니다. 하지만 설명의 편의를 위해 단순화한 것입니다. 그런 다음 이 함수에서 다양한 언어 관련 작업을 수행합니다(관심 있는 경우 "PHP Core 심층 이해" 책을 읽어보세요). Zend에는 복잡한 캡슐화와 간접 호출이 없습니다. 통역사에게는 아주 좋은 일입니다.

Zend의 실행 성능을 향상시키려면 프로그램의 기본 실행을 이해해야 합니다. 예를 들어 함수 호출에는 실제로 오버헤드가 있으므로 인라인 스레딩을 통해 최적화할 수 있습니다. 그 원리는 C의 인라인과 같습니다. 언어는 같지만 런타임에 관련 기능을 확장한 후 순차적으로 실행하고(유추일 뿐이며 실제 구현은 다름) CPU 파이프라인 예측 실패로 인한 낭비도 방지합니다.

또한 어셈블리를 사용하여 JavaScriptCore 및 LuaJIT와 같은 인터프리터를 구현할 수도 있습니다. 자세한 내용은 Mike의 설명을 읽어보는 것이 좋습니다

그러나 이 두 가지 방법은 수정하기가 너무 비싸고 하나를 다시 작성하는 것보다 훨씬 더 어렵습니다. 특히 나중에 PHP의 특성을 언급할 때 알 수 있듯이 이전 버전과의 호환성을 보장하기 위해서는 더욱 어렵습니다.

고성능 가상 머신을 개발하는 것은 간단한 문제가 아닙니다. JVM이 현재 성능에 도달하는 데 10년 이상이 걸렸습니다. 그러면 이러한 고성능 가상 머신을 직접 사용하여 PHP의 성능을 최적화할 수 있을까요? 이것이 옵션 3의 아이디어이다.

사실 이 솔루션은 Quercus나 IBM의 P8 등 이전에도 시도된 적이 있으며, Quercus는 거의 누구도 사용하지 않았으며 P8도 종료되었습니다. 페이스북도 이 방법을 조사했고, 믿을 수 없는 소문까지 돌았으나 사실 페이스북은 2011년 포기했다.

옵션 3은 좋아 보이지만 실제 효과는 이상적이지 않기 때문에 많은 전문가(예: Mike)에 따르면 VM은 항상 특정 언어에 최적화되어 있으며 다른 언어는 이를 구현할 때 많은 병목 현상이 발생합니다. Dart 문서에 Dynamic method invocation이 소개되어 있고, Quercus의 성능은 Zend APC([from The HipHop Compiler for PHP])와 크게 다르지 않다고 되어 있어 별 의미가 없습니다.

근데 OpenJDK도 최근 몇 년간 열심히 노력하고 있는데 최근 Grall 프로젝트가 꽤 괜찮아 보이는데, 그 중에서 눈에 띄는 성과를 낸 언어도 있는데, Grall을 공부할 시간이 없었어요. , 그래서 여기서 판단할 수 없습니다.

다음은 옵션 4인데, 이것이 바로 HPHPc(HHVM의 전신)가 하는 일인데, PHP 코드를 C로 변환한 후 로컬 파일로 컴파일하는 것입니다(미리). ) 방법에 대한 기술적인 세부 사항은 The HipHop Compiler for PHP 논문을 참조하세요. 다음은 개요를 얻는 데 사용할 수 있는 논문의 스크린샷입니다.

HHVM 是如何提升 PHP 性能的?이 접근 방식의 가장 큰 장점은 (VM에 비해) 구현이 간단하고 많은 컴파일 최적화를 수행할 수 있다는 것입니다(오프라인이므로 속도가 느려도 괜찮습니다). 위의 예에서

는 최적화되어 있지만 PHP에서는 - 1eval()과 같은 많은 동적 메서드를 지원하기 어렵습니다. 이를 위해서는 비용이 많이 드는 인터프리터를 내장해야 하기 때문에 HPHPc는 간단히 지원합니다. 이러한 구문을 지원하지 않습니다. create_function()

HPHPc 외에도 비슷한 프로젝트가 두 개 있는데 하나는 Roadsend이고 다른 하나는 phc입니다. phc가 하는 일은 PHP를 C로 변환한 후 이를 컴파일하는 것입니다. 다음은

을 C 코드로 변환하는 예입니다. file_get_contents($f) php_call_function (&fgc_info);

<div class="blockcode">코드 복사<div id="code_LjU"> <ol> <p> phc에 대해 말하자면, 저자는 2년 전 phc를 시연하기 위해 페이스북에 가서 그곳의 엔지니어들과 소통한 결과, 출시되자마자 인기를 끌었다고 자신의 블로그에서 눈물을 흘린 적이 있습니다. , 그리고 그는 4년 동안 바빴지만 어느덧 무명에 빠졌고 이제 그 미래는 암울해졌습니다. . . </p> <p>Roadsend는 더 이상 유지 관리되지 않습니다. PHP와 같은 동적 언어의 경우 이 접근 방식에는 동적으로 포함될 수 없기 때문에 Facebook은 모든 파일을 함께 컴파일했으며 실제로 온라인에 접속할 때 파일 배포가 1G에 도달하고 있습니다. 받아들일 수 없다. </p> <p>PHP QB라는 프로젝트도 있는데 시간 관계상 자세히 보지는 못했어요. </p> <p>그래서 남은 방법은 더 빠른 PHP 가상 머신을 작성하고 이 어두운 길을 끝까지 가는 것입니다. 아마도 여러분도 Facebook이 가상 머신을 구축할 것이라는 소식을 처음 들었을 때 여러분도 저와 같을 것입니다. 너무 터무니없다고 생각했지만, 주의 깊게 분석해 보면 실제로는 이것이 유일한 방법이라는 것을 알게 될 것입니다. </p> <h2>더 빠른 가상 머신</h2> <p>HHVM이 더 빠른 이유는 무엇인가요? JIT의 핵심 기술은 각종 뉴스 보도에서 언급됐지만 사실 그렇게 단순하지는 않다. JIT는 단순히 파동만으로 성능을 향상시킬 수 있는 마술 지팡이도 아니고, JIT의 운영 자체도 시간이다. , 간단한 프로그램의 경우 인터프리터보다 느릴 수 있습니다. 가장 극단적인 예는 LuaJIT 2의 인터프리터가 V8의 JIT보다 약간 빠르기 때문에 세부 사항 처리에 관한 것이 아닙니다. .HHVM의 개발 역사 지속적인 최적화의 역사입니다. HPHPc를 조금씩 능가하는 모습을 아래 사진에서 보실 수 있습니다. </p> <img alt="HHVM 是如何提升 PHP 性能的?" src="http://img.it-home.org/data/attachment/forum/2014pic/20140321154123_97.jpg" style="max-width:90%" style="max-width:90%"> <p>Android 4.4의 새로운 가상 머신 ART는 AOT 솔루션을 사용한다는 점은 언급할 가치가 있으며(기억하세요? 앞서 언급한 HPHPc는 이렇습니다) 결과는 JIT를 사용했던 이전 Dalvik보다 두 배 빠릅니다. 반드시 AOT보다 빠릅니다. </p> <p>따라서 이 프로젝트는 매우 위험합니다. 강한 마음과 인내가 없으면 중도에 포기될 가능성이 높습니다. Google은 한때 Python의 성능을 향상시키기 위해 JIT를 사용하려고 했지만 결국 Google의 경우 사용에 실패했습니다. Python 여기에는 실제로 성능 문제가 없습니다. Google은 Python으로 크롤링을 작성했지만 [In The Plex 참조] 1996년에는 그게 전부였습니다. </p> <p>Google에 비해 Facebook은 분명히 더 큰 동기와 결단력을 가지고 있습니다. PHP는 Facebook의 가장 중요한 언어입니다. Facebook이 이 프로젝트에 투자한 전문가는 누구인지 살펴보겠습니다. </p> </ol> <ul> <li>, <c>의 저자이자 C 분야의 명가인 안드레이 알렉산드레스쿠</c> </li> <li>Keith Adams는 VMware의 핵심 아키텍처를 담당했습니다. 당시 VMware에서는 그를 단독으로 파견하여 Intel과 기술 협력을 진행했는데, 이는 그가 VMM 분야에 대해 얼마나 많은 지식을 가지고 있는지 입증했습니다.</li> <li>Microsoft에서 .NET 가상 머신 개발에 참여하여 JIT를 개선한 Drew Paroski</li> <li>Jason Evans, Firefox의 메모리 사용량을 절반으로 줄인 jemalloc 개발</li> <li>"PHP 확장 및 내장"의 저자이자 PHP 커널 전문가인 사라 골레몬(Sara Golemon)은 PHP 마스터라면 누구나 이 책을 읽었을 것이라고 생각합니다. 어쩌면 그녀가 실제로 여성인지는 모를 수도 있습니다</li> </ul> <p> 비록 Lars Bak, Mike Pall과 같은 가상머신 분야의 최고 전문가는 없지만 이들 전문가가 함께 일할 수 있다면 가상머신을 작성하는 데에는 큰 문제가 없을 것입니다. 그렇다면 그들이 직면하게 될 과제는 무엇일까요? 다음으로 하나씩 논의해 보겠습니다. </p> <h3>사양은 어떻게 되나요? </h3> <p>PHP 가상 머신을 직접 작성할 때 직면해야 하는 첫 번째 문제는 PHP에는 언어 사양이 없고 여러 버전 간의 구문이 호환되지 않는다는 것입니다(5.2.1 및 5.2.3과 같은 작은 버전 번호라도). PHP 언어 사양 어떻게 정의하나요? IEEE의 성명을 살펴보겠습니다. </p> <blockquote> <p>PHP 그룹은 (언어) PHP 사양에 대한 최종 결정권을 갖고 있다고 주장합니다. 이 그룹 사양은 구현일 뿐이며 전문적인 사양이나 합의된 검증 제품군은 없습니다.</p> </blockquote> <p>그래서 Zend의 구현을 솔직하게 살펴보는 것이 유일한 방법입니다. 다행히 HPHPc에서는 한 번 고생한 적이 있어서 HHVM이 직접 사용할 수 있으므로 이 문제는 그리 크지 않습니다. </p> <h3>언어 또는 확장자? </h3> <p>PHP 언어를 구현하는 것은 가상 머신을 구현하는 것만큼 간단하지 않습니다. PHP 언어 자체에는 다양한 확장 기능도 포함되어 있으며 Zend는 사용할 수 있는 다양한 기능을 구현하기 위해 끊임없이 노력하고 있습니다. PHP 코드를 분석해 보면 빈 줄 주석을 제외하고 C 코드에 80만 줄이 있다는 것을 알 수 있는데, Zend 엔진 부품이 몇 개나 있는지 짐작해 보세요. 100,000개 미만의 행이 있습니다. </p> <p>이것은 개발자에게는 나쁜 일이 아니지만, 엔진 구현자에게는 매우 비극적인 일입니다. Java 가상 머신을 작성하려면 대부분 바이트코드 해석과 일부 기본 JNI 호출만 구현하면 됩니다. Java의 내장 라이브러리는 Java로 구현되므로 성능 최적화를 고려하지 않으면 작업량 측면에서 JVM보다 PHP 가상 머신을 구현하는 것이 훨씬 어렵습니다. 예를 들어 누군가는 TypeScript를 8,000줄로 구현했습니다. JVM Doppio. </p> <p>이 문제에 대한 HHVM의 해결 방법은 매우 간단합니다. 즉, 페이스북에서 사용하는 것만 구현하고, HPHPc에서는 이전에 작성한 것을 그대로 사용할 수도 있으므로 문제는 크지 않습니다. </p> <h3>통역사 구현</h3> <p>다음 단계는 PHP를 파싱한 후 HHVM에서 설계한 바이트코드를 생성하고 이를 <code>~/.hhvm.hhbc(SQLite 파일)에 저장하여 재사용할 때 Zend와 유사합니다. 바이트코드는 다른 기능으로 구현됩니다(이 메소드는 가상 머신에서 특별한 이름을 가집니다: 서브루틴 스레딩)

Interpreter의 본체는 bytecode.cpp에 구현되어 있습니다. VMExecutionContext::iopAdd과 같은 메소드의 경우 유형에 따라 최종 실행이 구분됩니다. 예를 들어 여기서는 추가 작업이 tv-arith.cpp에 구현되어 있습니다.

에서 발췌한 내용입니다. <div class="blockcode"> <div id="code_oM7"><ol> <li>if (c2.m_type == KindOfInt64) return o(c1.m_data.num, c2.m_data.num);</li> <li>if (c2.m_type == KindOfDouble) return o(c1.m_data.num, c2.m_data.dbl);</li> </ol></div> <em onclick="copycode($('code_oM7'));">复制代码</em> </div>

HHVM이 HPHPc에 비해 PHP 구문에 대한 지원을 크게 향상시킨 것은 바로 Interpreter 때문입니다. 이론적으로는 공식 PHP와 완벽하게 호환되지만 이것만으로는 성능이 크게 향상되지는 않습니다. Zend. 변수 유형을 결정할 수 없기 때문에 위와 유사한 조건문을 추가해야 합니다. 그러나 이러한 코드는 최신 CPU의 실행 최적화에 도움이 되지 않으며, 데이터가 각 읽기에 필요하다는 것입니다. m_data.num, m_data.dbl 등의 방법을 거쳐 간접적으로 얻는 것.

이와 같은 문제는 JIT에 의존하여 최적화해야 합니다.

JIT 구현 및 최적화

우선, PHP의 JIT가 이전에 시도된 적이 없다는 점을 언급할 가치가 있습니다.

  • 2008년에 일부 사람들이 LLVM을 실험했는데 결과는 원본보다 21배 느렸습니다. . .
  • 2010년에 IBM Japan Research Institute는 JVM 가상 머신 코드를 기반으로 P9를 개발했습니다. 성능은 공식 PHP의 2.5~9.5배입니다. PHP용으로 개조된 JIT(Just-In-Time) 컴파일러 평가 논문을 읽어보세요.
  • 2011년 Andrei Homescu는 RPython을 기반으로 이를 개발하고 HappyJIT: a tracing JIT 컴파일러 for PHP라는 논문을 작성했지만 테스트 결과는 혼합되어 이상적이지 않았습니다.

그럼 JIT란 정확히 무엇인가요? JIT를 구현하는 방법은 무엇입니까?

동적 언어에는 기본적으로 실행을 위해 문자열을 전달할 수 있는 평가 메서드가 있습니다. JIT는 문자열이 아닌 다른 플랫폼의 기계 코드를 연결한 다음 실행해야 한다는 점을 제외하면 비슷한 작업을 수행합니다. , 하지만 C로 구현하는 방법은 무엇입니까? 다음은 기사의 코드 일부입니다.

<div class="blockcode"> <div id="code_JSG"><ol> <li>부호 없는 문자 코드[] = {</li> <li> 0x48, 0x89, 0xf8, // mov %rdi, %rax</li> <li> 0x48, 0x83, 0xc0, 0x04, // $4 추가, %rax</li> <li> 0xc3 // ret</li> <li>};</li> <li>memcpy(m, code, sizeof(code));</li> </ol></div> <em onclick="copycode($('code_JSG'));">코드 복사</em> </div>

그런데 기계어 코드를 손으로 작성하다 보면 실수하기 쉽기 때문에 Mozilla의 Nanojit, LuaJIT의 DynASM 등 보조 라이브러리를 갖는 것이 가장 좋은데, HHVM은 이들을 사용하지 않고 라이브러리를 구현한다. x64(ARM 64비트를 생성하기 위해 VIXL도 사용하려고 함)의 경우 mprotect를 사용하여 코드를 실행 가능하게 만듭니다.

그런데 왜 JIT 코드가 더 빠른가요? 사실 C로 작성된 코드는 결국 기계어 코드로 컴파일되는데, 같은 코드를 그냥 수동으로 기계어 코드로 변환한다면, GCC에서 생성한 것과 무슨 차이가 있을까? 앞에서 CPU 구현 원리를 기반으로 한 몇 가지 최적화 기술을 언급했지만 JIT에서 더 중요한 최적화는 유형에 따라 특정 명령을 생성하여 명령 수와 조건부 판단 수를 크게 줄이는 것입니다. TraceMonkey의 다음 그림은 이를 매우 직관적으로 비교합니다. 나중에 HHVM에서 구체적인 예를 살펴보겠습니다.

HHVM 是如何提升 PHP 性能的?

HHVM은 처음에는 인터피터를 통해 실행되는데, 언제 JIT를 사용하게 되나요? 두 가지 일반적인 JIT 트리거 조건이 있습니다.

  • trace: 루프 실행 횟수를 기록합니다. 특정 횟수를 초과하면 이 코드를 JIT합니다
  • 방법: 함수 실행 횟수를 기록합니다. 특정 횟수를 초과하면 전체 함수를 JIT하거나 직접 인라인합니다

두 가지 방법 중 어느 것이 더 나은지에 대해 다양한 전문가, 특히 Mike Pall(LuaJIT 작성자), Andreas Gal(Mozilla VP) 및 Brendan Eich(Mozilla CTO)의 논의를 불러일으킨 Lambada 게시물이 있습니다. 내 의견을 많이 표현했고 모두에게 시청을 권장했습니다. 여기서는 부끄러움을 과시하지 않겠습니다.

두 가지의 차이점은 컴파일 범위뿐 아니라 지역 변수 처리와 같은 많은 세부 사항에 있는데 여기서는 다루지 않습니다

그러나 HHVM은 이 두 가지 방법을 사용하지 않고 대신 유형에 따라 구분되는 Tracelet이라는 방법을 만들었습니다

HHVM 是如何提升 PHP 性能的?

함수를 3개 부분으로 나누는 것을 볼 수 있습니다. 위쪽 2개 부분은 $k<code>$k가 정수 또는 문자열인 두 가지 상황을 처리하는 데 사용됩니다. 그래서 Tracelet을 분석하고 해체하는 방법에 대한 자세한 내용은 Translator.cpp의 Translator::analyze<code>Translator::analyze 메서드에서 볼 수 있습니다. 아직 살펴볼 시간이 있었습니다. 여기서는 논의하지 않겠습니다.

물론 고성능 JIT를 구현하기 위해서는 다양한 시도와 최적화가 필요합니다. 예를 들어 처음에는 HHVM에서 추가한 트레이스릿이 맨 앞에 배치됩니다. 즉, 위 그림에서 A와 C의 위치가 됩니다. 나중에 넣어보려고 했는데 테스트 결과 응답형을 미리 맞추는 게 더 쉽다는 걸 발견해서 성능이 14%나 향상됐어요

JIT의 실행 프로세스는 먼저 HHBC를 SSA(hhbc-translator.cpp)로 변환한 다음 SSA(예: 복사 전파)를 최적화하고 이를 X64 아래의 Translator-x64와 같은 로컬 기계어 코드로 다시 생성하는 것입니다. 구현되었습니다.

HHVM이 최종적으로 생성한 기계어 코드가 어떤 것인지 알아보기 위해 다음 PHP 함수와 같은 간단한 예를 들어보겠습니다.

<code class="php language-php" data-lang="php"><div class="blockcode"> <div id="code_B9S"> <ol> <li><?php<li>function a($b){<li> echo $b 2;<li>}</ol></div><em onclick="copycode($('code_B9S'));">复制代码</em></div>

함수 a($b){<div class="blockcode"> echo $b 2;<div id="code_ZLy">}<ol><li><em onclick="copycode($('code_B9S')));">코드 복사<li><li><li> <li>컴파일 후 다음과 같습니다. <li> <li><li><li><li><li>mov rcx,0x7200000<li>mov rdi,rbp<li>mov rsi,rbx<li>mov rdx,0x20<li>call 0x2651dfb <HPHP:: Transl::traceCallback(HPHP::ActRec*, HPHP::TypedValue*, long, void*)></li> <li>cmp BYTE PTR [rbp-0x8],0xa</li> <li>jne 0xae00306</li> <li>; 매개변수 확인 </li> <li> <li>mov rcx,QWORD PTR [rbp-0x10]; 여기서 %rcx에는 1의 값이 할당됩니다.</li> <li>mov edi,0x2; %rdi의 비트) 2</li> <li>add rdi,rcx; add %rcx</li> <li>call 0x2131f1b <HPHP::print_int(long)> 이번에는 첫 번째 매개변수 %의 값을 호출합니다. rdi는 이미 3입니다</li> <li> <li>; 나중에 논의하지 않습니다</li> <li>mov BYTE PTR [rbp 0x28],0x8</li> </ol>lea rbx,[rbp 0x20]</div>test BYTE PTR [r12],0xff<em onclick="copycode($('code_ZLy'));">jne 0xae0032a</em>push QWORD PTR [rbp 0x8]</div>mov rbp,QWORD PTR [rbp 0x0]mov rdi,rbpmov rsi,rbxmov rdx,QWORD PTR [rsp ]call 0x236b70e <HPHP::JIT::traceRet(HPHP::ActRec*, HPHP::TypedValue*, void*)>ret 코드 복사

HPHP::print_int 함수의 구현은 다음과 같습니다.

<div class="blockcode"><div id="code_K6f"> <ol> <code class="c language-c " data-lang="c "><div class="blockcode"> <div id="code_K6f"><ol> <li>void print_int(int64_t i) {</li> <li> char buf[256];</li> <li> snprintf(buf, 256, "%" PRId64, i);</li> <li> echo(buf);</li> <li> TRACE(1, "t-x64 output(int): %" PRId64 "n", i);</li> <li>}</li> </ol></div> <em onclick="copycode($('code_K6f'));">复制代码</em> </div>void print_int(int64_t i) {

char buf[256];int64_t snprintf(buf, 256, "%" PRId64, i);

echo(buf);

TRACE(1, "t-x64 출력(int): %" PRId64 "n", i);

} <div class="blockcode"> <div id="code_K70"><ol><li>-v Eval.JitWarmupRequests=0</li></ol></div> <em onclick="copycode($('code_K70'));">复制代码</em> </div>코드 복사

HHVM으로 컴파일된 코드는 int64_t

를 직접 사용하여 인터프리터에서 매개변수를 판단하고 간접적으로 데이터를 얻어야 하는 문제를 피함으로써 성능을 크게 향상시키고 최종적으로는 C로 컴파일된 코드는 크지 않습니다.

참고: 서버 모드에서 HHVM은 요청이 12개를 초과하는 경우에만 JIT를 트리거합니다. HHVM을 시작할 때 첫 번째 요청에서 JIT를 사용하도록 다음 매개변수를 추가할 수 있습니다. <div class="blockcode"> <div id="code_biL"><ol> <li><?hh<li>class Point2 {<li> public float $x, $y;<li> function __construct(float $x, float $y) {<li> $this->x = $x;</li> <li> $this->y = $y;</li> <li> }</li> <li>}</li> <li>//来自:https://raw.github.com/strangeloop/StrangeLoop2013/master/slides/sessions/Adams-TakingPHPSeriously.pdf</li> </ol></div> <em onclick="copycode($('code_biL'));">复制代码</em> </div> <div class="blockcode"><div id="code_K70"> <ol><p>-v Eval.JitWarmupRequests=0</p></ol> <code>float코드 복사

따라서 성능 테스트 시 주의가 필요합니다. 한 번 실행하거나 두번 드시고 비교하시면 효과를 보실 수 없습니다.

타입 파생은 매우 번거롭기 때문에 프로그래머에게 명확하게 작성하도록 강요해야 합니다

JIT의 핵심은 유형을 추측하는 것이므로 시간이 지남에 따라 특정 변수의 유형이 변경되면 최적화하기 어려울 것이므로 HHVM 엔지니어는 PHP 구문에 트릭을 적용하고 유형 지원을 추가하는 것을 고려하기 시작했으며 출시되었습니다. 새로운 언어 - Hack(이 이름에 대해 불평하는 것은 실제로 SEO에 좋지 않습니다), 다음과 같습니다:

<div class="blockcode"><div id="code_biL"> <ol><?hh<p>class Point2 { </p> 공개 float $x, $y;<ul> function __construct(float $x, float $y) {<li> $this->x = $x; $this->y = $ y;<li> }</li>}<li>//출처: https://raw.github.com/strangeloop/StrangeLoop2013/master/slides/sessions/Adams-TakingPHPSeriously.pdf</li> </ol>코드 복사<p> </p> <code>float<p> 키워드를 보셨나요? 정적 유형을 사용하면 HHVM이 성능을 더 잘 최적화할 수 있지만 이는 PHP 구문과 호환되지 않으며 HHVM만 사용할 수 있음을 의미하기도 합니다. </p> <h2>사실 이렇게 하면 가장 큰 장점은 Dart의 Optional Type과 마찬가지로 코드를 더 쉽게 이해하고 의도하지 않은 실수를 줄일 수 있다는 점이라고 생각합니다. 이는 IDE 식별을 용이하게 하는 것이기도 합니다. 페이스북은 아직까지 코드를 공동으로 편집할 수 있는 웹 IDE를 기반으로 애플리케이션을 개발 중이라고 합니다. </h2> <ul>HHVM을 사용할 수 있나요? <li> </li>일반적으로 이전 HPHPc에 비해 HHVM은 실제 가상 머신이고 다양한 PHP 구문을 더 잘 지원할 수 있으므로 수정 비용이 높지 않고 원활하게 전환할 수 있기 때문에 시도해 볼 가치가 있다고 생각합니다. 공식 PHP 버전에서는 FPM을 동시에 시작하여 언제든지 통화할 수 있습니다. 또한 HHVM에는 긴급 상황에 대비할 수 있는 FastCGI 인터페이스가 있어 위험을 제어할 수 있으며 매우 유망합니다. 장기적으로. <li> </li>성능이 얼마나 향상될 수 있는지 잘 모르겠습니다. 실제 테스트에 자체 비즈니스 코드를 사용해야 HHVM이 얼마나 많은 이점을 가져올 수 있는지, 특히 전체적인 성능 향상이 얼마나 되는지를 진정으로 알 수 있습니다. 이 데이터를 통해 우리는 결정을 내릴 수 있습니다. <li> </li>마지막으로 발생할 수 있는 문제를 정리하겠습니다. <li> </li> <li>확장 문제: PHP 확장을 사용하는 경우 다시 작성해야 합니다. 그러나 HHVM 확장은 Zend보다 작성하기가 훨씬 간단합니다. 자세한 내용은 위키에서 예제를 참조하세요. </li> <li>HHVM 서버의 안정성 문제: 이 멀티 스레드 아키텍처는 일정 시간 동안 실행한 후 메모리 누수를 일으킬 수 있거나 잘못 작성된 PHP로 인해 전체 프로세스가 직접 중단될 수 있으므로 테스트에 주의해야 합니다. 이 지역의 재난 대책에 대한 관용. </li> <li>문제 복구의 어려움: HHVM은 문제가 발생할 때 Zend보다 복구하기가 더 어렵습니다. 특히 JIT 코드가 더 안정적이기를 바랄 뿐입니다. </li> <li> </li>P.S. 사실 저는 기본적인 가상머신 지식만 알고 있고, PHP 코드를 몇 줄 작성해 본 적이 없습니다. 시간이 촉박하고 레벨이 제한되어 있어서 임시로 정보를 검색한 내용도 많습니다. 잘못된 정보가 있을 수 있으니 누구나 댓글과 조언을 환영합니다 :)<li> </li>2014년 1월 추가: 현재 공장 내 HHVM 프로모션 모멘텀은 매우 좋습니다. 특히 호환성 테스트가 98.58%에 도달하고 수정 비용이 더욱 절감되었으므로 2014년에는 모두가 시도해 볼 것을 권장합니다. . <li> </li>인용문</ul>

Keith Adams의 HN에 대한 단서
세 사람이 Facebook의 기반을 다시 구축한 방법
HHVM을 사용한 PHP on the Metal

HPHPi를 더 빠르게 만들기 HHVM 최적화 팁 JIT 속도의 힙합 가상 머신(hhvm) PHP 실행 Julien Verlaguet, Facebook: PHP를 정적으로 분석 HHVM으로 PHP 기반 개발 속도 향상 HHBC에 opcode 추가
성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.