Total Pageviews

Thursday, 25 August 2016

HHVM

A virtual machine designed for executing programs written in Hack and PHP. 

HHVM is an open-source virtual machine designed for executing programs written in Hack and PHP. HHVM uses a just-in-time (JIT) compilation approach to achieve superior performance while maintaining the development flexibility that PHP provides.
HHVM supports HackPHP 5 and the major features of PHP 7. We are aware of minor incompatibilities, so please open issues when you find them. HHVM also supports many extensions as well.
HHVM should be used together with a webserver like the built in, easy to deploy Proxygen, or a FastCGI-based webserver on top of nginx or Apache.

Installing

If you're new, try our getting started guide.
You can install a prebuilt package or compile from source.

Running

You can run standalone programs just by passing them to hhvm: hhvm my_script.php.
If you want to host a website:
  • Install your favorite webserver. Proxygen is built in to HHVM, fast and easy to deploy.
  • Install our package
  • Start your webserver
  • Run sudo /etc/init.d/hhvm start
  • Visit your site at http://.../index.php
Our getting started guide provides a slightly more detailed introduction as well as links to more information.

Contributing

We'd love to have your help in making HHVM better. If you're interested, please read our guide to contributing.

License

HHVM is licensed under the PHP and Zend licenses except as otherwise noted.
The Hack typechecker (hphp/hack) is licensed under the BSD license (hphp/hack/LICENSE) with an additional grant of patent rights (hphp/hack/PATENTS) except as otherwise noted.

Reporting Crashes

See Reporting Crashes for helpful tips on how to report crashes in an actionable manner.

Reporting and Fixing Security Issues

Please do not open GitHub issues or pull requests - this makes the problem immediately visible to everyone, including malicious actors. Security issues in HHVM can be safely reported via HHVM's Whitehat Bug Bounty program:
Facebook's security team will triage your report and determine whether or not is it eligible for a bounty under our program.

FAQ

Our user FAQ has answers to many common questions about HHVM, from general questions to questions geared towards those that want to use.
There is also a FAQ for contributors to HHVM.

from https://github.com/facebook/hhvm
------------
http://www.zhihu.com/question/23957972
-----------
刚刚看得国外的一个测试数据,HHVM和PHP7不相上下了,甩5.5和5.6好几条街啊
-----------
http://talks.php.net/sunshinephp15#/
PHP 之父 Rasmus Lerdorf 在 SunshinePHP 2015 的 keynote
有HHVM和PHP7的數據.
------------

HHVM 是如何提升 PHP 性能的?

背景

HHVM 是 Facebook 开发的高性能 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几乎不可行,十年前 Joel 就拿 Netscape 的例子警告过,你将放弃是多年的经验积累,尤其是像 Facebook 这种业务逻辑复杂的产品,PHP 代码实在太多了,据称有2千万行(引用自 [PHP on the Metal with HHVM]),修改起来的成本恐怕比写个虚拟机还大,而且对于一个上千人的团队,从头开始学习也是不可接受的。
方案2是最保险的方案,可以逐步迁移,事实上 Facebook 也在朝这方面努力了,而且还开发了 Thrift 这样的 RPC 解决方案,Facebook 内部主要使用的另一个语言是 C++,从早期的 Thrift 代码就能看出来,因为其它语言的实现都很简陋,没法在生产环境下使用。
目前在 Facebook 中据称 PHP:C++ 已经从 9:1 增加到 7:3 了,加上有 Andrei Alexandrescu 的存在,C++ 在 Facebook 中越来越流行,但这只能解决部分问题,毕竟 C++ 开发成本比 PHP 高得多,不适合用在经常修改的地方,而且太多 RPC 的调用也会严重影响性能。
方案3看起来美好,实际执行起来却很难,一般来说性能瓶颈并不会很显著,大多是不断累加的结果,加上 PHP 扩展开发成本高,这种方案一般只用在公共且变化不大的基础库上,所以这种方案解决不了多少问题。
可以看到,前面3个方案并不能很好地解决问题,所以 Facebook 其实没有选择的余地,只能去考虑 PHP 本身的优化了。

更快的 PHP

