實戰 hhvm extension php conf 2014

Post on 28-Nov-2014

120 Views

Category:

Internet

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

HHVM 是 Facebook 開發的一個高效能 PHP 虛擬機用來取代行之有年的 Zend Engine。 但是,在獲得更高效能的同時也意味著原本 PECL 上的大量 Extension 必須一一改寫。 藉由這個議程可以了解到如何透過 HNI 界面,混用 C++ 以及 Hack Lang。 在效能以及開發速度上取得平衡,撰寫出屬於自己的 HHVM Extension。

TRANSCRIPT

實戰 HHVM Extension

Ricky Su@phpconf2014

About me

Ricky 是我 哥

● Symfony 愛好者

● PHP也有Day 固定攝影師。

● 目前在 擔任高級水電工。

● ricky@ez2.us

● http://www.facebook.com/ricky.su.35

● http://ricky.ez2.us/ (目前Server掛點中)

玩體驗

HHVM是什麼?

● 由 Facebook 於 2010年2月2日發布

● 將 PHP 轉換成 C++,再透過 g++ 編

譯執行檔。

● 於2013年2月19日被官方棄用。

HipHop (HPHPc)

● 透過 JIT 的方式加速 PHP 執行。

● 運行速度已經超越 HPHPc。

● 除了 PHP 外,還支援了 Hack Lang。

● 只支援 x64 平台,未來會支援 ARM。

● 目前 Facebook 的 PHP 程式皆運行在

HHVM 上。

HHVM

HHVM != PHP (Zend Engine)

HHVM 的執行效能?

fibonacci(40) 殘酷考驗

fibonacci(40)

<?php function fibonacci($n) { return $n<2?$n:fibonacci($n-1)+fibonacci($n-2); }

HHVM benchmark

Less is better

HHVM Extension benchmark

Less is better

但是開發

HHVM Extension

有個東西一定要了解

Hack Lang

Hack = 強型態的 PHP

Hack Lang

<?hhfunction fibonacci(int $n):int{ return $n<2?$n:fibonacci($n-1)+fibonacci($n-2); }

Hack Lang

<?hhfunction print_nl(?string $n = null): void{ echo "$n\n";}

Hack Lang Reference

http://goo.gl/PPB64m

HHVM Extension requirement

● x64 OS● gcc >= 4.7.3● g++ >= 4.7.3● cmake >= 2.8.3

HHVM Extension

寫起來很複雜嗎

只要三個檔案

就可以寫出

fibonacci

config.cmakeHHVM_EXTENSION( fibonacci fibonacci.cpp)HHVM_SYSTEMLIB( fibonacci ext_fibonacci.php)

ext_fibonacci.php<?hh<<__Native>> function fibonacci(int $n): int;

fibonacci.cpp#include "hphp/runtime/base/base-includes.h"namespace HPHP {static int64_t HHVM_FUNCTION(fibonacci, int64_t n) { return n<2?n:HHVM_FN(fibonacci)(n-2) + HHVM_FN(fibonacci)(n-1);}static class FibonacciExtension : public Extension { public: FibonacciExtension() : Extension("fibonacci") {} virtual void moduleInit() { HHVM_FE(fibonacci); loadSystemlib(); }} s_fibonacci_extension;HHVM_GET_MODULE(fibonacci)} // namespace HPHP

build extension

$ hphpize$ cmake .$ make && make install

config.cmakeHHVM_EXTENSION( fibonacci fibonacci.cpp foo.cpp bar.cpp other.cpp)

extensionname

config.cmakeHHVM_EXTENSION( fibonacci fibonacci.cpp foo.cpp bar.cpp other.cpp)

cpp files

config.cmakeHHVM_SYSTEMLIB( fibonacci ext_fibonacci.php)

PHP檔案只能一個而且命名必須是 ext_ 開頭

HNI (HHVM Native Interface)<?hh<<__Native>> function fibonacci(int $n): int;

function echo_ fibonacci(int $n): void{ echo fibonacci($n);}

register extenstionstatic class FibonacciExtension : public Extension { public: FibonacciExtension() : Extension("fibonacci") {} virtual void moduleInit() {

HHVM_FE(fibonacci);

loadSystemlib(); }} s_fibonacci_extension;HHVM_GET_MODULE(fibonacci)

register extenstionstatic class FibonacciExtension : public Extension { public: FibonacciExtension() : Extension("fibonacci") {} virtual void moduleInit() {

HHVM_FE(fibonacci);

loadSystemlib(); }} s_fibonacci_extension;HHVM_GET_MODULE(fibonacci)

