顯示具有 apache 標籤的文章。 顯示所有文章
顯示具有 apache 標籤的文章。 顯示所有文章

2013年9月2日 星期一

PHP Extension (1) - 環境準備與Hello World

下列所有實作均以Ubuntu為範例,視不同distribution或版本可能指令與路徑均有不同

準備環境

$sudo apt-get install apache2 php5 php5-dev

Hello World

傳統PHP function要達到輸出hello world的方式
<?php
function hello_world() {  
  return 'Hello World';  
}
echo hello_world();
?>

若要使用PHP extension開發,要使用c語言實作出相同的function

test_hello_world.h
#ifndef PHP_TEST_HELLO_WORLD_H  
#define PHP_TEST_HELLO_WORLD_H  

extern zend_module_entry test_hello_world_module_entry;  
#define phpext_test_hello_world_ptr &test_hello_world_module_entry  

#ifdef PHP_WIN32  
#define PHP_TEST_HELLO_WORLD_API __declspec(dllexport)  
#else  
#define PHP_TEST_HELLO_WORLD_API  
#endif  

#ifdef ZTS  
#include "TSRM.h"  
#endif  

PHP_MINIT_FUNCTION(test_hello_world);  
PHP_MSHUTDOWN_FUNCTION(test_hello_world);  
PHP_MINFO_FUNCTION(test_hello_world);  

PHP_FUNCTION(hello_world);  

/*  
    Declare any global variables you may need between the BEGIN 
    and END macros here:      

    ZEND_BEGIN_MODULE_GLOBALS(test_hello_world) 
    long  global_value; 
    char *global_string; 
    ZEND_END_MODULE_GLOBALS(test_hello_world) 
 */  

#ifdef ZTS  
#define TEST_HELLO_WORLD_G(v) TSRMG(test_hello_world_globals_id, zend_test_hello_world_globals *, v)  
#else  
#define TEST_HELLO_WORLD_G(v) (test_hello_world_globals.v)  
#endif  

#endif  /* PHP_TEST_HELLO_WORLD_H */  

test_hello_world.cc
#ifdef HAVE_CONFIG_H  
#include "config.h"  
#endif  

#include "php.h"  
#include "php_ini.h"  
#include "ext/standard/info.h"  
#include "test_hello_world.h"  
#include "string"  

using namespace std;  

/* If you declare any globals in php_test_hello_world.h uncomment this: 
   ZEND_DECLARE_MODULE_GLOBALS(test_hello_world) 
 */  

function_entry test_hello_world_functions[] = {  
    PHP_FE(hello_world, NULL)  
    {NULL, NULL, NULL}  
};  

zend_module_entry test_hello_world_module_entry = {  
#if ZEND_MODULE_API_NO >= 20010901  
    STANDARD_MODULE_HEADER,  
#endif  
    "test_hello_world",  
    test_hello_world_functions,  
    PHP_MINIT(test_hello_world),  
    PHP_MSHUTDOWN(test_hello_world),  
    NULL, //RINIT  
    NULL, //RSHUTDOWN  
    PHP_MINFO(test_hello_world),  
#if ZEND_MODULE_API_NO >= 20010901  
    "$Revision: 1.5 $",  
#endif  
    STANDARD_MODULE_PROPERTIES  
};  

extern "C" {  
#ifdef COMPILE_DL_TEST_HELLO_WORLD  
    ZEND_GET_MODULE(test_hello_world)  
#endif  
}  

PHP_MINIT_FUNCTION(test_hello_world)  
{  
    return SUCCESS;  
}     

PHP_MSHUTDOWN_FUNCTION(test_hello_world)  
{  
    return SUCCESS;  
}     

PHP_MINFO_FUNCTION(test_hello_world)  
{  
    php_info_print_table_start();  
    php_info_print_table_header(2, "test_hello_world support", "enabled");  
    php_info_print_table_end();  
}     

