Tính toán giá trị mức giới hạn trên tổng chi phí tài nguyên cho một chƣơng trình TFJ

Một phần của tài liệu Phương pháp dựa trên hệ thống kiểu để tính cận trên tài nguyên của các chương trình Featherweight Java có giao tác (Trang 49)

trình TFJ

a) Mô tả thuật toán

Đầu vào: Mã chƣơng trình Featherweight Java có giao tác.

Đầu ra: Giá trị giới hạn trên tổng chi phí tài nguyên hoặc thông báo “chƣơng trình thành lập không hợp lệ”.

Thuật toán ta có thể chia nhỏ thành các giai đoạn đoạn sau:

Hình 4.2Mô tả các giai đoạn để tính giá trị giới hạn trên tài nguyên

Trong đó:

Giai đoạn 1: Giai đoạn ta kết xuất đƣợc chuỗi TFJ (stringTFJPrimitive) từ mã chƣơng trình TFJ (source TFJ). Đây ta đặt cho nó có ý nghĩa là chuỗi nguyên thủy bởi lẽ chuỗi này chỉ chứa các thành phần +1, -1, (, ) lần lƣợt tƣơng ứng đƣợc chuyển đổi với các thành phần onacid, commit, spawn, endspawn trong chƣơng trình TFJ thông qua bộ

52

phân tích cú pháp(TFJparser). Một đặc điểm của chuỗi này là ở các thành phần biểu diễn luồng con nó có thể chƣa có thông số đầy đủ về các thành phần commit mà nó cần đóng các log đã đƣợc kế thừa từ cha của chúng(tức là các -1 ở các thời điểm joint commit cuối cùng mỗi một luồng). Do đó ta cần có một giai đoạn chuẩn hóa chúng để đảm bảo rằng sau khi kết thúc luồng con ), tức là endspawn, chúng ta luôn luôn giải phóng hết các log mà nó kế thừa từ cha nó chƣa đƣợc giải phóng. Điều này sẽ đƣợc sử lý qua các giai đoạn tiếp theo đây.

Giai đoạn 2: Giai đoạn ta phân tích các thành phần chuỗi stringTFJPrimitive từ trái qua phải trong đó mỗi phần tử ở dạng “(” hoặc “)” hoặc là A với A là một dãy liên tiếp của “+1” và -1 và đƣa vào ngăn xếp stackTFJ.

Giai đoạn 3: Tối ƣu hóa ngăn xếp stackTFJ để đƣa về dạng ngăn xếp

stackOptimizationTFJ có thể áp dụng tính toán đƣợc, bổ sung thông tin đóng tài nguyên, tức là các thông tin commit để đóng các onacid chƣa đƣợc đóng kế thừa từ luồng cha ở mỗi luồng con nếu có. Theo đó, các phần tử của nó sẽ có dạng “(” hoặc “)j” hoặc “j” hoặc là A với A là một dãy liên tiếp của “+1” và -1.

Giai đoạn 4: Tính toán giá trị giới hạn trên cho tổng chi phí tài nguyên

valueEstimateResource cần dùng.

Ví dụ 4.3: Các giai đoạn thuật toán cho một chƣơng trình TFJ.

Cho một chƣơng trình TFJ đầu vào có dạng mã nhƣ sau:

public class a{

public int sum(int p, int q) { int result=0; result:=p+q; return result; } } public class b { public int main(){ int valueresult; a ob= new a; onacid spawn onacid onacid valueresult :=0; commit onacid spawn onacid valueresult := ob.sum(3,5); commit commit commit commit endspawn commit

53 commit commit endspawn commit } }

Khi đó, mã trên có thể mô hình hóa ở dạng các luồng lồng nhau nhƣ Hình 4.3 sau:

Hình 4.3 Mô hình chương trình TFJ cho Ví dụ 4.3

Giai đoạn 1: Lấy đƣợc chuỗi stringTFJPrimitive là “ +1(+1+1-1+1(+1-1-1-1)-1-1-1)-1” Giai đoạn 2: Phân tích chuỗi stringTFJPrimitive thành một ngăn xếp stackTFJ.

Giai đoạn 3: Tối ƣu ngăn xếp stackTFJ thành ngăn xếp stackOptimizationTFJ.