既然要优化 PHP,那如何去优化呢?在我看来可以有以下几种方法:
  • 方案1,PHP 语言层面的优化。
  • 方案2,优化 PHP 的官方实现(也就是 Zend)。
  • 方案3,将 PHP 编译成其它语言的 bytecode(字节码),借助其它语言的虚拟机(如 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 是如何执行的,Zend 的 interpreter(也叫解释器)在读到 opcode 后,会根据不同的 opcode 调用不同函数(其实有些是 switch,不过为了描述方便我简化了),然后在这个函数中执行各种语言相关的操作(感兴趣的话可看看深入理解 PHP 内核这本书),所以 Zend 中并没有什么复杂封装和间接调用,作为一个解释器来说已经做得很好了。
想要提升 Zend 的执行性能,就需要对程序的底层执行有所解,比如函数调用其实是有开销的,所以能通过 Inline threading 来优化掉,它的原理就像 C 语言中的 inline 关键字那样,但它是在运行时将相关的函数展开,然后依次执行(只是打个比方,实际实现不太一样),同时还避免了 CPU 流水线预测失败导致的浪费。
另外还可以像 JavaScriptCore 和 LuaJIT 那样使用汇编来实现 interpreter,具体细节建议看看 Mike 的解释
但这两种做法修改代价太大,甚至比重写一个还难,尤其是要保证向下兼容,后面提到 PHP 的特点时你就知道了。
开发一个高性能的虚拟机不是件简单的事情,JVM 花了10多年才达到现在的性能,那是否能直接利用这些高性能的虚拟机来优化 PHP 的性能呢?这就是方案3的思路。
其实这种方案早就有人尝试过了,比如 Quercus 和 IBM 的 P8,Quercus 几乎没见有人使用,而 P8 也已经死掉了。Facebook 也曾经调研过这种方式,甚至还出现过不靠谱的传闻 ,但其实 Facebook 在2011年就放弃了。
因为方案3看起来美好,但实际效果却不理想,按照很多大牛的说法(比如 Mike),VM 总是为某个语言优化的,其它语言在上面实现会遇到很多瓶颈,比如动态的方法调用,关于这点在 Dart 的文档中有过介绍,而且据说 Quercus 的性能与 Zend+APC 比差不了太多([来自The HipHop Compiler for PHP]),所以没太大意义。
不过 OpenJDK 这几年也在努力,最近的 Grall 项目看起来还不错,也有语言在上面取得了显著的效果,但我还没空研究 Grall,所以这里无法判断。
接下来是方案4,它正是 HPHPc(HHVM 的前身)的做法,原理是将 PHP 代码转成 C++,然后编译为本地文件,可以认为是一种 AOT(ahead of time)的方式,关于其中代码转换的技术细节可以参考 The HipHop Compiler for PHP 这篇论文
这种做法的最大优点是实现简单(相对于一个 VM 来说),而且能做很多编译优化(因为是离线的,慢点也没事),比如上面的例子就将- 1优化掉了,但它很难支持 PHP 中的很多动态的方法,如 eval()create_function(),因为这就得再内嵌一个 interpreter,成本不小,所以 HPHPc 干脆就直接不支持这些语法。
除了 HPHPc,还有两个类似的项目,一个是 Roadsend,另一个是 phc ,phc 的做法是将 PHP 转成了 C 再编译,以下是它将 file_get_contents($f) 转成 C 代码的例子:
static php_fcall_info fgc_info;
php_fcall_info_init ("file_get_contents", &fgc_info);
php_hash_find (LOCAL_ST, "f", 5863275, &fgc_info.params);
php_call_function (&fgc_info);
话说 phc 作者曾经在博客上哭诉,说他两年前就去 Facebook 演示过 phc 了,还和那里的工程师交流过,结果人家一发布就火了,而自己忙活了4年却默默无闻,现在前途渺茫。。。
Roadsend 也已经不维护了,对于 PHP 这样的动态语言来说,这种做法有很多的局限性,由于无法动态 include,Facebook 将所有文件都编译到了一起,上线时的文件部署居然达到了 1G,越来越不可接受了。
另外有还有一个叫 PHP QB 的项目,由于时间关系我没有看,感觉可能是类似的东东。
所以就只剩下一条路了,那就是写一个更快的 PHP 虚拟机,将一条黑路走到底,或许你和我一样,一开始听到 Facebook 要做一个虚拟机是觉得太离谱,但如果仔细分析就会发现其实也只有这样了。

更快的虚拟机

HHVM 为什么更快?在各种新闻报道中都提到了 JIT 这个关键技术,但其实远没有那么简单,JIT 不是什么神奇的魔法棒,用它轻轻一挥就能提升性能,而且 JIT 这个操作本身也是会耗时的,对于简单的程序没准还比 interpreter 慢,最极端的例子是 LuaJIT 2 的 Interpreter 就稍微比 V8 的 JIT 快,所以并不存在绝对的事情,更多还是在细节问题的处理上,HHVM 的发展历史就是不断优化的历史,你可以从下图看到它是如何一点点超过 HPHPc 的.
值得一提的是在 Android 4.4 中新的虚拟机 ART 就采用的是 AOT 方案(还记得么?前面提到的 HPHPc 就是这种),结果比之前使用 JIT 的 Dalvik 快了一倍,所以说 JIT 也不一定比 AOT 快。
因此这个项目是有很大风险的,如果没有强大的内心和毅力,极有可能半途而废,Google 就曾经想用 JIT 提升 Python 的性能,但最终失败了,对于 Google 来说用到 Python 的地方其实并没什么性能问题(好吧,以前 Google 是用 Python 写过 crawl [参考 In The Plex],但那都是1996年的事情了)。
比起 Google,Facebook 显然有更大的动力和决心,PHP 是 Facebook 最重要的语言,我们来看看 Facebook 都投入了哪些大牛到这个项目中(不全): 
  • Andrei Alexandrescu,『Modern C++ Design』和『C++ Coding Standards』的作者,C++ 领域无可争议的大神
  • Keith Adams,负责过 VMware 核心架构,当年 VMware 就派他一人去和 Intel 进行技术合作,足以证明在 VMM 领域他有多了解了
  • Drew Paroski,在微软参与过 .NET 虚拟机开发,改进了其中的 JIT
  • Jason Evans,开发了 jemalloc,减少了 Firefox 一半的内存消耗
  • Sara Golemon,『Extending and Embedding PHP』的作者,PHP 内核专家,这本书估计所有 PHP 高手都看过吧,或许你不知道其实她是女的
虽然没有像 Lars Bak、Mike Pall 这样在虚拟机领域的顶级专家,但如果这些大牛能齐心协力,写个虚拟机还是问题不大的,那么他们将面临什么样的挑战呢?接下来我们一一讨论。

规范是什么?

自己写 PHP 虚拟机要面临的第一个问题就是 PHP 没有语言规范,很多版本间的语法还会不兼容(甚至是小版本号,比如 5.2.1 和 5.2.3),PHP 语言规范究竟如何定义呢?来看一篇来自 IEEE 的说法:
The PHP group claim that they have the final say in the specification of (the language) PHP. This groups specification is an implementation, and there is no prose specification or agreed validation suite.
所以唯一的途径就是老老实实去看 Zend 的实现,好在 HPHPc 中已经痛苦过一次了,所以 HHVM 能直接利用现成,因此这个问题并不算太大。

语言还是扩展?

实现 PHP 语言不仅仅只是实现一个虚拟机那么简单,PHP 语言本身还包括了各种扩展,这些扩展和语言是一体的,Zend 不辞辛劳地实现了各种你可能会用到的功能。如果分析过 PHP 的代码,就会发现它的 C 代码除去空行注释后居然还有80+万行,而你猜其中 Zend 引擎部分有多少?只有不到10万行。
对于开发者来说这不是什么坏事,但对于引擎实现者来说就很悲剧了,我们可以拿 Java 来进行对比,写个 Java 的虚拟机只需实现字节码解释及一些基础的 JNI 调用,Java 绝大部分内置库都是用 Java 实现的,所以如果不考虑性能优化,单从工作量看,实现 PHP 虚拟机比 JVM 要难得多,比如就有人用8千行的 TypeScript 实现了一个 JVM Doppio
而对于这个问题,HHVM 的解决办法很简单,那就是只实现 Facebook 中用到的,而且同样可以先用 HPHPc 中之前写过的,所以问题也不大。

实现 Interpreter

接下来是 Interpreter 的实现,在解析完 PHP 后会生成 HHVM 自己设计的一种 Bytecode,存储在 ~/.hhvm.hhbc(SQLite 文件) 中以便重用,在执行 Bytecode 时和 Zend 类似,也是将不同的字节码放到不同的函数中去实现(这种方式在虚拟机中有个专门的称呼:Subroutine threading
Interpreter 的主体实现在 bytecode.cpp 中,比如 VMExecutionContext::iopAdd 这样的方法,最终执行会根据不同类型来区分,比如 add 操作的实现是在 tv-arith.cpp 中,下面摘抄其中的一小段
if (c2.m_type == KindOfInt64)  return o(c1.m_data.num, c2.m_data.num);
if (c2.m_type == KindOfDouble) return o(c1.m_data.num, c2.m_data.dbl);
正是因为有了 Interpreter,HHVM 在对于 PHP 语法的支持上比 HPHPc 有明显改进,理论上做到完全兼容官方 PHP,但仅这么做在性能并不会比 Zend 好多少,由于无法确定变量类型,所以需要加上类似上面的条件判断语句,但这样的代码不利于现代 CPU 的执行优化,另一个问题是数据都是 boxed 的,每次读取都需要通过类似 m_data.num 和 m_data.dbl 的方法来间接获取。
对于这样的问题,就得靠 JIT 来优化了。

实现 JIT 及优化

首先值得一提的是 PHP 的 JIT 之前并非没人尝试过:
那么究竟什么是 JIT?如何实现一个 JIT?
在动态语言中基本上都会有个 eval 方法,可以传给它一段字符串来执行,JIT 做的就是类似的事情,只不过它要拼接不是字符串,而是不同平台下的机器码,然后进行执行,但如何用 C 来实现呢?可以参考 Eli 写的这个入门例子,以下是文中的一段代码:
unsigned char code[] = {
  0x48, 0x89, 0xf8,                   // mov %rdi, %rax
  0x48, 0x83, 0xc0, 0x04,             // add $4, %rax
  0xc3                                // ret
};
memcpy(m, code, sizeof(code));
然而手工编写机器码很容易出错,所以最好的有一个辅助的库,比如的 Mozilla 的 Nanojit 以及 LuaJIT 的 DynASM,但 HHVM 并没有使用这些,而是自己实现了一个只支持 x64 的(另外还在尝试用 VIXL 来生成 ARM 64 位的),通过 mprotect 的方式来让代码可执行。
但为什么 JIT 代码会更快?你可以想想其实用 C++ 编写的代码最终编译出来也是机器码,如果只是将同样的代码手动转成了机器码,那和 GCC 生成出来的有什么区别呢?虽然前面我们提到了一些针对 CPU 实现原理来优化的技巧,但在 JIT 中更重要的优化是根据类型来生成特定的指令,从而大幅减少指令数和条件判断,下面这张来自 TraceMonkey 的图对此进行了很直观的对比,后面我们将看到 HHVM 中的具体例子:
HHVM 首先通过 interpeter 来执行,那它会在什么时候使用 JIT 呢?常见的 JIT 触发条件有 2 种:
  • trace:记录循环执行次数,如果超过一定数量就对这段代码进行 JIT
  • method:记录函数执行次数,如果超过一定数量就对整个函数进行 JIT,甚至直接 inline
关于这两种方法哪种更好在 Lambada 上有个帖子引来了各路大神的讨论,尤其是 Mike Pall(LuaJIT 作者) 、Andreas Gal(Mozilla VP) 和 Brendan Eich(Mozilla CTO)都发表了很多自己的观点,推荐大家围观,我这里就不献丑了。
它们之间的区别不仅仅是编译范围,还有很多细节问题,比如对局部变量的处理,在这里就不展开了
但 HHVM 并没有采用这两种方式,而是自创了一个叫 tracelet 的做法,它是根据类型来划分的,看下面这张图
可以看到它将一个函数划分为了 3 部分,上面 2 部分是用于处理 $k 为整数或字符串两种不同情况的,下面的部分是返回值,所以看起来它主要是根据类型的变化情况来划分 JIT 区域的,具体是如何分析和拆解 Tracelet 的细节可以查看 Translator.cpp 中的 Translator::analyze 方法,我还没空看,这里就不讨论了。
当然,要实现高性能的 JIT 还需进行各种尝试和优化,比如最初 HHVM 新增的 tracelet 会放到前面,也就是将上图的 A 和 C 调换位置,后来尝试了一下放到后面,结果性能提示了 14%,因为测试发现这样更容易提前命中响应的类型
JIT 的执行过程是首先将 HHBC 转成 SSA (hhbc-translator.cpp),然后对 SSA 上做优化(比如 Copy propagation),再生成本地机器码,比如在 X64 下是由 translator-x64.cpp 实现的。
我们用一个简单的例子来看看 HHVM 最终生成的机器码是怎样的,比如下面这个 PHP 函数:
<?php
function a($b){
  echo $b + 2;
}
编译后是这个样子:
mov rcx,0x7200000
mov rdi,rbp
mov rsi,rbx
mov rdx,0x20
call 0x2651dfb <HPHP::Transl::traceCallback(HPHP::ActRec*, HPHP::TypedValue*, long, void*)>
cmp BYTE PTR [rbp-0x8],0xa
jne 0xae00306
; 前面是检查参数是否有效

mov rcx,QWORD PTR [rbp-0x10]           ; 这里将 %rcx 被赋值为1了
mov edi,0x2                            ; 将 %edi(也就是 %rdi 的低32位)赋值为2
add rdi,rcx                            ; 加上 %rcx
call 0x2131f1b <HPHP::print_int(long)> ; 调用 print_int 函数,这时第一个参数 %rdi 的值已经是3了

; 后面暂不讨论
mov BYTE PTR [rbp+0x28],0x8
lea rbx,[rbp+0x20]
test BYTE PTR [r12],0xff
jne 0xae0032a
push QWORD PTR [rbp+0x8]
mov rbp,QWORD PTR [rbp+0x0]
mov rdi,rbp
mov rsi,rbx
mov rdx,QWORD PTR [rsp]
call 0x236b70e <HPHP::JIT::traceRet(HPHP::ActRec*, HPHP::TypedValue*, void*)>
ret 
而 HPHP::print_int 函数的实现是这样的:
void print_int(int64_t i) {
  char buf[256];
  snprintf(buf, 256, "%" PRId64, i);
  echo(buf);
  TRACE(1, "t-x64 output(int): %" PRId64 "\n", i);
}
可以看到 HHVM 编译出来的代码直接使用了 int64_t,避免了 interpreter 中需要判断参数和间接取数据的问题,从而明显提升了性能,最终甚至做到了和 C 编译出来的代码区别不大。
需要注意:HHVM 在 server mode 下,只有超过12个请求就才会触发 JIT,启动过 HHVM 时可以通过加上如下参数来让它首次请求就使用 JIT:
-v Eval.JitWarmupRequests=0
所以在测试性能时需要注意,运行一两次就拿来对比是看不出效果的。

类型推导很麻烦,还是逼迫程序员写清楚吧

JIT 的关键是猜测类型,因此某个变量的类型要是老变就很难优化,于是 HHVM 的工程师开始考虑在 PHP 语法上做手脚,加上类型的支持,推出了一个新语言 - Hack(吐槽一下这名字真不利于 SEO),它的样子如下:
<?hh
class Point2 {
  public float $x, $y;
  function __construct(float $x, float $y) {
    $this->x = $x;
    $this->y = $y;
  }
}
//来自:https://raw.github.com/strangeloop/StrangeLoop2013/master/slides/sessions/Adams-TakingPHPSeriously.pdf
注意到 float 关键字了么?有了静态类型可以让 HHVM 更好地优化性能,但这也意味着和 PHP 语法不兼容,只能使用 HHVM。
其实我个人认为这样做最大的优点是让代码更加易懂,减少无意的犯错,就像 Dart 中的可选类型也是这个初衷,同时还方便了 IDE 识别,据说 Facebook 还在开发一个基于 Web 的 IDE,能协同编辑代码,可以期待一下。

你会使用 HHVM 么?

总的来说,比起之前的 HPHPc,我认为 HHVM 是值得一试的,它是真正的虚拟机,能够更好地支持各种 PHP 的语法,所以改动成本不会更高,而且因为能无缝切换到官方 PHP 版本,所以可以同时启动 FPM 来随时待命,HHVM 还有 FastCGI 接口方便调用,只要做好应急备案,风险是可控的,从长远来看是很有希望的。
性能究竟能提升多少我无法确定,需要拿自己的业务代码来进行真实测试,这样才能真正清楚 HHVM 能带来多少收益,尤其是对整体性能提升到底有多少,只有拿到这个数据才能做决策。
最后整理一下可能会遇到的问题,有计划使用的可以参考:
  • 扩展问题:如果用到了 PHP 扩展,肯定是要重写的,不过 HHVM 扩展写起来比 Zend 要简单的多,具体细节可以看 wiki 上的例子
  • HHVM Server 的稳定性问题:这种多线程的架构运行一段时间可能会出现内存泄露问题,或者某个没写好的 PHP 直接导致整个进程挂掉,所以需要注意这方面的测试和容灾措施。
  • 问题修复困难:HHVM 在出现问题时将比 Zend 难修复,尤其是 JIT 的代码,只能期望它比较稳定了。
P.S. 其实我只了解基本的虚拟机知识,也没写过几行 PHP 代码,很多东西都是写这篇文章时临时去找资料的,由于时间仓促水平有限,必然会有不正确的地方,欢迎大家评论赐教 :)
2014年1月补充:目前 HHVM 在鄙厂的推广势头很不错,推荐大家在2014年尝试一下,尤其是现在兼容性测试已经达到98.58%了,修改成本进一步减小。

引用

--------------------------
php7与hhvm的效能之争

鳥哥(惠新宸,PHP語言開發者之一)在2014年的Qcon分享中有一個數據,全球排名前100萬的網站中,81.3%使用的Web服務端腳本語言是PHP,2013年同期是78.3%。也就是說,PHP的在Web服務方面並沒有減少,只是在移動互聯網浪潮中,增加了很多的其他語言技術的應用,進而被稀釋了。
最近關於PHP7和HHVM的性能對比,成為了一個熱點的爭議話題,大家都在討論和關注哪一個才是PHP性能提升的未來。

HHVM(HipHop Virtual Machine)的起源

HHVM是一個開源的PHP虛擬機,使用JIT的編譯方式以及其他技術,讓PHP代碼的執行性能大幅提升。據傳,可以將當前版本的原生PHP代碼提升5-10倍的執行性能。
HHVM起源於Facebook公司,Facebook早起的很多代碼是使用PHP來開發的,但是,隨著業務的快速發展,PHP執行效率成為越來越明顯的問題。為了優化執行效率,Facebook在2008年就開始使用HipHop,這是一種PHP執行引擎,最初是為了將Fackbook的大量PHP代碼轉成 C++,以提高性能和節約資源。使用HipHop的PHP代碼在性能上有數倍的提升。後來,Facebook將HipHop平台開源,逐漸發展為現在的HHVM。
1. PHP為什麼慢?
PHP的慢是相對於C/C++級別的語言來說,事實上,PHP語言最初的設計,就不是用來解決計算密集型的應用場景。我們可以這樣粗略理解為,PHP為了提升開發效率,而犧牲了執行效率。
我們知道PHP一個很大的特點,就是弱類型特性,也就是說,我可以隨意定義一個變量,然後給它隨意賦值為各種類型的數據。以一個int整型數字為例子,在C語言中:
int num = 200;//通常是4字節
但是,如果是PHP定義了一個同樣的變量,實際對應的存儲結構則是:
 
這個結構體將會佔據遠比C變量多得多的內存,PHP中定義方式如下:
$a = 200;//這變量將實際佔用對比C變量很多倍的存儲空間。
其實對PHP來說,無論存儲什麼類型的數據,都是用上述“通殺”的結構體實現。為了兼容PHP程序員的變量類型“亂入”,PHP做到了對開發者的友好,但是對執行引擎很殘酷。單個變量內存消耗可能還不明顯,一旦用到PHP的數組等,則複雜度指數上升(數組的實現是HashTable)。然後,Zend引擎執行時,將這些PHP代碼編譯為opcode(PHP的中間字節碼,格式有點類似於彙編),由Zend引擎逐行解釋執行。
無論是字符串的連接操作,還是數組的簡單修改等,幾乎都是“PHP程序員一句話,Zend引擎跑斷腿”的節奏。因此,同樣的操作,對比C來說,PHP消耗了更多的CPU和內存等系統資源。除此之外,還有內存自動回收、變量類型判斷等等,都會增加系統資源的消耗。
例如,我用純PHP實現的快速排序函數和原生sort函數,排序10000個整型數字,來做一個耗時對比,結果如下:
 
原生的sort耗時3.44 ms,而我們自己實現的PHP函數sort則是68.79 ms。我們發現,兩者執行效率差距巨大。我的測試方式,是計算函數執行前後的時間間隔,而不是整個PHP腳本從啟動到結束的時間。PHP腳本啟動和關閉過程,本身有著一系列的初始化和清理工作,也會佔據不少的耗時。 
 

通常情況下,PHP執行效率的排行是:

  1. 最快的是PHP語言結構(isset、echo等),PHP語言的一部分(它們根本不是函數)。
  2. 然後比較快的就是PHP的原生和拓展函數。PHP拓展,基於Zend API之上,用C實現的功能,執行效率和C++/Java是屬於同一個數量級的。
  3. 真正慢的就是,我們通過PHP自己寫的代碼和函數。例如,假如我們使用的比較重的純PHP實現的框架,因為框架本身的模塊很多,所以,會明顯拖累語言層面的執行效率,同時佔據更多的內存。(國內的Yaf框架,以拓展的方式實現,因此執行效率遠快於純PHP寫的框架)

 
在一般情況下,我們並不推薦用過PHP實現邏輯複雜計算類型的功能,尤其是Web系統流量比較大的場景下。因此,PHP程序員應該對PHP的各種原生函數和各類拓展有一個比較廣泛的瞭解,在具體的功能實現場景中,尋求更原生的解決方案(原生接口或者拓展),而不是自己寫一堆複雜的PHP代碼來實現這類型功能。
如果有足夠的PHP拓展開發實力,將這類型業務功能重寫為一個PHP拓展,也會大幅提升代碼的執行效率。這是一個非常不錯的方式,也被廣泛應用PHP優化中。但是,自己編寫的PHP業務拓展的缺點也很明顯:

  1. 拓展開發耗時比較長,需求變更的時候修改也複雜,寫得不好可能會影響Web服務穩定性。(例如,在Apache的worker模式下,多線程場景下掛掉,會影響同一個進程下的其他正常子線程。如果是多線程的Web模式,編寫拓展還需要支持線程安全)
  2. 拓展在PHP版本升級的時候,可能需要做額外的兼容工作。
  3. 人員變動後的維護和接手成本也比較高。

實際上,在互聯網一線企業中,更常見的解決方案,並非增加PHP拓展,而用C/C++獨立寫一個服務server,然後PHP通過socket和服務server通信來完成業務處理,並不將PHP本身和業務耦合在一起。
不過,Web服務大部分的性能瓶頸都在網絡傳輸和其他服務server的耗時上(例如MySQL等),PHP執行的耗時在整體耗時的佔用比例非常小,所以從業務角度來說,影響可能並不明顯。
2. HHVM提升PHP執行性能的方式
HHVM提升PHP性能的途徑,採用的方式就是替代Zend引擎來生成和執行PHP的中間字節碼(HHVM生成自己格式的中間字節碼),執行時通過JIT(Just In Time,即時編譯是種軟件優化技術,指在運行時才會去編譯字節碼為機器碼)轉為機器碼執行。Zend引擎默認做法,是先編譯為opcode,然後再逐條執行,通常每條指令對應的是C語言級別的函數。如果我們產生大量重複的opcode(純PHP寫的代碼和函數),對應的則是Zend多次逐條執行這些C代碼。而JIT所做的則是更進一步,將大量重複執行的字節碼在運行的時候編譯為機器碼,達到提高執行效率的目的。通常,觸發JIT的條件是代碼或者函數被多次重複調用。
 
普通的PHP代碼,因為無法固定變量的類型,需要額外添加判斷類型的邏輯代碼,這樣PHP代碼是不利於CPU執行和優化的。因此,HHVM通常需要用到Hack寫法(為了兼容某種特性而額外添加的技巧性質的代碼)的PHP代碼來“配合”,就是為了讓變量類型固定,方便虛擬機編譯執行。PHP追求以一種形式來容納一切類型,而Hack則可以將被容納的一切標記上確定的類型。
PHP代碼的Hack寫法的例子:
 
上面的例子中,PHP代碼主要被添加上了變量類型。Hack寫法的總體方向,就是將之前“動態”的寫法變為“靜態”的寫法,來配合HHVM。
HHVM因為它的高性能而吸引了不少人的關注,一些一線互聯網公司也開始跟進使用。從純語言執行性能測試結果來看,HHVM領先了開發中的PHP7版本不少。
 
不過,從具體業務場景來看,HHVM和PHP7的差距並沒有那麼大,以WordPress開源博客首頁為測試場景的結果中,他們目前的差距並不明顯。 
 
但是,PHP7目前還在開發中,就已經可用的技術方案來看,目前的HHVM略勝一籌。不過,HHVM的部署和應用都存在一些的問題:
  1. 服務部署比較複雜,有一定維護成本。
  2. 對PHP原生代碼並非完整支持,PHP拓展也需要做適當的兼容。
  3. HHVM是個新虛擬機,長時間運行有內存洩露。(據說,一線互聯網公司在應用這個技術時,是通過自己打Patch的方式解決內存洩露)
HHVM畢竟是一個相對比較新的開源項目,發展到成熟仍然需要一定時間。

PHP7的性能革新

PHP長期以來飽受批評的性能問題,將會在這個版本得到大幅度的改善。版本中間沒有PHP6哈,據說,是因為這個版本曾經立過項目,後來大部分功能都在5.x的版本裡實現了,為了避免混淆,下一個大版本直接就是PHP7。(幾年以前,我還看到過關於PHP6的書籍。)
1. PHP7的介紹
雖然PHP7的正式版本可能要到2015年的10月份才發佈,不過明年6月份應可以看見一個測試版本了,之後是3-4個月的質量保證。
PHP社區的項目計畫如下:
 
因為項目仍然處於開發中的原因,從表格中,可以看見的特性描述都比較模糊。肯定有更多的其他特性,只是尚未公佈。下面的這些,是從PHP社區看見的,因為PHP7是一個開發中的項目,下面的這些也不一定準確,不過,不妨礙我們一起來看看。
  1. PHPNG(PHP next generation,下一代PHP),對Zend執行引擎本身的各種性能優化,其中JIT,可能會實現在Zend Opcache組件中。
  2. AST(Abstract Syntax Tree,抽象語法樹),目的是在PHP編譯過程引入一個中間件,替代直接從解釋器吐出opcode的方式。讓解釋器和編譯器解耦,可以減少大量Hack代碼,同時,讓實現更容易理解和維護。
  3. uniform variable syntax(統一變量語法),引入一種內部一致和完整的變量語法,讓PHP的解析器更完整地支持各種類型的變量。部分變量的用法需要調整,例如變量的變量$$a等。
  4. 支持integer semantics(整型語義),例如NaN、Infinity、<<、>>,修正list()的一致性等等。

上面的特性中,最令人期待的就是PHPng的性能優化,PHP社區已經放出了一些性能的測速數據。從數據上看,PHPng的執行性能比起項目啟動之初,已經有接近1倍的提升。這個成績已經非常不錯,況且,最關鍵的是PHP7的優化計畫還有很多尚未完成。等到都全部完成了,相信我們可以看見一個性能更高的PHP7。
這測速數據是來自於PHP社區(wiki.php.net/phpng),截取了一部分的數據:
 
對其當前PHP5.6版本,PHPNG的10月份性能提升已經非常明顯了: 
 
簡單翻譯下:

  • 綜合測試速度提升35%。
  • 在實際應用場景有20%-70%的速度提升(WordPress首頁有60%的提升)
  • 更少的內存消耗
  • 支持大部分常用的SAPIs
  • 支持大部分的PHP拓展綁定到資源分配(69個完成,6個待遷移)
  • 提供堪比HHVM3.3.0的執行速度

2. PHP的弱類型爭議
PHP被爭議的特點很多,但是隨著語言版本的發布和完善,功能和特性方面的批評開始變少了。但是,PHP的“弱類型”特性,卻明顯受到更多的爭議,從HHVM通過Hack的方式直接“去掉”了“弱類型”特性可以看出,HHVM並不喜歡“弱類型”特性。然而,在我們很多PHP程序員的眼中,這卻是PHP的重要優點之一。PHP裡的變量被設計得隨性和飄逸,海納百川,一切皆可包容,不是讓語言顯得更為簡單嗎?
實際上,有些人認為它是個嚴重的問題,對於“弱類型”的批評觀點大致如下:
  1. 在“嚴謹”的語言中,通常是預先定義好一個變量的類型,自始至終,變量的類型是固定的,使用範圍也是固定。而PHP的變量,通常我們只能看見它名字,類型大部分都不可以預先定義,並且還可以隨意改變。(內存分配不好管理)
  2. 為了兼容弱類型特性,PHP需要實現大量兼容代碼,包括類型判斷、類型轉換、存儲方式等,增加了語言內部的複雜度。(執行效率低下)
  3. 變量的類型是不可控的,在執行過程中存在大量的“隱性類型轉換”,容易產生不可預知的結果。(這裡的確需要強調,PHP的類型轉換是個必須掌握的點,各種類型的互相轉換的可能會產生很多問題,尤其是初學PHP的同學哈)

他們認為,這些都不符合“所見即所得”的簡單性,而語法嚴謹的語言更高效率,也更容易“理解”。
受到類似批評的還有Javascript等語言,因為它在這個問題上的表現是一樣的。但是,一門語言最終被大規模使用,必然有它們的道理。PHP成為Web服務開發的首選腳本語言,Javascript則直接稱霸Web前端領域,能走到這一步都不可能是偶然因素,開發者們用腳投票選擇了它們。編程語言是人類和機器溝通的橋樑,終極追求是實現“人人皆可編程”的宏偉目標。
縱觀語言發展歷史,從0和1的機器碼開始,到彙編語言,然後到C語言,再到動態腳本語言PHP。執行效率呈指數下降,但是,學習門檻也呈指數降低。PHP語言不僅屏蔽了C的內存管理和指針的複雜性,而且更進一步屏蔽了變量類型的複雜性。提升了項目開發的效率,降低了學習的門檻,但同時犧牲了一定的執行性能。然後,HHVM的Hack給我們一種“回歸原始”的感覺,重新引入了變量的複雜性。當然,不同的語言解決不同場景下的問題,並不能夠一概而論。
 

小結

HHVM對PHP的性能提升,讓人眼前一亮,而磨刀霍霍的PHP7則讓人萬分期待。兩者都是極其優秀的開源項目,都在不斷前進和發展中。就目前而言,因為距離PHP7正式版的發布還有比較長的一段時間,所以當前性能優化方案的首選當然是HHVM。不過,就我個人而言,我比較看好PHP7,因為它更能做到PHP代碼的向下兼容。如果兩者性能相差不大,我會選擇簡單的那個。
參考資料:
from http://inspiregate.com/programming/php/468-php7-performance-and-hhvm-dispute.html
-----------

PHP 7 vs. HHVM Comparison

Let's look at PHP 7 and Hip Hop Virtual Machine: pros and cons of each, benchmarks, and more.

PHP is one of the most popular scripting languages used for web development. The latest version of PHP, PHP 7 is a new version of the language that is been optimized for fast performance. However, PHP has a rival in HHVM (HipHop Virtual Machine) — a virtual tool that executes PHP code. The competition between these two options is heating up, so let’s take a look at the performance that each can offer.

What is HHVM?

In 2008, Facebook started working on a tool to convert PHP script into C++ so it could be compiled and executed on web servers. The aim was to conserve server resources, an important goal, as Facebook’s user base was growing rapidly. In this sense, the project was a success; it allowed the server to accommodate between five and six times more traffic than it had managed before.
Fast-forward a couple years to 2010. Facebook’s server needs had grown even more, placing it in a position to require another innovation to allow it to operate more efficiently. In response to this demand, Facebook developed the HipHop Virtual Machine (HHVM).
HHVM uses Just-In-Time (JIT) compilation to convert PHP code into a type of bytecode. It then converts this bytecode into machine code and optimizes it so that it runs as quickly as possible.

What is PHP 7?

PHP 7 is the PHP community’s response to HHVM. Early announcements of the launch of PHP 7 claimed that it would offer better than 100 percent performance improvements over the previous version of the language, PHP 5.
You might be wondering why PHP skipped version 6. The answer is that development on PHP 6 began in 2005, but it went on so long and ran into so many problems that PHP 6 had developed a bad reputation long before it was ready for release. As a result, the PHP community decided to skip the name PHP 6 and go straight to PHP 7 for the new working version of the language.
The real question is not how PHP 7 compares to PHP 5, as it is pretty clear that PHP 7 offers speedier performance. Instead, the consideration is how PHP 7 compares to HHVM. Many experts have conducted tests on the two ways of handling PHP code, which have revealed some interesting results.

PHP 7 vs. HHVM: Similarities and Differences

Before answering the “which is better” question, let’s take a look at the key differences between PHP 7 and HHVM, as well as the ways in which they are similar.

Code Interpretation

The fundamental difference between PHP 7 and HHVM is the way in which each one interprets PHP code. PHP 7 uses the standard PHP interpreter, free software that is available for anyone to use, to directly interpret and execute PHP code on the server. This generates HTML code, which is then sent to the client. The client then displays the desired content to the web user.
In contrast, the Hip Hop Virtual Machine first converts PHP code into HipHop bytecode. This code is then translated into machine code and executed. Some optimization takes place during this translation, ironing out inefficiencies in PHP code with the aim of delivering faster performance.

Writing Code

Both the PHP interpreter and HHVM take PHP code and execute it. Therefore, the process of writing the code is pretty much the same in each case. However, if you want to use HHVM, you need to install it on your server and then call it using the hhvm command on the command line.

Benchmark Testing

HHVM has offered much faster performance than previous versions of PHP. However, recent benchmark tests suggest that PHP 7 is slightly faster than HHVM, at least in some situations. Let’s take a look at the results of some benchmark testingconducted by Kinsta.
  • WordPress: Running on WordPress 4.1.1, PHP 7 allows more than twice as many requests to be executed per second as PHP 5.6. However, it still doesn’t process quite as many as HHVM 3.6.1, which executed 624 requests per second in the test compared to just 604 executed each second by PHP 7. 
  • Drupal: PHP 7 offers a distinct advantage over HHVM for Drupal users. PHP 7 can handle 37 percent more server requests per second compared to HHVM on Drupal 8. 

Which Companies Use HHVM?

In addition to Facebook, which developed HHVM, many other businesses have adopted this solution to running PHP applications on their own servers. These include Wikimedia and the e-commerce site Etsy.
  • Wikimedia: Wikimedia hosts a huge range of educational content, including the famous Wikipedia online encyclopedia. Attracting nearly half a billion Internet users each month, Wikimedia needs to optimize server performance to cope with its high level of demand. HHVM poses a significant advantage over PHP in that it can load multiple SPU cores simultaneously whereas PHP is a single-threaded language that can’t be parallelized. According to Wikimedia, deploying HHVM shrank CPU load from 50 to just 10 percent, halved the mean time taken to respond to users submitting edits and reduced the average page load time from 1.3 seconds to just 0.9 seconds. 
  • Etsy: With 54 million users, Etsy’s servers also face significant demands. Etsy engineers compared HHVM to PHP 5.4 and found that HHVM could cope with up to 280 server requests per second whereas the response time of PHP 5.4 started to dramatically increase once the number of requests grew beyond 190 per second. 

What Does the Future Hold for PHP 7 and HHVM?

PHP 7 is due for stable release in November 2015. Therefore, companies are not yet using the new language, but promising benchmark test results of the performance of the beta version of PHP 7 could tempt more companies to adopt the new version of the language.
The future looks bright for PHP 7, but what about HHVM? It is likely that it is far from dead. Many businesses are already using HHVM to increase performance on their sites. The transition between PHP and HHVM is not instantaneous. It took Etsy more than six months to complete the transition. With the speed benefits of PHP 7 compared to HHVM being only very slight, it is unlikely that businesses will rush to switch back to PHP.
Facebook is continuing to develop HHVM. It has recently announced support for Mac OS X, making the technology accessible for developers who prefer to work in the Apple development environment. HHVM developers are convinced thatHHVM is still faster than PHP 7 in many situations, including with WordPress.

Why Does the HHVM vs. PHP 7 Competition Matter to PHP Shop Owners?

As an online store owner, you need to make your decision on whether to use PHP 7 or HHVM based on the platform that hosts your shop. For example, if your site is built using WordPress, take a look at benchmark tests for HHVM and PHP 7 to find out how the latest release of each one performs. You want to choose the solution that can offer the biggest reduction in page load times, server response times and CPU usage.

Reasons to Choose HHVM

  • HHVM uses dynamic translation to deliver faster performance in many situations, including on WordPress. 
  • HHVM uses less memory to process each request in cases where it faces a very large number of requests. 
  • HHVM developers are steadily increasing the number of PHP code bases that the engine can run. It can already run the latest version of WordPress, along with many other common PHP frameworks and applications. 
  • HHVM is open source. Even though HHVM has been developed by Facebook, it is open source, which means the source code is available to anyone who wants to use or alter it. 

Reasons to Choose PHP 7

  • PHP 7 performs faster than HHVM in some situations, including when running on Drupal 8. 
  • Using PHP 7 doesn’t require you to install or setup HHVM. 
  • Code written in PHP 5 should work as expected after a transition to PHP 7, although some features of PHP 4 code are no longer supported in the new release. In practice, this means that any code created in the last decade is probably ready for the transition to PHP 7. 
  • PHP 7 is developed by the PHP community, a group with a long-standing reputation for creating stable and reliable PHP releases. 

HHVM vs. PHP 7: Make Your Choice

Don’t agonize for too long over the decision. Kinsta recommends that online businesses choose quickly between PHP 7 and HHVM. The sooner you make your decision, the sooner you can begin to implement the solution, allowing you to optimize your website performance. A poorly performing website can cause your reputation to suffer, which can be difficult to reverse.
Both HHVM and PHP 7 offer significant benefits compared to older versions of PHP. Make your choice and start the process of switching your site to the new system as soon as possible。
from https://dzone.com/articles/php-7-vs-hhvm-comparison
-----------

An Introduction to HHVM

just-in-time (JIT) compiler. In these respects, HHVM has similarities to virtual machines for other languages including C#/CLR and Java/JVM.

A little big of history

In early 2008 Facebook began working on HipHop(now HPHP), a PHP execution engine; its original motivation was to convert Facebook massive PHP code base into C++ in order to save resources and increase the application performance. The original release was known as HPHPc a PHP to C++ compiler.
For next 2 years Facebook continued working on HipHop adding HPHPi ( a 'developer mode' version of HPHP) and HipHop debugger known as HPHPd, this allowed developers to watch and step through the code and interactively debug PHP applications running on the HipHop platform.
At it's peak, HipHop PHP code showed up to 6x times better performance than its ZEND counterpart.However, there where several drawbacks to this first iteration of HipHop:
  • HPHPc did not fully supported the PHP language, most noticeably the lack of support for create_function() and eval() --Honestly, I don't see the lack of support for the last one as something bad-- functions.
  • Facebook developers had to maintain two difference engines (HPHPc and HPHPi) with resulted in duplication of efforts and waste of resources.
  • Finally, HPHPc required a vastly different deployment process which will hurt adoption by PHPdevelopers.
In light of these problems Facebook took two key actions on early 2010, the first was to open source the HipHop platform. -- Open sourcing a project like this is a great way to build a community around the project and getting external help from that community --/
At the same time Facebook started the development of the modern version of HipHop, known as HHVM (HipHop Virtual Machine), HHVM improves the strengths of HPHPc and corrects many of the critical problems.
HHVM was build on top of HPHPc and it works by converting PHP code into high level bytecode(an intermediate language) this bytecode is the translated into machine code dynamically at runtime by a JIT (Just-In-Time) compiler.
If you are like me you probably have a vague recollection of the concepts of bytecode, machine code and Just-In-Time compilers, so let's take a momentarily side step and quickly review these concepts and how the they play a key role on HHVM.

Bytecode, Machine code, JIT, Oh my ...!

  • Bytecode: Is a non human readable code designed for efficient execution by an interpreter or compiler.When HHVM first loads our project it converts all the PHP code into this intermediary form of bytecode; the bytecode generate is not particular to any type of architecture and could be portable among different systems.
  • Machine code: Are a set of instructions designed to be executed directly by the CPU. If you ever played with Assembly (Who hasn't !?) you know very well what machine code is, for those very few of you who haven't had the pleasure of working on assembly or similar languages; machine code is generated by the compiler or interpreter and then handed to the CPU
  • JIT (Just In Time) compiler: Just in time compilation is a technique used to improve performance of software, this is achieved by compiling bytecode during execution, the byte code is store in memory and then the JIT compiler loads and compiles as many sections of the byte code as needed.
The performance and speed gained by applying these techniques is what gives HipHop and subsequently HHVM its core strengths. Keeping a PHP code base while achieving performance comparable to compiled applications.
Currently HHVM supports PHP 5.4 almost on its entirety, however there are still numerous bugs that prevent some applications from running, for that reason Facebook has set as goal to have the top 20 open source PHP applications running on HHVM. The first popular application to achieve this was Wordpress.

What's next

So now that we have a better understanding of what HHVM does and the advantages if running it we can start testing our applications on HHVM. In a subsequent post I will be covering the setup of a dedicated Vhost for HHVM, running benchmarks against your applications and eventually (fingers crossed) how to run Magento on HHVM.
from http://coderoncode.com/hhvm/programming/development/vagrant/2013/07/24/introduction-hhvm.html