# Gzoltar 使用方法 > 建議虛擬機設定16GB的RAM,不然Gzoltar在執行較大的檔案,如Closure會因為OutOfMemory而錯誤 ## 環境設定 下載SimFix ``` git clone https://github.com/xgdsmileboy/SimFix.git ``` 下載GZoltar ``` git clone https://github.com/GZoltar/gzoltar.git ``` 最後的 "bashrc" 檔案會在後面加這些。 ``` export JAVA_HOME=/opt/JDK/jdk1.7.0_80 #export JAVA_HOME=/opt/JDK/jdk1.8.0_401 export PATH=$JAVA_HOME/bin:$PATH export ANT_HOME=/opt/ANT/apache-ant-1.9.16 export PATH=$ANT_HOME/bin:$PATH #defects4j path export PATH=$PATH:~/defects4j/framework/bin export DEFECTS4J_HOME=~/defects4j export GZOLTAR_JAR='~/SimFix/sbfl/gzoltar/gzoltar.jar' ``` gzoltar切換至要使用的版本(以v1.7.2為例),並確認切換正確。 > 目前gzoltar最新版本為1.7.3,也可以選擇不切版本直接使用,此工具不影響matrix結果。 > 但請注意如果使用v1.7.3,後續的腳本要自行更改。 ``` cd gzoltar git checkout v1.7.2 git describe --tags ``` ## 實際操作方式 ### step 1 * 輸入下列指令打包,在打包之前要先到 "bashrc" 切換成java1.8,不然會報錯。 ``` export JAVA_HOME=/opt/JDK/jdk1.8.0_401 ``` ### step 2 請檢查~/gzoltar/ 底下任一資料夾是否都存在target資料夾。 如果沒有,請在terminal上執行下面指令。 ``` cd ~/gzoltar/ mvn -e -X -DskipTests clean package | tee build.log ``` ### step 3 自動抓出所有的src位置與test名稱,用於後續GZoltar使用。 這裡還是使用自己另外抓的defects4j,不是SimFix的。 在"Home"目錄下 新增一個sh檔案"auto_arc_text.sh" ,完成後執行。 ``` touch auto_arc_text.sh ``` > 20250520更新 > 在每個錯誤版本的資料夾使用此指令就能抓出來了,再把它放到相對應的位置 > 因為math有點不一樣,所以用find的指令找出test會有問題 > `defects4j export -p tests.all` > 所以之後把find test的部分修改 將下面內容貼入auto_arc_text.sh中 :::spoiler auto_arc_text.sh ``` #!/bin/bash # ---------------------------------------- # 以下是需要手動修改的部分 # 修改這裡的 defects4j 將project的資料抓下來的位置 # 每個人抓下來的位置都不同 user_def_path=~/d4j_project/ # 這裡是src_path的位置,此為SimFix提供,表示Defects4J的原始碼與測試檔案的路徑 # 建議能從SimFix提供的檔案取得,位置在SimFix/d4j-nfo/src_path # 每個人抓下來的位置都不同 src_path=~/src_path/ # 針對的專案 # 更改處理成其他的專案要修改,例如,closure,Num是133個。 # 並且記得建立"src_and_test_folder"資料夾的部分要記得刪除。 proj2=chart Num=26 # ---------------------------------------- # 建立資料夾名為 src_and_test_folder mkdir src_and_test_folder echo "資料夾 'src_and_test_folder' 已建立。" cd src_and_test_folder # 建立存放各個project的詳細測試與src檔案。 mkdir ${proj2} echo "資料夾 '${proj2}' 已建立。" cd ${proj2} for bug_id in $(seq 1 ${Num}) do mkdir ${proj2}_${bug_id}_buggy mess=${proj2}_${bug_id}_buggy echo "資料夾 '${mess}' 已建立。" cd ${mess} > src.txt #防呆初始化,怕出事 > test.txt #防呆初始化,怕出事 # 取得src_path檔案位置 src_path_locate=${src_path}${proj2}/${bug_id}.txt #echo "檔案位置: '${src_path_locate}'" source=$(head -n 1 "$src_path_locate") #echo "source code 位置: '${source}'" test_path=$(head -n 3 "$src_path_locate" | tail -n 1) #echo "test code 位置: '${test_path}'" #這邊需要看不同的專案,他所讀取的位置 #例如Chart的位置,我是放在/ /ncyu/d4j_project/chart/chart_x_buggy中,所以後面就要加上專案的build與test資料夾 #find ${user_def_path}${proj2}/${proj2}_${bug_id}_buggy/source/org -name *.java >> src.txt find ${user_def_path}${proj2}/${proj2}_${bug_id}_buggy${source} -name *.java >> src.txt # 移動到對應的defects4J資料夾 cd ${user_def_path}${proj2}/${proj2}_${bug_id}_buggy # 處理成GZoltar看得懂的格式。 defects4j export -p tests.all >> ~/src_and_test_folder/${proj2}/${proj2}_${bug_id}_buggy/test.txt #這個格式gzoltar看不懂,所以註解 #find ${user_def_path}${proj2}/${proj2}_${bug_id}_buggy/tests/org -name *.java >> test.txt # 處理成GZoltar看得懂的格式。 # 這個格式在其他的專案有問題,所以改成defects4J提供的方法。 #find "${user_def_path}${proj2}/${proj2}_${bug_id}_buggy/tests" -type f -name "*Tests*" | sed "s|${user_def_path}${proj2}/${proj2}_${bug_id}_buggy/tests/||; s|/|.|g; s|\.java$||" > test.txt #find "${user_def_path}${proj2}/${proj2}_${bug_id}_buggy${test_path}" -type f -name "*Tests*" | sed "s|${user_def_path}${proj2}/${proj2}_${bug_id}_buggy/tests/||; s|/|.|g; s|\.java$||" > test.txt # 回到"src_and_test_folder/Chart" cd ~/src_and_test_folder/${proj2} done cd .. # ---------------------------------------- # 如果需要新增其他專案資料夾,請在此處添加 # 例如:mkdir Closure # ---------------------------------------- ``` ::: 注意在執行前要先到~/SimFix/d4j-info/ 底下將src_path資料夾完整複製至Home底下,否則會顯示not found file。 ``` chmod +x auto_arc_text.sh ./auto_arc_text.sh ``` ### step 4 寫一個腳本自動執行不同錯誤定位的結果。 此腳本放在gzoltar資料夾中"test_gzoltar.sh" 這是一次處理chart的部分。 :::spoiler chart_test_gzoltar.sh ``` SCRIPT_DIR=$(pwd) #PID=$chart #BID=$2 #PID=chart #PID2=Chart #BID=1 # ------------------ # 自己的defects4j的git clone位置在哪裡。 D4J_HOME=~/defects4j # 資料集檔案位置 # 此處需要自行修正。 D4J_DIR=~/d4j_project/ # GZoltar的主程式路徑。 # 每個人都不一樣,記得更改(路徑和版本)。 GZOLTAR_AGENT_JAR=~/gzoltar/com.gzoltar.agent.rt/target/com.gzoltar.agent.rt-1.7.2-all.jar GZOLTAR_CLI_JAR=~/gzoltar/com.gzoltar.cli/target/com.gzoltar.cli-1.7.2-jar-with-dependencies.jar # 這裡是src_path的位置,此為SimFix提供,表示Defects4J的原始碼與測試檔案的路徑 # 建議能從SimFix提供的檔案取得,位置在SimFix/d4j-nfo/src_path # 每個人抓下來的位置都不同 src_path=~/src_path/ # 要使用的SBFL公式,目前可使用為:ochiai、jaccard、dstar(這部分還不確定英文要怎麼打,之續需要再確認) # 根據他們的網站,應該是會自動轉成大寫:https://gzoltar.com/web/javadoc/1.7.2/com/gzoltar/sfl/SFLFormulas.html。 # 不過不確定,需要再釐清。 sfll=ochiai # 使用的專案以及錯誤版本 pre_PID=chart pre_PID2=Chart Num=26 # GZoltar失敗的版本紀錄。 ERROR_LOG=~/gzoltar/${pre_PID}_error_log.txt # ------------------ GZoltar() { # 取得錯誤版本以及專案參數 local BID=$1 local PID=$2 local PID2=$3 # ------------------ # 檔案位置 # 此處需要自行修正,自己的Defects4j當初拉到哪個資料夾。 PROJECT_DIR=~/d4j_project/${PID}/${PID}_${BID}_buggy # ------------------ # # 移動到要錯誤定位的檔案位置,例如Chart-1的檔案存放在哪裡。 cd ${PROJECT_DIR} # 取得src_path檔案位置 src_path_locate=${src_path}${PID}/${BID}.txt echo "檔案位置: '${src_path_locate}'" build_path=$(head -n 2 "$src_path_locate" | tail -n 1) echo "source code 位置: '${build_path}'" build_test_path=$(head -n 4 "$src_path_locate" | tail -n 1) echo "test code 位置: '${build_test_path}'" # Checkout defects4j project # 這是defects4j經過compile之後的結果檔案,自己輸入,因為低版本的好像有問題。 SRC_DIR=${PROJECT_DIR}${build_path} echo "SRC_DIR 位置: '${SRC_DIR}'" TEST_DIR=${PROJECT_DIR}${build_test_path} echo "TEST_DIR 位置: '${TEST_DIR}'" LIB_DIR=$(~/defects4j/framework/bin/defects4j export -p cp.test) # 因為defectsj是使用1.7的java,而GZoltar是使用java1.8 # 所以預設bashrc使用java1.7,要執行java1.8的時候就直接export,不要寫在bashrc中。 export JAVA_HOME=/opt/JDK8/jdk1.8.0_401 export PATH=$JAVA_HOME/bin:$PATH # FIXME: Change Test Data Here! # 這是剛剛的auto_arc_text.sh所產生的檔案位置,要自己修改。 TEST_DATA=~/src_and_test_folder/${PID}/${PID}_${BID}_buggy/test.txt # 這一個處理方式用RELEVANT_TESTS提供的修改。 TEST_DATA=$(cat ${TEST_DATA} | sed 's/$/#*/' | sed ':a;N;$!ba;s/\n/:/g') # List test methods # output為輸出結果。 # includes為要輸入的檔案是什麼。 java -cp ${LIB_DIR}:${GZOLTAR_CLI_JAR} \ com.gzoltar.cli.Main listTestMethods \ ${TEST_DIR} \ --outputFile ${PROJECT_DIR}/listTestMethods.txt \ --includes ${TEST_DATA} # 這邊是相關資料丟到Defects4J的資料夾中,所以預計先等Defects4J抓好後先備份到Nas上。 # 可能不同GZoltar的結果都放一份。 SER_FILE=${PROJECT_DIR}/gzoltar.ser LOADED_CLASSES_FILE=${D4J_HOME}/framework/projects/${PID2}/loaded_classes/${BID}.src NORMAL_CLASSES=$(cat ${LOADED_CLASSES_FILE} | sed 's/$/:/' | sed ':a;N;$!ba;s/\n//g') INNER_CLASSES=$(cat ${LOADED_CLASSES_FILE} | sed 's/$/$*:/' | sed ':a;N;$!ba;s/\n//g') LOADED_CLASSES=${NORMAL_CLASSES}${INNER_CLASSES} # Generate .ser file # 產生覆蓋資訊的步驟 java -javaagent:${GZOLTAR_AGENT_JAR}=destfile=${SER_FILE},buildlocation=${SRC_DIR},includes=${LOADED_CLASSES},excludes="",inclnolocationclasses=false,output="file" \ -cp ${GZOLTAR_CLI_JAR}:${LIB_DIR} \ com.gzoltar.cli.Main runTestMethods \ --testMethods ${PROJECT_DIR}/listTestMethods.txt \ --collectCoverage # Generate report # family -> 輸出資料的資料夾名稱 # formula -> 使用的SBFL公式,官網有提供能用哪些SBFL公式,例如可以改成"jaccard"。 # family -> 只能使用"sfl"這個名稱,不然會報錯。 java -cp ${GZOLTAR_CLI_JAR}:${LIB_DIR} \ com.gzoltar.cli.Main faultLocalizationReport \ --buildLocation ${SRC_DIR} \ --granularity line \ --inclPublicMethods \ --inclStaticConstructors \ --inclDeprecatedMethods \ --dataFile ${SER_FILE} \ --outputDirectory ${PROJECT_DIR} \ --family sfl \ --formula ${sfll} \ --metric entropy \ --formatter txt } for bug_id in $(seq 1 ${Num}) do export JAVA_HOME=/opt/JDK/jdk1.7.0_80 export PATH=$JAVA_HOME/bin:$PATH GZoltar ${bug_id} ${pre_PID} ${pre_PID2} echo "GZoltar針對專案:'${pre_PID}'_'${bug_id}',使用的公式為:'${sfll}',已完成" # 檢查 RANK_DIR 這個 sfl 資料夾是否存在。 # 記錄用,不確定有沒有用,等等要再確認。 RANK_DIR=${D4J_DIR}${pre_PID}/${pre_PID}_${bug_id}_buggy/sfl if [ -d "$RANK_DIR" ]; then echo "排名結果資料夾存在: $RANK_DIR" >> "$ERROR_LOG" # 將錯誤訊息寫入日誌檔案 else # echo "排名結果資料夾不存在: $RANK_DIR" >> "$ERROR_LOG" # 將錯誤訊息寫入日誌檔案 echo "排名結果錯誤版本不存在: $pre_PID_${bug_id} 不存在" >> "$ERROR_LOG" fi done ``` ::: 這是一次處理math與lang的部分。 > 這是因為虛擬機RAM設定太小而導致Closure的錯誤後的處理。 > 有使用到shell的list用在for中的操作。 :::spoiler math_lang_test_gzoltar.sh ``` SCRIPT_DIR=$(pwd) # ------------------ # 自己的defects4j的git clone位置在哪裡。 D4J_HOME=~/defects4j # GZoltar的主程式路徑。 # 每個人都不一樣,記得更改。 GZOLTAR_AGENT_JAR=~/gzoltar/com.gzoltar.agent.rt/target/com.gzoltar.agent.rt-1.7.2-all.jar GZOLTAR_CLI_JAR=~/gzoltar/com.gzoltar.cli/target/com.gzoltar.cli-1.7.2-jar-with-dependencies.jar # 這裡是src_path的位置,此為SimFix提供,表示Defects4J的原始碼與測試檔案的路徑 # 建議能從SimFix提供的檔案取得,位置在SimFix/d4j-nfo/src_path # 每個人抓下來的位置都不同 src_path=~/src_path/ # 要使用的SBFL公式,目前可使用為:ochiai、jaccard、dstar(這部分還不確定英文要怎麼打,之續需要再確認) # 根據他們的網站,應該是會自動轉成大寫:https://gzoltar.com/web/javadoc/1.7.2/com/gzoltar/sfl/SFLFormulas.html。 # 不過不確定,需要再釐清。 sfll=jaccard # 使用的專案以及錯誤版本 pre_PID=closure pre_PID2=Closure # 這邊手動輸入版本,針對Closure的修正 # 將需要的特定數字放入一個陣列 bug_ids=(3 13 16 26 29 36 59 60 107 108 110 112 114 115 116 117 118 119 120 121 125 129) # ------------------ GZoltar() { # 取得錯誤版本以及專案參數 local BID=$1 local PID=$2 local PID2=$3 # ------------------ # 檔案位置 # 此處需要自行修正,自己的Defects4j當初拉到哪個資料夾。 PROJECT_DIR=~/d4j_project/${PID}/${PID}_${BID}_buggy # 設置 JAVA_OPTS #export JAVA_OPTS="-Xms4096m -Xmx4096m -XX:-UseGCOverheadLimit" export JAVA_OPTS="-Xms4096m -Xmx4096m" # ------------------ # # 移動到要錯誤定位的檔案位置,例如Chart-1的檔案存放在哪裡。 cd ${PROJECT_DIR} # 取得src_path檔案位置 src_path_locate=${src_path}${PID}/${BID}.txt echo "檔案位置: '${src_path_locate}'" build_path=$(head -n 2 "$src_path_locate" | tail -n 1) echo "source code 位置: '${build_path}'" build_test_path=$(head -n 4 "$src_path_locate" | tail -n 1) echo "test code 位置: '${build_test_path}'" # Checkout defects4j project # 這是defects4j經過compile之後的結果檔案,自己輸入,因為低版本的好像有問題。 SRC_DIR=${PROJECT_DIR}${build_path} echo "SRC_DIR 位置: '${SRC_DIR}'" TEST_DIR=${PROJECT_DIR}${build_test_path} echo "TEST_DIR 位置: '${TEST_DIR}'" LIB_DIR=$(~/defects4j/framework/bin/defects4j export -p cp.test) # 因為defectsj是使用1.7的java,而GZoltar是使用java1.8 # 所以預設bashrc使用java1.7,要執行java1.8的時候就直接export,不要寫在bashrc中。 export JAVA_HOME=/opt/JDK8/jdk1.8.0_401 export PATH=$JAVA_HOME/bin:$PATH SER_FILE=${PROJECT_DIR}/gzoltar.ser # Generate report # family -> 輸出資料的資料夾名稱 # formula -> 使用的SBFL公式,官網有提供能用哪些SBFL公式,例如可以改成"jaccard"。 # family -> 只能使用"sfl"這個名稱,不然會報錯。 java -cp ${GZOLTAR_CLI_JAR}:${LIB_DIR} \ com.gzoltar.cli.Main faultLocalizationReport \ --buildLocation ${SRC_DIR} \ --granularity line \ --inclPublicMethods \ --inclStaticConstructors \ --inclDeprecatedMethods \ --dataFile ${SER_FILE} \ --outputDirectory ${PROJECT_DIR} \ --family sfl \ --formula ${sfll} \ --metric entropy \ --formatter txt } # 使用for迴圈遍歷特定數字 for bug_id in "${bug_ids[@]}" do export JAVA_HOME=/opt/JDK/jdk1.7.0_80 export PATH=$JAVA_HOME/bin:$PATH export JAVA_OPTS="-Xms4096m -Xmx4096m" GZoltar ${bug_id} ${pre_PID} ${pre_PID2} echo "GZoltar針對專案:'${pre_PID}'_'${bug_id}',使用的公式為:'${sfll}',已完成" done ``` ::: ### 額外補充 補充: GZoltar的公式檔案位置存放在 "gzoltar/com.gzoltar.fl/src/main/java/com/gzoltar/sfl/formulas" 再補充: 如果gzoltar錯誤時需要還原defects4J,可以使用以下腳本。 這是要將d4j的gzoltar的部分刪除。 ``` touch init_d4j.sh ``` :::spoiler init_d4j.sh ``` #!/bin/bash # 此檔案為還原GZoltar所產生的檔案。 # ------------------ # 檔案位置 # 此處需要自行修正。 D4J_DIR=~/d4j_project/ pre_PID=chart pre_PID2=Chart Num=26 # ------------------ for bug_id in $(seq 1 ${Num}) do # cd ${D4J_DIR}${pre_PID}/${pre_PID}_${bug_id}_buggy rm -rf ${D4J_DIR}${pre_PID}/${pre_PID}_${bug_id}_buggy/sfl rm -f ${D4J_DIR}${pre_PID}/${pre_PID}_${bug_id}_buggy/gzoltar.ser rm -f ${D4J_DIR}${pre_PID}/${pre_PID}_${bug_id}_buggy/listTestMethods.txt done ``` ::: ``` chmod +x ./init_d4j.sh ```