Ở giai đoạn này stackOptimizationTFJ đã chứa thông tin về việc đóng các onacid

kế thừa từ luồng cha ở mỗi luồng con, đầy đủ hóa cho việc sử dụng phép toán gộp ⊗ vào thuật toán và là căn cứ để xác định mức độ ƣu tiên khi tính toán với việc bổ sung các thành phần mà ta qui ƣớc là “j” hoặc “)j” hoặc các -1, commit, ở cuối mỗi luồng con còn thiếu.

Giai đoạn 4: Tính giá trị giới hạn trên của tổng chi phí tài nguyên.

valueEstimateReource = #8 Hình 4.4 minh họa tổng hợp các giai đoạn:

Hình 4.4 Minh họa ví dụ các giai đoạn để tính giới hạn trên tổng chi phí tài nguyên

54

Khi một chƣơng trình đƣợc coi là thành lập đúng thì ta có thể áp dụng một số thuật toán nhƣ sau:

Thuật toán 1: Chuyển một chuỗi stringTFJPrimitive sang dạng stackTFJ. Bƣớc 1: Nhận giá trị đầu vào xâu stringTFJPrimitive,

Khởi tạo stackTFJ = null, lƣu trữ xâu trả về

i=0, biến đếm chỉ số cho từng ký tự.

Bƣớc 2: Nếu i>= TFJString.Length thì trả về ngăn xếp stackTFJ và kết thúc. Bƣớc 3: Nếu TFJString[i] != „(‟TFJString[i] != „)‟ thì

temp=temp+ TFJString[i] , i=i+1 và quay về Bƣớc 2. Bƣớc 4: Nếu TFJString[i] = „(‟ thì

Bƣớc 4.1: Nếu temp.Length>0 thì stackTFJ.Push(temp). Bƣớc 4.2 : stackTFJ.Push(„(‟) , quay về Bƣớc 2.

Bƣớc 5: Nếu TFJString[i] = „)‟ thì

Bƣớc 5.1: Nếu temp.Length>0 thì stackTFJ.Push(temp).

Bƣớc 5.2: stackTFJ.Push(„)‟) , quay về Bƣớc 2.

Thuật toán 2: Tối ƣu một ngăn xếp stackTFJ sang ngăn xếp stackOptimizationTFJ. Qui ƣớc: + reverseStackTFJ là một ngăn xếp đảo ngƣợc của stackTFJ.

