++++ 伺服器列表|

  • itanium.iis.sinica.edu.tw
  • sparc.iis.sinica.edu.tw
  • tesla.iis.sinica.edu.tw
  • opteron.iis.sinica.edu.tw
  • xeon.iis.sinica.edu.tw
  • i7.iis.sinica.edu.tw
  • i722.iis.sinica.edu.tw
  • i71.iis.sinica.edu.tw
  • ps3.iis.sinica.edu.tw
  • opteron48.iis.sinica.edu.tw

++++

  • xeon, tesla - Intel(R) Xeon(R) CPU E5410 - Core microarchitecture

http://en.wikipedia.org/wiki/Xeon#Quad-Core_and_Multi-Core_Xeon

  • i71 - Intel(R) Xeon(R) CPU X5550 - Nehalem microarchitecture

http://en.wikipedia.org/wiki/Xeon#Nehalem-based_Xeon

  • i7, i722 - Intel(R) Core(TM) i7 CPU 975 - Nehalem microarchitecture

http://en.wikipedia.org/wiki/List_of_Intel_Core_i7_microprocessors#.22Bloomfield.22_.2845_nm.29

1. benchmark 放在 itanium 下的 /data/Benchmarks。svn repo 放在 itanium 下的 /data/svn
目前使用工作站為: i7, i71, i722, ps3。

Quick Start

Build QEMU

請見 QEMU

Build LLVM

SPEC

閱讀 SPEC CPU2006 DocumentationSPEC CPU2006 Config FilesThe 'runspec' Command

選項 –nobuild 可以避免重新編譯。
  1. 在 /data/Benchmarks/SPEC/CPU2006_v1.1_x86/config 底下生成一個設定檔。
    $ cp Example-linux64-amd64-gcc43.cfg chenwj-i71-example.cfg
  2. 新增
    qemu = /path/to/qemu-i38
    curdir = /tmp/chenwj/spec
    # 測量結果放置處
    output_root  = ${curdir}/spec_results
    # summit 可以加上額外的指令及參數,預設為 $command
    submit = $qemu $command
  3. 建立軟連結,方便修改設定檔
    $ cd /tmp/chenwj/spec
    $ ln -s /data/Benchmarks/SPEC/CPU2006_v1.1_x86/config/chenwj-i71-example.cfg .
    $ cd /data/Benchmarks/SPEC/CPU2006_v1.1_x86
    # 這樣才抓得到 runspec
    $ . shrc
    $ cd /tmp/chenwj/spec
    $ runspec --config=chenwj-i71-example.cfg --iterations=1 --size=test mcf
  4. 中止測量Ctrl+Z
    $ pstree -p | grep runspec -A2 -B2
    $ killall

若要同時執行多個 benchmark,請手動並將其至於背景執行。

Binary Translator

LnQ

LLVM 2.8 svn。LLVM-GCC 2.6。

請見 LnQ

建置 LLVM

目前使用 LLVM 2.8 svn 版本,較 LLVM 2.8 Release 舊。停用斷言只是臨時作法。
$ svn co svn+ssh://user@itanium.iis.sinica.edu.tw/data/svn/llvm-qemu/llvm/src/llvm
$ mkdir build; cd build
$ ../llvm/configure --prefix=$INSTALL --enable-optimized --enable-assertions=no
$ make install

建置 LLVM-GCC

$ wget http://llvm.org/releases/2.6/llvm-gcc-4.2-2.6-x86_64-linux.tar.gz
$ tar xvf llvm-gcc-4.2-2.6-x86_64-linux.tar.gz

建置 LnQ