定義函數

register extenstionstatic class FibonacciExtension : public Extension { public: FibonacciExtension() : Extension("fibonacci") {} virtual void moduleInit() { HHVM_FE(fibonacci);

HHVM_FE(foo);

loadSystemlib(); }} s_fibonacci_extension;HHVM_GET_MODULE(fibonacci)

如果有還有其他函數接著定義

register extenstionstatic class FibonacciExtension : public Extension { public: FibonacciExtension() : Extension("fibonacci") {} virtual void moduleInit() {

HHVM_FE(fibonacci);

loadSystemlib(); }} s_fibonacci_extension;HHVM_GET_MODULE(fibonacci)

讀取HNI

implement function

static int64_t HHVM_FUNCTION(fibonacci, int64_t n) { return n<2?n:HHVM_FN(fibonacci)(n-2) + HHVM_FN(fibonacci)(n-1);}

implement function

static int64_t HHVM_FUNCTION(fibonacci, int64_t n) { return n<2?n:HHVM_FN(fibonacci)(n-2) + HHVM_FN(fibonacci)(n-1);}

函數回傳值型態

implement function

static int64_t HHVM_FUNCTION(fibonacci, int64_t n) { return n<2?n:HHVM_FN(fibonacci)(n-2) + HHVM_FN(fibonacci)(n-1);}

函數名稱

implement function

static int64_t HHVM_FUNCTION(fibonacci, int64_t n) { return n<2?n:HHVM_FN(fibonacci)(n-2) + HHVM_FN(fibonacci)(n-1);}

參數型態定義

implement function