+ stackLocalBalance là một ngăn xếp lƣu giá trị cân bằng tại các thời điểm „)‟ trong phạm vi tính từ „(‟ tƣơng ứng ở reverseStackTFJ, hay nói cách khác chính là giá trị cân bằng số onacid - số commit trong 1 luồng con. + globalBalance là một giá trị cân bằng toàn cục tại 1 thời điểm.

+ stackBrackets là ngăn xếp lƣu các giá trị các dấu „(‟, „)‟ có thứ tự gặp khi loại bỏ một phần tử trong ngăn xếp reverseStackTFJ.

+ stackOptimizationTFJ là ngăn xếp đƣợc tối ƣu, là giá trị trả về.

+ itemReverseStackTFJ là giá trị mỗi phần tử lấy ra từ reverseStackTFJ + Phƣơng thức balanceTFJ(stringTFJ) lấy hệ số cân bằng của chuỗi số có dấu (đại diện cho một luồng đơn, ví dụ balanceTFJ(“+2-1+1-1”)=1).

+ Phƣơng thức balancePrimitive(stringTFJPrimitive) lấy hệ số cân bằng của chuỗi có dấu chỉ chứa 2 thành phần +1 và -1 (đại diện cho một luồng đơn, ví dụ balancePrimitive (“+1-1+1+1”)=2).

Bƣớc 1: Nhận giá trị đầu vào một ngăn xếp stackTFJ

Khởi tạo: reverseStackTFJ= reverseStack(stackTFJ), stackLocalBalance = null, stackOptimizationTFJ=null, stackBrackets =null, globalBalance=0, itemReverseStackTFJ= “”, stackLocalBalance.Push(0)

Bƣớc 2: Nếu reverseStackTFJ.Count <=0 thì chuyển sang Bƣớc 7 Bƣớc 3: itemReverseStackTFJ = reverseStackTFJ.Pop()

55 Bƣớc 4.1: Nếu stackOptimizationTFJ.Count >= 1 thì Nếu stackOptimization.First() == "(" thì stackLocalBalance.Push(0), stackOptimizationTFJ.Push(“#0”) Chuyển sang Bƣớc 4.2 Bƣớc 4.2: Nếu stackOptimizationTFJ.Count == 0 thì Nếu stackOptimizationTFJ.First() == "(" thì stackOptimizationTFJ.Push(“#0”) Chuyển sang Bƣớc 4.3 Bƣớc 4.3: stackOptimizationTFJ.Push(itemReverseStackTFJ), stackBrackets.Push(“(”)

Rồi quay lại Bƣớc 2

Bƣớc 5: Nếu itemReverceStackTFJ = “)” thì Bƣớc 5.1: firstStackBrackets =stackBrackets.First(), tempItemStackOptimization= stackOptimizationTFJ.Pop(), firstStackBrackets =stackBrackets.First(), stackOptimizationTFJ.Push(canonical (temItemStackOptimization+ “-”+golobalBalance.toString()))

Bƣớc 5.2: Nếu firstStackBrackets == "(" || tempItemStackOptimization=="#0"

thì lobalBalance = globalBalance-stackLocalBalance.Pop(); Chuyển sang Bƣớc 5.4 Bƣớc 5.3: lobalBalance = globalBalance-stackLocalBalance.Pop() -stackLocalBalance.Pop(); Chuyển sang Bƣớc 5.4 Bƣớc 5.4: Nếu firstStackBrackets = “(” thì Bƣớc 5.4.1: stackOptimizationTFJ.Push(“j”) Bƣớc 5.4.2: Nếu reverseStackTFJ.Count >0 thì Bƣớc 5.4.2.1 : Nếu reverseStackTFJ.First() = “)” thì stackOptimizationTFJ.Push(“#0”) Chuyển tới Bƣớc 5.6 Bƣớc 5.4.2.2: stackOptimizationTFJ.Push("#0"), Chuyển tới Bƣớc 5.6 Bƣớc 5.5: Nếu firstStackBrackets= “)” thì Bƣớc 5.5.1: stackOptimizationTFJ.Push(“)j”) Bƣớc 5.5.2: Nếu reverseStackTFJ.Count >0 thì Bƣớc 5.5.2.1 : Nếu reverseStackTFJ.First() = “)” thì stackOptimizationTFJ.Push(“#0”) Chuyển tới Bƣớc 5.6 Bƣớc 5.5.2.2: stackOptimizationTFJ.Push("#0"), Chuyển tới Bƣớc 5.6

56

Bƣớc 5.6: stackBrackets.Push(“)”), quay lại Bƣớc 2 Bƣớc 6: Bƣớc 6.1: stackOptimizationTFJ.Push(“itemReverseStackTFJ”) globalBalance = balanceTFJ( "+" + globalBalance.ToString() + itemReverseStackTFJ.ToString()) Bƣớc 6.2: Nếu globalBalance<0 thì

stackOptimizationTFJ.Clear();// Xóa các phần tử stack stackOptimizationTFJ.Push("Lỗi đóng hết giao

tác không hợp lệ"); Chuyển sang Bƣớc 8 Bƣớc 6.3: Nếu reverseStackTFJ.Count() > 0 thì stackLocalBalance.Push(balancePrimitive(itemReverseStackTFJ)); Chuyển về Bƣớc 2 Bƣớc 7: Nếu globalBalance > 0 thì

stackOptimizationTFJ.Clear() ; // Xóa các phần từ trong stack stackOptimizationTFJ.Push("Lỗi chưa đóng hết giao tác")

Bƣớc 8: return stackOptimizationTFJ

Kết thúc

Thuật toán 3: Tính toán giá trị giới hạn trên tổng chi phí tài nguyên với đầu vào là

stackOptimizationTFJ.

Qui ƣớc: + stackOptimizationTFJ là ngăn xếp đầu vào.

+ stackEstimate là một ngăn xếp lƣu các giá trị tạm thời trong tính toán tài nguyên.

+ stackBrackets là ngăn xếp lƣu các giá trị các dấu „(‟, „)‟ có thứ tự gặp khi loại bỏ một phần tử trong ngăn xếp stackOptimizationTFJ .

+ result là giá trị trả về, giới hạn trên tổng chi phí tài nguyên.

+ Các lời gọi phƣơng thức canonical(X), chính tắc hóa một chuỗi có dấu X. + Các lời gọi phƣơng thức joint(X,Y), phép tính gộp ⊗ của 2 chuỗi số có dấu X,Y.

Bƣớc 1: Nhận giá trị đầu vào một ngăn xếp stackOptimizationTFJ. Khởi tạo:

stackEstimate = null, stackBrackets =null, result= “”,

Bƣớc 2: Nếu stackOptimizationTFJ.Count <=0 thì

result=stackEstimale.First(), // Chứa giá trị tài nguyên hoặc thông báo lỗi Kết thúc.

Bƣớc 3: X = canonical (stackOptimizationTFJ.Pop())

Bƣớc 4: Nếu X = “j” thì

stackBrackets.Push(“j”),

Rồi quay lại Bƣớc 2 Bƣớc 5: Nếu X = “)j” thì