加上 –enable-debug 可以進行除錯。
lnq-llvm-2.8 必須對 LLVM 2.8 Release 上補丁。
  1. 設定 PATH
    $ export PATH=$PATH:/path/to/llvm:/path/to/llvm-gcc/ 
  2. 下載 LnQ
    # data/svn/llvm-qemu/qemu/src/branches/lnq-llvm-2.8/
    $ svn co svn+ssh://user@itanium.iis.sinica.edu.tw/data/svn/llvm-qemu/qemu/src/branches/lnq
    $ mkdir build; cd build
    # --extra-cflags='-DLNQ_EDGE_PROFILE' 開啟 edge profile,此資訊可用來建立 CFG
    # qemu-i386 -d edge_count -logfile filename
    $ ../lnq/configure --prefix=/path/to/install --target-list=i386-linux-user --enable-llvm-translator
    $ make install 
  3. 設定 LLVM IR 函式庫的路徑
    $ cp i386-linux-user/lnq-ir-lib.bc /path/to/lnq-ir-lib.bc
    $ export LNQ_IR_LIB=/path/to/lnq-ir-lib.bc
    1. qemu/src/trunk/target-i386/llvm-translator.h qemu/src/trunk/target-i386/llvm-translator.cpp
    2. lnq-ir-lib.bc 為 LLVM bitcode,可用 llvm-dis 讀取內容

開發手冊

QEMU Hybrid

請下載 LLVM 的 Release 版本。$llvm_prefix 為自訂安裝路徑。

請見 Hybrid QEMU

  1. 簽出 Hybrid QEMU。
    # file:///data/svn/llvm-qemu/hybrid-qemu/branches/
    $ svn co svn+ssh://user@itanium.iis.sinica.edu.tw/data/svn/llvm-qemu/hybrid-qemu/branches/user-mode
    $ svn co svn+ssh://user@itanium.iis.sinica.edu.tw/data/svn/llvm-qemu/hybrid-qemu/branches/system-mode
  2. 建置 LLVM。
    $ wget http://llvm.org/releases/2.8/llvm-2.8.tgz; tar vxf llvm-2.8.tgz
    $ cd llvm-2.8; patch -p1 < ../system-mode/patch/llvm-2.8.patch; cd ..
    $ mkdir build; cd build
    $ ../llvm-2.8/configure --prefix=${INSTALL} --enable-optimized
    $ make install
  3. 建置 LLVM-GCC。
    $ wget http://llvm.org/releases/2.8/llvm-gcc4.2-2.8-x86_64-linux.tar.bz2
    $ tar xvf llvm-gcc4.2-2.8-x86_64-linux.tar.bz2
  4. 設定 PATH。
    $ export PATH=$PATH:/path/to/llvm:/path/to/llvm-gcc
  5. 建置 QEMU-Hybrid。
    $ cd build
    $ ../system-mode/configure --prefix=$INSTALL --enable-debug --enable-llvm=hybrids --target-list=i386-linux-user
    $ make install

Annotaion Framwork & Binary Optimizer

建置系統

系統依賴的函式庫 Boost 和 libelf 在 I7、i71 和 i722 上皆已安裝。
有多個 libelf 版本實作同一套 API。目前使用的是 GNU libelf
perfmon 已不再維護。建議改用 perf。

建置 Annotaion Framwork & Binary Optimizer & LnQ-DBO

LnQ 必須加以修改以便和 DBO 協作。LnQ-DBO 位在 /data/svn/llvm-qemu/qemu/src/branches/lnq-dbo。DBO 位在 /data/svn/chenwj/dbo/trunk。
$ svn co svn+ssh://user@itanium.iis.sinica.edu.tw/data/svn/chenwj/chenwj-top/trunk chenwj-top
$ cd chenwj-top;
$ . ./bootstrap.sh all

手動建置 lnq-dbo。

$ svn co file:///data/svn/llvm-qemu/qemu/src/branches/lnq-dbo
$ mkdir build; cd build
$ ../lnq-dbo/configure --prefix=$INSTALL --target-list=i386-linux-user --enable-llvm-translator --enable-dbo
$ make install

開發手冊

修改 QEMU

補丁

Introduction: Using diff and patch (tutorial)