PHP_FUNCTION(hello_world)  
{  
    string ret("hello world");  
    RETURN_STRING(const_cast(ret.c_str()), 1);  
}  

config.m4
PHP_ARG_ENABLE(test_hello_world, whether to enable test_hello_world support,  
Make sure that the comment is aligned:  
[  --enable-test_hello_world           Enable test_hello_world support])  

if test "$PHP_TEST_HELLO_WORLD" != "no"; then  
    PHP_SUBST(TEST_HELLO_WORLD_LIBADD)  
    PHP_NEW_EXTENSION(test_hello_world, test_hello_world.cc, $ext_shared)  
    PHP_REQUIRE_CXX  

    PHP_ADD_INCLUDE(/usr/include)  
    PHP_ADD_LIBRARY_WITH_PATH(stdc++, /usr/lib, TEST_HELLO_WORLD_LIBADD)  
    OS=`uname`;  
    if test $OS = "FreeBSD"; then  
        CPPFLAGS="$CPPFLAGS -Wno-error -Wall -g"
    else  
        CPPFLAGS="$CPPFLAGS -Wno-error -Wall -g -m32 -lstdc++"
    fi  
fi  

編譯
$ phpize

$ ./configure

$ make
如果編譯成功,可以看到如下畫面



將設定檔放入下列路徑/etc/php5/conf.d/test_hello_world.ini,php才知道需要載入此模組
extension = test_hello_world.so

將編譯完成的.so放入php的library中
/usr/lib/php5/20090626+lfs/test_hello_world.so



重起apache服務
$ service apache2 restart

重新測試test.php
<?php
echo hello_world();
?>

若需要清除編譯結果,指令如下
$ make clean
$ phpize --clean











 
疑難排解
如果遇到錯誤訊息undefined symbol: _ZNSs4_Rep20_S_empty_rep_storageE

PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib/php5/20090626+lfs/yahoo_hello_world.so' - /usr/lib/php5/20090626+lfs/yahoo_hello_world.so: undefined symbol: _ZNSs4_Rep20_S_empty_rep_storageE in Unknown on line 0

解決方法
加上-lstdc++在CPPFLAGS中

參考: http://stackoverflow.com/questions/11939934/c-apache-module-fails-on-znss4-rep20-s-empty-rep-storagee



2012年6月22日 星期五

Pylons profiling工具 -- repoze.profile

repoze.profile可以針對WSGI進行完整的profiling,本文特別針對Pylons的使用做簡單說明

1. 安裝
只要使用
$ easy_install repoze.profile
下完指令即可安裝完成
 
2. 設定
直接在pylons的middleware.py修改如下

from repoze.profile.profiler import AccumulatingProfileMiddleware

# ...

def make_app(.....):
    load_environment(global_conf, app_conf)
    app = PylonsApp()

    app = AccumulatingProfileMiddleware(
        app,
        log_filename='/tmp/profiling.log',
        cachegrind_filename='/tmp/cachegrind.out',
        discard_first_request=True,
        flush_at_shutdown=True,
        path='/__profile__'
    )

    app = RoutesMiddleware(app, config['routes.map'])
    app = SessionMiddleware(app, config)
    app = CacheMiddleware(app, config)

    #.....
 

log_filename代表profiling log檔案存放位置
cachegrind_filename代表要給KCachegrind工具觀看的profiling log檔案存放位置
discard_first_request代表要不要忽略第一次檢視的結果,因為通常第一次的數據都會比較不正常而影響了整體的結果
flush_at_shutdown代表middleware instance不存在時是否要將profiling結果刪掉
path顧名思義就是利用browser檢視profile結果的URI
 
設定完成後重起httpd server
 
3. 確認結果
確認 http://localhost/__profile__ 能否存取
理論上可以看到畫面如下
 
 
4. 使用KCachegrind檢視
 
5. 參考資料

http://pypi.python.org/pypi/repoze.profile
http://docs.repoze.org/profile/#viewing-the-profile-statistics
http://nickmurdoch.livejournal.com/392632.html