57 stackBrackets.Push(“)j”), Quay lại Bƣớc 2 Bƣớc 6: Nếu X = “(” thì Bƣớc 6.1: Nếu stackBrackets.First() = “(” thì T1=canonical(stackEstimate.Pop() ) T2=canonical(stackEstimate.Pop() ) T = join (T1, T2) stackEstimate.Push(T) Bƣớc 6.2: stackBrakets.Push(“(”) , quay về Bƣớc 2 Bƣớc 7: Nếu stackBrackets.Count >0 thì Bƣớc 7.1: Nếu stackBrackets.First()= “j” thì T1=canonical(stackEstimate.Pop()) T=join (canonical(X), T1) stackEstimate.Push(T) Quay lại Bƣớc 2 Bƣớc 7.2: Nếu stackBrackets.First() = “(” thì T1=canonical(stackEstimate.Pop()) T=join(canonical(X+T1) stackEstimate.Push(T) Quay lại Bƣớc 2 Bƣớc 7.3: stackEstimate.Push(T) Quay lại Bƣớc 2 Bƣớc 8: stackEstimate.Push(canonical(X)) Quay lại Bƣớc 2

Nói tóm lại, trong Chƣơng 4 này chúng ta đi mô tả các bƣớc xây dựng một bộ công cụ tính kiểu tự động. Dựa trên cú pháp TFJ đã đƣợc nghiên cứu từ các công trình nghiên cứu trƣớc đó, ta đi xây dựng đặc tả một bộ cú pháp TFJ cụ thể trên ANTLR, trong đó tập trung đƣa yếu tố quản lý bộ nhớ dựa trên giao tác, thông qua đó hình thành các chƣơng trình TFJ tuân thủ theo ngữ pháp đã thành lập. Đích cuối cùng của bộ công cụ tính kiểu tự động là nhận chƣơng trình TFJ nhƣ một dữ liệu đầu vào để đƣa ra đánh giá về chƣơng trình có thành lập đúng theo ngữ pháp hay không và đƣa ra giá trị giới hạn trên về chi phí tài nguyên cho chƣơng trình đó.

58

CHƢƠNG 5. THỰC NGHIỆM

Trong chƣơng này chúng ta sẽ đƣa ra một số ví dụ thực nghiệm cho thấy rằng bộ công cụ tính kiểu tự động chạy đúng, tức là kết quả tính toán tài nguyên tĩnh cho các chƣơng trình Featherweight Java có giao tác nhờ bộ công cụ này là đúng so với tính toán bằng tay.

Thực nghiệm 1: Xét một bài toán viết các chƣơng trình cho mô hình đơn giản để thể hiện tính năng hỗ trợ của cú pháp TFJ nhƣ: Triệu gọi phƣơng thức (từ bản thân lớp chính hoặc từ một lớp khác), khai báo lớp, tạo đối tƣợng.

Cho mô hình nhƣ sau:

Hình 5.1 Mô hình giao tác Thực nghiệm 1

Gọi S1 là tài nguyên cần tính, áp dụng lý thuyết kiểu để tính kiểu cho mô hình này ta có đƣợc: S1=+1+1 (+1+1 −1−1−1+1−1−1⨂+1 −1−1+1+1 +1 −1−1−1−1) ≅ +2 (#2−1#1−1⨂#1−1#3−1) ≅ +2 #3¬2(#1−1⨂#3−1) ≅ +1 #3¬2#4¬2 ≅ +1 #5#4¬2 ≅ +1 #5¬2 ≅ #7

Sau đây là bộ mã chƣơng trình mô tả cho mô hình giao tác trên:

Mã chương trình 1: Chƣơng trình đơn giản, xử lý trong phƣơng thức main, một lớp. class a

{

public int main() {

onacid

onacid

spawn

onacid //Bat dau e1 onacid

write("cong viec 1"); commit

commit // Ket thuc e1 commit

59 write("cong viec 2"); commit commit endspawn onacid write("cong viec 3"); commit commit onacid onacid onacid write("cong viec 4"); commit commit commit commit } }

Kết quả màn hình thực nghiệm cho ta thấy giá trị thu đƣợc bằng với kết quả tính toán ở trên:

Hình 5.2 Chạy mã Thực nghiệm 1 trên công cụ

Mã chương trình 2: Chƣơng trình triệu gọi phƣơng thức trong một lớp và trong một lớp khác.

class B {

int max(int a, int b) { int result =0; onacid

60 else {result:=b} commit return result; } } class A { void task1(){ onacid onacid write("cong viec 1"); commit commit } void task2(){ onacid write("cong viec 2"); commit } void task3(){ onacid write("cong viec 3"); commit } void task4(){ onacid onacid onacid write("cong viec 3"); commit commit commit }

public int main() { B ob= new B; ob.max(4,5); onacid onacid spawn this.task1(); commit this.task2(); commit endspawn this.task3(); commit this.task4(); commit } }

Theo mã chƣơng trình này ta thấy phƣơng thức main() nằm trong lớp A khởi tạo một đối tƣợng ob thuộc lớp B và đồng thời triệu gọi phƣơng thức max(int a, int b) của lớp

B. Ngoài ra, nó cũng triệu gọi các phƣơng thức nội tại ở lớp A thông qua con trỏ this. Sau khi triệu gọi tất cả các lệnh liên quan đến giao tác nhƣ onacid, commit, spawn, endspawn

có mặt trong các phƣơng thức sẽ đƣợc cộng dồn tại vị trí mà phƣơng thức đƣợc triệu gọi. Thao tác kiểm tra tƣơng tự nhƣ với mã chƣơng trình 1 ta vẫn thu đƣợc mô hình giao tác giống và kết quả tài nguyên nhƣ mã chƣơng trình 1.

61

Thực nghiệm 2: Xây dựng một chƣơng trình cho bài toán đa luồng. Sử dụng lại bài toán đã thảo luận ở các chƣơng trƣớc theo mô hình sau:

Hình 5.3 Mô hình giao tác cho Thực nghiệm 2

Trong đó e1 đóng góp 1 giao tác, e2 đóng góp 2 giao tác, e3 đóng góp 3 giao tác, e4

đóng góp 4 giao tác.

Gọi S2 là tài nguyên cần tính, áp dụng lý thuyết kiểu để tính kiểu cho mô hình này ta có đƣợc: S2=+1+1 [#1−1−1 +1(#2−1−1−1−1 #3−1#4−1)] +2[#1−2+1(#2−3−1#3−1#4−1)] +2(#1−2+1#2¬2#3¬2#4−2) +2(#1−2#4#3¬2#4¬2) +2(#1−2#4¬2#4¬2) +2#5¬3#4¬3 +1#8#4¬3 +1#8¬3 #11

Sau đây là bộ mã chƣơng trình TFJ mô tả mô hình giao tác trên: class a

{

public int main() {

onacid

onacid

spawn

onacid //Bat dau e1

write("cong viec 1"); commit // Ket thuc e1 commit

commit endspawn onacid

spawn

onacid //Bat dau e2 onacid

write("cong viec 2"); commit

commit // Ket thuc e2 commit

62 commit endspawn commit

onacid //Bat dau e3 onacid

onacid

write("cong viec 3"); commit

commit

commit // Ket thuc e3 commit

onacid //Bat dau e4 onacid onacid onacid write("cong viec 4"); commit commit commit

commit // Ket thuc e4 commit

} }

Và kết quả ta thu đƣợc màn hình chƣơng trình sau

63

KẾT LUẬN

Luận văn đã tổng quát hóa đƣợc các khái niệm cũng nhƣ kiến thức về hệ thống kiểu, bộ nhớ giao tác phần mềm, trình bày đƣợc cú pháp, ngữ nghĩa của TFJ. Mặt khác điểm nổi bật mà đề tài tập trung nhất là đã áp dụng lý thuyết phƣơng pháp hệ thống kiểu để xây dựng bộ công cụ tính kiểu tự động. Quá trình xây dựng bộ công cụ tự động tính kiểu này bao gồm xây dựng module các phép toán tính kiểu trên chuỗi số có dấu, từ đó làm thƣ viện cho việc giải quyết bài toán cuối cùng đó là tạo một module, với một chƣơng trình đầu vào Featherweight Java có giao tác ta có thể tính toán tĩnh giới hạn trên tổng tài nguyên chi phí khi chƣơng trình thành lập đúng hoặc ngƣợc lại đƣa ra thông báo nhận xét chƣơng trình thành lập không đúng.

Xét về mặt đƣa vào thực tiễn, đề tài này vẫn còn khá mới mẻ, chỉ đƣợc kiểm chứng ở mức độ nghiên cứu. Cụ thể, thực nghiệm thể hiện giải thuật cho các phép toán tính toán kiểu và đi xây một cú pháp cho ngôn ngữ TFJ trên ALTNR , từ đó với các chƣơng trình viết ra tuân theo chuẩn ngữ pháp ngôn ngữ này ta có thể tính toán tĩnh giá trị giới hạn trên của tổng chi phí tài nguyên. Việc xây dựng một ngữ pháp cho ngôn ngữ còn nhiều hạn chế (chƣa xét đến các thuộc tính phức tạp của một ngôn ngữ hƣớng đối tƣợng nhƣ kế thừa, đa hình, lớp ảo …), đồng thời việc tính giá trị tài nguyên ở trên cũng chỉ dừng lại ở mức các giao tác và các luồng lồng nhau mà chƣa xét đến trƣờng hợp có điều kiện logic (tƣơng ứng với việc sử dụng phép toán chọn trong tính kiểu). Chính vì vậy, để áp dụng hệ thống kiểu này vào thực tiễn cho các ngôn ngữ trong các hệ thống phần mềm lớn thì cần phải mất nhiều thời gian và công sức hơn nữa. Hy vọng rằng kết quả của hƣớng nghiên cứu này sẽ là cơ sở cho các nghiên cứu tiếp theo nhằm tối ƣu các chƣơng trình phần mềm, đáp ứng đƣợc nhu cầu thực tế của ngƣời dùng trong tƣơng lai.

64

TÀI LIỆU THAM KHẢO Tiếng Anh

1. Benjamin C. Pierce (2002), Types and Programming Languages, MIT Press.

2. Suresh Jagannathan, Jan Vitek, Adam Welc, and Antony Hosking, (2005), “A transactional object calculus”.

3. Luca Cardelli (1997), Type systems.

4. Robert Harper (2012), Practical Foundations for Programming Languages.

5. Hoang Truong (2006), Type Systems for Guaranteeing Resource Bounds of Component Software.

6. T. Mai Thuong Tran, O. Owe, and M. Steffen (2010), “Safe typing for transactional vs. lock-based concurrency in multi-threaded Java”.

7. M. Steffen and T. M. T. Tran (2009), “Safe commits for Transactional Featherweight Java”.

8. Ronald Garcia (2007), Static Computation and Reflection.

9. Matthias Ladkau (2009), A Wide Spectrum Type System for Transformation Theory. 10. Jiang Hui, Lin Dong, Zhang Xingyuan, Xie Xiren (2001), “Type System in

Programming Languages”.

11. Igarashi, Atsushi, Pierce Benjamin C, Wadler, Philip (2001), “Featherweight Java: a

Một phần của tài liệu Phương pháp dựa trên hệ thống kiểu để tính cận trên tài nguyên của các chương trình Featherweight Java có giao tác (Trang 49)

Tải bản đầy đủ (PDF)

(85 trang)