$ diff -ruN qemu-0.11.0/linux-user/syscall.c qemu-dbo/linux-user/syscall.c > patch-linux-user-syscall.c 
$ wget http://download.savannah.gnu.org/releases/qemu/qemu-0.11.0.tar.gz; tar xvf qemu-0.11.0.tar.gz 
$ cd qemu-0.11.0
$ cp example/patch/ice_shared_lib_tk.h
$ patch < example/patch/patch-exec-c
$ patch < example/patch/patch-translate-all-c
$ patch -p1 < example/patch/patch-linux-user-main.c
$ patch -p1 < example/patch/patch-linux-user-syscall-c
修改內容
  1. 新增 ice_shared_lib_tk.h
  2. exe.c
    #include "ice_shared_lib_tk.h"
    TranslationBlock *tb_gen_code(CPUState *env,
                                  target_ulong pc, target_ulong cs_base,
                                  int flags, int cflags)
    {
        phys_pc = get_phys_addr_code(env, pc);
        tb = tb_alloc(pc);
     
        // QEMU 的 code cache 已滿,flush code cache。
        // TK_del_trace 清空 guest addr <-> host addr 的 AVLTree。
        if (!tb) {
            /* flush must be done */
            tb_flush(env);
            /* cannot fail at this point */
            tb = tb_alloc(pc);
            /* Don't forget to invalidate previous TB info.  */
            tb_invalidated_flag = 1;
     
            /* For ICE Binary Optimizer */
            TK_del_trace((void*)0, (void*)0, (void*)0, (void*)0);
        }
    }
  3. translate-all.c
    #include "ice_shared_lib_tk.h"
    int cpu_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr)
    {
    // 將 guest addr <-> host addr 填入 AVLTree
    TK_add_trace((void*)tb->pc,
                 (void*)(tb->pc+tb->size),
                 (void*)tb->tc_ptr,
                 (void*)((unsigned long)(tb->tc_ptr)+gen_code_size));
     
    #ifdef DEBUG_DISAS
        if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
            qemu_log("OUT: [size=%d]\n", *gen_code_size_ptr);
            log_disas(tb->tc_ptr, *gen_code_size_ptr);
            qemu_log("\n");
            qemu_log_flush();
        }
    #endif
        return 0;
    }
  4. linux-user/main.c
    #include "ice_shared_lib_tk.h"
    guest_thread_start_fp TK_guest_thread_start;
    /* call TK_guest_thread_start(...) in the beginning of a created thread. */
    guest_thread_end_fp   TK_guest_thread_end;
    /* call guest_thread_start(...) in the end of a created thread. */
    add_trace_fp      TK_add_trace;
    /* call TK_add_trace(...) when bulding a new trace. */
    del_trace_fp      TK_del_trace;
    /* call TK_del_trace(...) when deleting a trace. */
    setup_optimizer_fp    TK_setup_optimizer;
    /* The two following functions are not used as far. They do not need their functionalities now. */
    int TK_regen_trace(int opt_f, int n_gcode, void* og_s_addr, void* og_e_addr, int* n_trace, void** g_s_addr, void** g_e_addr, void** h_s_addr, void** h_e_addr){return -1;}
    /* simulator must provide regen_trace(...) to generate the trace for the indicated guest code fragments. */
    void* TK_get_guest_CFG(){return NULL;}
    /* simulator must provide get_guest_CFG(...) to return the information about guest CFG */
    qemu_end_fp     TK_qemu_end;
     
    void cpu_loop(CPUX86State *env)
    {
        // 啟動 dbo 做為另一隻執行緒
        TK_guest_thread_start(GET_THREAD_ID);
     
        for(;;) {
        }
    }
     
    int main(int argc, char **argv, char **envp)
    {
        if (argc <= 1)
            usage();
     
        // 取得 __libc_start_main 註冊的 DBO 函式。init_optimizer 請見 DBO 中的 shared_lib.h。
        init_optimizer(argc, argv, &TK_guest_thread_start, &TK_add_trace, &TK_del_trace, &TK_setup_optimizer, &TK_guest_thread_end, &TK_qemu_end);
        TK_setup_optimizer(TK_regen_trace, TK_get_guest_CFG);
     
        qemu_cache_utils_init(envp);
    }
  5. linux-user/syscall.c
    #include "ice_shared_lib_tk.h"
    abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                        abi_long arg2, abi_long arg3, abi_long arg4,
                        abi_long arg5, abi_long arg6)
    {
        switch(num) {
          case TARGET_NR_exit:
            TK_guest_thread_end(GET_THREAD_ID);
          case TARGET_NR_exit_group:
            TK_guest_thread_end(GET_THREAD_ID);
        }    
    }