static int64_t HHVM_FUNCTION(foo, int64_t n, const String &n2) { // ...}

如果有多個參數接著定義

型態對應PHP Type C++ Parameter

TypeC++ Return

Typevoid N/A void

bool bool bool

int int64_t int64_t

float double double

string const String & String

array const Array & Array

resource const Resource & Resource

object const Object & Object

mixed const Variant & Variant

以上官方文件

都可以查到

但是

也只能查到這些了

如果要知道更多

RTFSC

接下來要踩地雷了

Native Class

HNI<?hhclass foo { protected ?mixed $bar; <<__Native>> public function __construct(mixed $bar): void; <<__Native>> public function getBarNative(): ?mixed; public function getBar():?mixed { return $this->bar; }}

register extenstionstatic class FooExtension : public Extension { public: FooExtension() : Extension("foo") {} virtual void moduleInit() { HHVM_ME(foo, __construct); HHVM_ME(foo, getBarNative); loadSystemlib(); }} s_foo_extension;HHVM_GET_MODULE(foo)

register extenstionstatic class FooExtension : public Extension { public: FooExtension() : Extension("foo") {} virtual void moduleInit() { HHVM_ME(foo, __construct); HHVM_ME(foo, getBarNative); loadSystemlib(); }} s_foo_extension;HHVM_GET_MODULE(foo)

註冊 foo__construct

implement class method

static void HHVM_METHOD( __construct, const Variant &bar) { this_->o_set("bar", bar, "foo");}

implement class method

static void HHVM_METHOD( __construct, const Variant &bar) { this_->o_set("bar", bar, "foo");}

對應 PHP 中的 $this

implement class method

static void HHVM_METHOD( __construct, const Variant &bar) { this_->o_set("bar", bar, "foo");}

存入成員變數

implement class method

static void HHVM_METHOD( __construct, const Variant &bar) { this_->o_set("bar", bar, "foo");}

$this->bar

implement class method

static void HHVM_METHOD( __construct, const Variant &bar) { this_->o_set("bar", bar, "foo");}

$this->bar = $bar

implement class method

static void HHVM_METHOD( __construct, const Variant &bar) { this_->o_set("bar", bar, "foo");}

指定目前的 context 為 foo

implement class method

static Variant HHVM_METHOD(getBarNative) { return this_->o_get("bar", false, "foo");}

implement class method

static Variant HHVM_METHOD(getBarNative) { return this_->o_get("bar", false, "foo");}

$this->bar

implement class method

static Variant HHVM_METHOD(getBarNative) { return this_->o_get("bar", false, "foo");}

如果讀取 $this->bar

發生錯誤時是否要丟出 error

implement class method

static Variant HHVM_METHOD(getBarNative) { return this_->o_get("bar", false, "foo");}

指定目前的 context 為 foo

Type Casting

Type Castingvar.toBoolean();

var.toDouble();

var.toString();

var.toInt64();

var.toArray();

Object Access

Object AccessC++ PHPobject.o_get(...) $object->...

object.o_set(...) $object->xxx = xxx

object.instanceof(class) object instanceof class

String Access

String AccessC++ PHPstring = “hello ” + “world” $string = “hello ” . ”world”

string += “foo” $string .= “foo”

string1 == string2 $string1 == $string2

string[1] $string[1]

string.substr(1, 2) substr($string, 1, 2)

string.size() strlen($string)

Array Access

Array AccessVariant var = array[1];

Variant var = array[String(“key”)];

Array AccessC++ PHParray.set(1, var) $array[1] = $var

array.set(String(“key”), var) $array[“key”] = $var

array.append(var) $array[] = $var

array = make_packed_array(1, 2, “val”) $array = [1, 2, “val”]

array = Array::Create() $array = []

Resource

Resource data declarenamespace HPHP {

class InternalResourceData : public SweepableResourceData { public: virtual const String& o_getClassNameHook() const { return classnameof(); } DECLARE_RESOURCE_ALLOCATION(InternalResourceData) CLASSNAME_IS("InternalResourceData") InternalResourceData(FILE *file); virtual ~InternalResourceData(); FILE *getHandler();

private: FILE *file; };

}

Resource data declarenamespace HPHP {

IMPLEMENT_OBJECT_ALLOCATION(InternalResourceData) InternalResourceData::InternalResourceData(FILE *file) { this->file = file; }

InternalResourceData::~InternalResourceData() { fclose(file); }

FILE *InternalResourceData::getHandler(){ return file; }

}

Resource usagestatic Resource HHVM_FUNCTION(open_file, const String &filename) { FILE *file = fopen(filename.c_str(), "r"); Resource resource(NEWOBJ(InternalResourceData(file))); return resource;}

static String HHVM_FUNCTION(read_file, const Resource &resource) { FILE * file; InternalResourceData *resource_data = resource.getTyped<InternalResourceData>(); file = resource_data->getHandler(); // ...}

Reference Counting

Variables

Value$aref count = 1

$a = “some value”;

Variables

Value$aref count = 2

$b = $a;

$b

Variables

Value$aref count = 1

$b = null;

$b

Variables

Value$aref count = 0

$a = null;

$b

Variables

Value$aref count = 0

$a = null;

$b

delete value

HHVM Variables

Variable ValueObject ObjectDataString StringDataArray ArrayData

Resource ResourceData

Increase referenceObject var = some_object;

Object *var = new Object(some_object);

ObjectDara *value = some_object->get();

value->incRefCount();

Decrease referenceObject *var = new Object(some_object);

delete var;

ObjectDara *value = some_object->get();

value->decRefAndRelease();

HHVM密(ㄉ一ˋ)技(ㄌㄟˊ)

HHVM Extension 第三方 Library

set callback

HHVM Extension 第三方 Library

call callback

HHVM Extension 第三方 Library

call callback

接著就GG了...Crash

都是 they 的錯gcc -O2

因為gcc -O2 預設開啟

omit-frame-pointer

導致 HHVM rbp 指標出錯

解決方法

重新編譯第三方套件

gcc 加上

-fno-omit-frame-pointer

但請放棄這個念頭

請改用神秘的

JIT::VMRegAnchor _;

VMRegAnchor

static void HHVM_FE(someFunction) { JIT::VMRegAnchor _; //then call 3rd party library;}

在呼叫第三方library之前加上這段就OK了。

取得Global Variable

取得Global VariableArray global(get_global_variables()->asArrayData());

Array _SERVER = global[StaticString("_SERVER")].toArray();

Array _GET = global[StaticString("_GET")].toArray();

Array _POST = global[StaticString("_POST")].toArray();

取得 Constant

取得 Constant#if HHVM_API_VERSION >= 20140829L //HHVM 3.3.0 #include "hphp/runtime/ext/std/ext_std_misc.h"#else // HHVM 3.2.0 #include "hphp/runtime/ext/ext_misc.h"#endif

Variant some_conatant = HHVM_FN(constant)(StaticString("SOME_CONSTANT"));

呼叫 PHP 的某個函數

呼叫 PHP 的某個函數

vm_call_user_func(StaticString("printf"), make_packed_array("%s %s", "hello", "world"));

printf(“%s %s”, “hello”, “world”);

或是直接

call native function

hphp/runtime/ext/*.h這裡幾乎實作了所有php的函數

Call native function#include "hphp/runtime/ext/std/ext_std_variable.h"

HHVM_FN(print_r)(var); //print_r($var);

還有更多地雷由您來踩

有問題嗎?

Thanks

top related