Chƣơng 4 Thực nghiệm
4.1. Xây dựng công cụ TVG
Sau khi đặc tả ràng buộc thời gian bằng biểu thức chính quy thời gian đây là đầu vào cho công cụ TVG. Áp dụng các phƣơng pháp đƣợc giới thiệu từ Chƣơng 3 tác giả đã cài đặt thành công Công cụ tự động sinh mã Aspect từ biểu thức chính quy thời gian. Tác giả sử dụng công cụ Netbeans 7.0.1 cùng với JDK để cài đặt công cụ. Chi tiết về công cụ đƣợc trình bày trong phụ lục A. Hình 4.1 mô tả giao diện công cụ Netbeans 7.0.1.
Hình 4.1 – Cài đặt công cụ TVG bằng Netbean 7.0.1 Cài đặt công cụ TVG đƣợc tác giả thực hiện qua các bƣớc chính sau đây: Cài đặt công cụ TVG đƣợc tác giả thực hiện qua các bƣớc chính sau đây:
Bƣớc 1: Phân tích biểu thức chính quy thời gian đầu vào. Từ đó xây dựng máy trạng thái.
Bƣớc 2: Xây dựng các mẫu AspectJ tuân theo cú pháp Aspect cơ bản, bao gồm tên Aspect, vùng pointcut và vùng advise.
Bƣớc 3: Duyệt qua máy trạng thái lấy dữ liệu từng trạng thái sử dụng các phƣơng thức thao tác với xâu ký tự để sinh mã Aspect.
Hoàn thành quá trình cài đặt tác giả đã xây dựng đƣợc công cụ tự động sinh mã aspect để kiểm chứng ràng buộc thời gian trong chƣơng trình tƣơng tranh. Hình 4.2 mô tả một đoạn mã aspect sinh ra từ công cụ TVG.
pointcut pc_secondSequence_int(int i): args(i) && execution (String secondSequence(int));
before(int i): pc_secondSequence_int(i) { start = System.nanoTime();
if (startSys == 0){ startSys = start; }
}
after(int i): pc_secondSequence_int(i) { long end = System.nanoTime();
long exec = end - start; long execMinSpec = 2000; long execMaxSpec = 30000;
log("Time execute: " + thisJoinPoint + ": " + exec + " nanosec [" + start + "," + end + "]");
if ((exec > execMaxSpec)||(exec < execMinSpec)) { log(thisJoinPoint); } if(endSys == 0){ endSys = end; }else{ if(endSys < end){ endSys = end; } } CheckTotalTime(); }
Hình 4.2 – Một đoạn mã aspect sinh ra từ công cụ TVG.
4.1.1. Đọc và phân tích biểu thức chính quy thời gian
Thuật toán đọc và phân tích biểu thức chính quy thời gian đã đƣợc tác giả trình bày tổng quát trong Hình 3.4. Sau đây tác giả xin đƣợc trình bày chi tiết quá trình cài đặt thuật toán trong công cụ TVG.
Đầu tiên tác giả kiểm tra cấu trúc biểu thức chính quy thời gian đầu vào có hợp lệ hay không. Tác giả sử dụng một mẫu (pattern) để kiểm tra từng thành phần trong biểu thức chính quy thời gian có hợp lệ hay không. Chuỗi pattern đƣợc trình bày trong Hình 4.3. Tiếp theo, tác giả xây dựng một lớp TimingMethod đƣợc trình bày trong Hình 4.4. Mục đích của lớp TimingMethod để biểu diễn cho một thành phần trong biểu thức chính quy thời gian TRE. Các thành phần của lớp bao gồm: Tên phƣơng thức (name), thời gian thực thi tối thiểu cho phép (timeMin), thời gian thực thi tốt đa cho phép (timeMax).
String functionPattern = "^[a-zA-Z]+[ ]([a-zA-Z]|[0- 9]|[_]|[.]|[-])+"
+ "\\((\\w||\\W)*\\)" + "\\[\\d+[,]\\d+\\]$";
Hình 4.3 – Pattern kiểm tra từng thành phần trong TRE package generator; package generator;
public class TimingMethod {
private String name; //Ten phuong thuc
private long timeMin; // thoi gian thuc thi nho nhat private long timeMax; // thoi gian thuc thi lon nhat
public TimingMethod(String name, long timeMin, long timeMax) { this.name = name;
this.timeMin = timeMin; this.timeMax = timeMax; }
public String getName() {return name;}
public void setName(String name) {this.name = name;} public long getTimeMax() {return timeMax;}
public void setTimeMax(long timeMax) {this.timeMax = timeMax;} public long getTimeMin() {return timeMin;}
public void setTimeMin(long timeMin) {this.timeMin = timeMin;} }
Hình 4.4 – Lớp TimingMethod
Sau khi đã kiểm tra đƣợc tính hợp lệ của biểu thức TRE đầu vào, tác giả tiến hành phân tích biểu thức TRE để lấy đƣợc các thông tin về ràng buộc thời gian cần thiết để có thể sinh mã aspect. Mã nguồn của quá trình trên đƣợc trình bày trong Hình 4.5. Tác giả sử dụng một HashMap để tiến hành lƣu các thông tin đọc đƣợc từ biểu thức TRE đầu vào. Trong quá trình phân tích tác giả sử dụng một Stack để tiến hành bóc tách các thành phần trong biểu thức TRE.
public HashMap<String, String> splitProtocol(String protocol) { HashMap<String, String> pHm = new HashMap<String, String>(); protocol = protocol.trim().replaceAll(" +", " ");
String[] protocolArray = protocol.split(" "); for (int i = 0; i < protocolArray.length; i++) { if (protocolArray[i].equals("->")) { sigma += 1; } } if (sigma >= 2) { sigma = sigma - 2; }
Stack<String> stack = new Stack<String>(); int counter = 1;
String rs = "";
if (protocolArray.length > 0) {
for (int i = 0; i < protocolArray.length; i++) { if (protocolArray[i].equals("[START]")) { continue;
} else if (protocolArray[i].equals("->")) { if (!stack.empty()) {
int checkS = stack.search("("); if (checkS >= 1) { stack.push(protocolArray[i].trim()); } else { String x = stack.pop(); pHm.put("single" + counter, x); counter += 1; } } } else if (protocolArray[i].equals(")")) { String x = stack.pop(); String block = ""; while (!x.equals("(")) { block += x; x = stack.pop(); }
pHm.put("block" + counter, block);
rs = ExcecBlockMethodSingle(block, "block" + counter); counter += 1;
if (x.equals("(")) {
if (stack.search("(") >= 1) {
stack.push(rs); } } } else { stack.push(protocolArray[i].trim()); } } } else { check = false; } return pHm; }
Hình 4.5 – Quá trình đọc và phân tích biểu thức TRE.
4.1.2. Sinh mã aspect
Sau khi đã có đƣợc các thông tin về ràng buộc thời gian từ việc đọc biểu thức chính quy thời gian (TRE) đầu vào. Tác giả tiến hành sinh mã aspect kiểm chứng dựa trên những thông tin này. Tác giả sử dụng ba mẫu (template) đƣợc trình bày trong Hình 3.5, Hình 4.6, Hình 4.7 để tạo ra mã aspect kiểm chứng.
Mẫu aspectHead đƣợc trình bày trong Hình 4.6 tạo ra phần đầu của mã aspect kiểm chứng: Thƣ viện aspectJ sử dụng, Tên của aspect kiểm chứng, và khai báo các tham số cần thiết.
Mẫu strPointcut đƣợc trình bày trong Hình 3.5 tạo ra mã aspect tƣơng ứng với từng thành phần trong biểu thức TRE.
Mẫu aspectHead đƣợc trình bày trong Hình 4.7 tạo ra mã aspect tƣơng ứng với các hàm tiện ích trong aspect kiểm chứng bao gồm: Hàm ghi nhật ký (log), Hàm kiểm tra tổng thời gian thực thi các thành phần trong biểu thức TRE có hợp lệ hay không.
Tiếp theo, tác giả tiến hành thay thế các tham số trong các mẫu (các tham số này đƣợc quy ƣớc đặt trong dấu $...$) bằng các dữ liệu đã đọc và phân tích từ biểu thức chính quy thời gian đầu vào TRE. Quá trình trên đƣợc trình bày chi tiết trong Hình 4.8.
public String generateAspectJ(HashMap<String, String> input) { String result = "";
for (Entry<String, String> e : mTC.entrySet()) { String sAspect = strPointcut;
String fullMethod = ""; String method = ""; long timeMinSpec = 0; long timeMaxSpec = 0; fullMethod = e.getValue(); TimingMethod tm = GetTimingMethod(fullMethod); timeMinSpec = tm.getTimeMin(); timeMaxSpec = tm.getTimeMax(); method = tm.getName();
String method_arg_type = Utils.getMethodArgType(method); sAspect = Utils.replaceStr(sAspect, "$METHOD_ARG_TYPE$", method_arg_type);
String arg = Utils.getMethodArgName(method);
sAspect = Utils.replaceStr(sAspect, "$METHOD_ARG_NAME$", arg); if (!arg.equals("")) {
arg = "args(" + arg + ") && "; }
sAspect = Utils.replaceStr(sAspect, "$ARGS$", arg); sAspect = Utils.replaceStr(sAspect, "$METHOD_RETURN$", Utils.getMethodReturn(method));
sAspect = Utils.replaceStr(sAspect, "$METHOD_NAME$", Utils.getMethodName(method));
sAspect = Utils.replaceStr(sAspect, "$METHOD_ARG$", Utils.getMethodArgs(method));
sAspect = Utils.replaceStr(sAspect, "$METHODNAME$", Utils.getMethodNameOverload(method));
sAspect = Utils.replaceStr(sAspect, "$METHODNAMEPC$", Utils.getMethodNameOverload(method).replace(".", "_"));
sAspect = Utils.replaceStr(sAspect, "$MinSpec$", Long.toString(timeMinSpec));
sAspect = Utils.replaceStr(sAspect, "$MaxSpec$", Long.toString(timeMaxSpec));
result += sAspect; }
return result; }
static final String aspectHead = "\r\n"
+ "import org.aspectj.lang.JoinPoint; \r\n" + "\r\n"
+ "public aspect TimingChecker{\r\n" + " long startSys = 0;\r\n" + " long endSys = 0;\r\n" + " long start;\r\n" + " long end;\r\n" + " int flagChecker = 1;\r\n" + " TimingChecker(){\r\n" + " }\r\n" + "$ASPECT_BODIES$\r\n" + "}\r\n"; Hình 4.7 – Template aspectHead. static String aspectTail =
" void log(JoinPoint jp) {\r\n" + " String s = \"WRONG: \" +\r\n" + " jp.getSourceLocation() + \":\" + \r\n" + " jp.getSignature();\r\n" + " System.out.println(s);\r\n" + " }\r\n" + " void log(String s) {\r\n" + " System.out.println(\"INF: \"+ s);\r\n" + " }\r\n" + " void CheckTotalTime() {\r\n" + " int flagSpec = $Flag$;\r\n"
+ " long totalMinTimeSpec = $TotalMinTimeSpec$;\r\n" + " long totalMaxTimeSpec = $TotalMaxTimeSpec$;\r\n" + " long currentTotalSys = endSys - startSys;\r\n" + " if (flagSpec == flagChecker) {\r\n"
+ " log(\"CurrentTotal Time System: \" + currentTotalSys); \r\n"
+ " if (currentTotalSys > totalMaxTimeSpec) {\r\n" + " log(\"Over Total Time Alow\"); \r\n"
+ " }\r\n"
+ " else if (currentTotalSys < totalMinTimeSpec) {\r\n"
+ " log(\"Less Total Time Alow\"); \r\n" + " }\r\n"
+ " }\r\n"
+ " flagChecker += 1;\r\n" + " }\r\n";