DBO 執行流程

  1. ice_shared_lib_s.cpp
    // 避免 C++ Name mangling 機制破壞函式名 __libc_start_main 
    #ifdef __cplusplus
    extern "C" {
    void
    __libc_start_main( PARAMS_START_MAIN )
    {
        // 複製原本的命令行參數
        for( i = 1; i <  argc; i++ )
            argv[i] = ubp_av[i];
     
        // 註冊 DBO 相關的函式
        argv[i + _OPTIMIZER_ACTIVE_F] = ubp_av[0];
        argv[i + _GUEST_THREAD_START_P] = ( char* )guest_thread_start;
        argv[i + _ADD_TRACE_P] = ( char* )add_trace;
        argv[i + _DEL_TRACE_P] = ( char* )del_trace;
        argv[i + _GUEST_THREAD_END_P] = ( char* )guest_thread_end;
     
        // 取得真正的入口函式
        real_libc_start_main = ( void( * )( PARAMS_START_MAIN ) )dlsym( RTLD_NEXT, "__libc_start_main" );
    }
    }
    #endif /* __cplusplus */
  2. perfmon event buffer overflow 時的處理流程: guest_thread_start → thread_monitor → monitor_thread_start( ev_p, ut_id, buff_ov_handle ) → buff_ov_handle → process_buffer

由 LnQ 傳遞函式指針給 DBO

前述皆是由 DBO 傳遞函式指針給 LnQ。如果要由 LnQ 傳遞函式指針給 DBO,則有底下檔案需要修改。假設 LnQ 要傳遞 gen_trace 給 DBO。目前做法是利用 LnQ_pass_gen_trace。

LnQ_pass_gen_trace( void (*gen_trace_fp)(void* trace, void* back_jump) ) 

DBO

  1. shared_lib.h
    // 在 argv 的索引
    #define _PASS_GEN_TRACE_P 7
    // 定義 gen_trace 函式指針型別
    typedef void (*gen_trace_fp)(void* trace, void* back_jump);
    // 定義 LnQ 用來傳遞 gen_trace_fp 的函式指針型別
    typedef void ( *lnq_pass_gen_trace_fp )(gen_trace_fp gt_fp);
  2. ice_shared_lib_s.h
    void lnq_pass_gen_trace(gen_trace_fp gt_fp);
  3. ice_shared_lib_s.cpp
    // 存放 gen_trace 函式指針的全域變數
    gen_trace_fp gen_trace_p;
    __libc_start_main( PARAMS_START_MAIN )
    {
      // malloc 大小隨傳遞的函式指針個數改變!
      argv = ( char** )malloc(( argc + 8 ) * sizeof( void* ) );
      // 傳遞函式指針給 LnQ,LnQ 再透過此函式傳遞 gen_trace 的函式指針 
      argv[i + _PASS_GEN_TRACE_P] = ( char* )lnq_pass_gen_trace;
      real_libc_start_main = ( void( * )( PARAMS_START_MAIN ) )dlsym( RTLD_NEXT, "__libc_start_main" );
    }
    // 此函式要傳給 LnQ,LnQ 再透過此函式傳遞 gen_trace 的函式指針
    // 將該函式指針存放至先前的全域變數
    void lnq_pass_gen_trace(gen_trace_fp gt_fp)
    {
      gen_trace_p = gt_fp;
    }

LnQ

  1. ice_shared_lib_tk.h
    // 在 argv 的索引
    #define _PASS_GEN_TRACE_P   7
    // 定義總共要傳遞的函式指針個數
    #define optimize_fun_num    PASS_GEN_TRACE_P
    // 定義用來傳遞 gen_trace_fp 的函式指針型別
    typedef void (*lnq_pass_gen_trace_fp)(void (*gen_trace_fp)(void* trace, void* back_jump));
    // 預設的函式指針
    static void void_f6(void (*gen_trace_fp)(void* trace, void* back_jump))
    {
    #ifdef _MSG_FOR_ARGMENT_PASSING
            //fprintf(stderr, " .f5. ");
    #endif
            //return 0;
    }
    // LnQ 會呼叫此函式傳遞所需的函式指針
    static inline int
    init_optimizer( int argc, char** argv,
                    lnq_pass_gen_trace_fp* lnq_pass_gen_trace_p)
    {
      if( 0 != strcmp( _ACTIVE_STRING, argv[0] ) )
      {
        // 如果有問題,傳入預設的函式指針
        *lnq_pass_gen_trace_p = void_f6;
      }
      else
      {
        // 索引隨函式指針個數而有所變動!
        for( i = 1; i < 8; i++ ) if( NULL == argv[argc + i] )
        {
          // 如果有問題,傳入預設的函式指針
          *lnq_pass_gen_trace_p = void_f6;
          return -2;
        }
        // 取得 DBO 傳遞的函式指針
        *lnq_pass_gen_trace_p = ( lnq_pass_gen_trace_fp )argv[argc + _PASS_GEN_TRACE_P];
      }
    }
     
    // 供 linux-user/main.c 呼叫 LnQ_pass_gen_trace 以便傳遞 gen_trace 的函式指針
    extern lnq_pass_gen_trace_fp    LnQ_pass_gen_trace;
  2. linux-user/main.c
    #ifdef CONFIG_USE_DBO
    #include "ice_shared_lib_tk.h"
    lnq_pass_gen_trace_fp LNQ_pass_gen_trace;
    #endif
     
    int main(int argc, char **argv, char **envp)
    {
    #ifdef CONFIG_USE_DBO
        // LnQ 透過 init_optimizer 得到負責傳遞 gen_trace 的函式指針 LnQ_pass_gen_trace
        init_optimizer(argc, argv, &TK_guest_thread_start, &TK_add_trace, &TK_del_trace, &TK_guest_thread_end, &LnQ_pass_gen_trace);
        // LnQ 可以如此傳遞 gen_trace 函式指針給 DBO
        // LnQ_pass_gen_trace(&gen_trace);
    #endif
    }

除錯

只有 run 才能傳入命令行參數。
lnq-dbo 依序開啟 llvm translator 和 dbo 以便判別哪裡出錯。編譯 lnq-dbo 和 dbo 要加上 –enable-debug。
$ gdb qemu-i386
(gdb) r bzip2_base.i386-m32-gcc44 input.source 1
$ gdb
(gdb) set environment LD_PRELOAD=/path/to/libdbo.so
(gdb) file /path/to/qemu-i386
(gdb) run -U LD_PRELOAD bzip2_base.i386-m32-gcc44-annotated input.source 1
上述方法不適用於 libdbo.so,但可以 LD_PRELOAD 其它的 .so。可能的解法請見 How to run gdb with LD_PRELOAD?

gdb 事實上會叫起 bash -c 執行 qemu-i386。所以 LD_PRELOAD 會影響 bash 和 qemu-i386。可以透過以下方法觀察到。

void __libc_start_main( PARAMS_START_MAIN )
{
  // 印出命令行參數,包括執行檔名稱
  for( i = 0; i <  argc; i++ )
    std::cerr << ubp_av[i] << " ";
  std::cerr << "\n";
  argv = ( char** )malloc(( argc + 8 ) * sizeof( void* ) );
  //dbo.OpenELF(argv[3]);
  //dbo.GetCFGData("TEST");
  //dbo.BuildCFG();
}

dbo 會在 entry point 開啟 argv[3] 的執行檔,這裡的命令行參數對 bash 和 qemu-i386 而言不一樣。這裡改用一隻 script 設定 LD_PRELOAD 和執行 qemu-i386,如此 LD_PRELOAD 就只會影響 qemu-i386。但是 gdb 只能執行 elf,故目前寫成 perl script 再用 perlcc 將其編譯成 elf。

上述方法無效!

請見 set exec-wrapper

set exec-wrapper env 'LD_PRELOAD=/path/to/libdbo.so'
file /path/to/qemu-i386
# 設定中斷點
break guest_thread_start
run -U LD_PRELOAD bzip2_base.i386-m32-gcc44-annotated input.source 1

計劃網站

外部連結

註腳

登录