Kiểm chứng chương trình trong Spin

Một phần của tài liệu Kiểm chứng tính đúng đắn hệ thống tính toán của chương trình bằng kiểm duyệt mô hình (Trang 32)

4. Cấu trúc luận văn

2.2.1.Kiểm chứng chương trình trong Spin

2.2.1.1. Đặc trưng của SPIN

Spin (Simple Promela Interpreter) là một công cụ kiểm chứng, nó hỗ trỡ ngôn ngữ đặc tả hệ thống Promela. Spin được dùng để theo dõi những lỗi logic ở trong những bản thiết kế của hệ thống phân tán như hệ điều hành, giao thức truyền thông dữ liệu, thuật toán song song, giao thức báo hiệu tàu điện,...Ta có thể sử dụng Spin mà không cần phải dựng lên mô hình dưới dạng đồ thị trạng thái [5].

Spin hỗ trợ kiểm chứng mọi thuộc tính yêu cầu có thể biểu diễn dưới dạng LTL (Linear Temporal Logic – Logic thời gian tuyến tính), hoặc cũng có thể sử dụng các khẳng định – assertion để đặc tả một số thuộc tính cần kiểm chứng.

Ngôn ngữ đặc tả Promela được sử dụng để diễn tả mô hình hệ thống và thuộc tính của nó để kiểm chứng mô hình.

Spin có thể mô phỏng sự thực thi của hệ thống.

Việc sử dụng Spin rất đơn giản, hiệu quả cao, và nó phù hợp để kiểm chứng hệ thống phân tán.

2.2.1.2. Mô hình hệ thống trong SPIN

Các hệ thống được mô hình hóa trong Spin như là một tập các tiến trình (mạng các Automata), được chạy song song theo chế độ đan xen và giao tiếp với nhau qua các thông điệp hay qua chia sẻ các biến.

Hình 2.1: mô hình của hệ thống trong Spin [5]

2.2.1.3. Cấu trúc của Spin

Cấu trúc cơ bản của Spin được thể hiện trong hình 2.2. Luồng công việc bắt đầu từ việc đặc tả mô hình ở mức cao của hệ thống hiện thời, qua giao diện Front-End của Xspin (giao diện đồ họa người dùng của Spin), sau đó kiểm tra lỗi cú pháp, thực hiện mô phỏng tương tác cho đến khi người dùng nhận được sự tin cậy cơ bản mô hình thuộc tính mong đợi. Một chương trình Promel đúng đắn có thể yêu cầu được tạo từ một công thức được đặc tả trong logic thời gian tuyến tính (LTL). Sau đó Spin được sử dụng để tạo một chương trình xác minh tối ưu. Chương trình xác minh này được biên dịch với thời gian biên dịch có thể được chọn trước, và sau đó thực hiện xác minh chính nó. Nếu bất kỳ phản ví dụ nào thỏa mãn yêu cầu tính đúng đắn được phát hiện thì chúng có thể được đưa trở lại để mô phỏng trong Spin. Việc mô phỏng có thể được kiểm tra chi tiết để xác định nguyên nhân [3].

Shared Variables (shared memory)

Channels

System Global Scope

access access

send & receive send & receive

Pro ce ss A lo cal sc op e Pro ce ss B lo cal sc op e

Hình 2.2: Cấu trúc của Spin [3]

2.2.1.4. Giả lập ngẫu nhiên

Spin biên dịch và chạy một chương trình Promela trong chế độ giả lập ngẫu nhiên rồi in ra các trạng thái của chương trình, sau đó in ra các trạng thái của thuộc tính.

Một trạng thái của chương trình là bộ các giá trị của các biến, biến đếm vị trí các tiến trình. Một tính toán của chương trình là chuỗi các trạng thái bắt đầu bởi trạng thái khởi tạo và tiếp tục với những trạng thái xuất hiện sau khi mỗi câu lệnh được thực hiện [3].

Ví dụ 2.26.Chương trình với 2 tiến trình

1 byte n=0; 2 active proctype P(){ 3 n=1; 4 printf("Process P, n=%d\n",n); 5 } 6 active proctype Q(){ 7 n=2; Model-Specific ANSI C code Executable Verifier Counter - Examples XSPIN Front – End (Tcl/Tk code) PROMELA Parser Random/Guided Simulation LTL Parser and Translator Verifier Generator Syntax Error Reports

8 printf("Process Q, n=%d\n",n); 9 }

Trong ví dụ 2.26 biến n được khởi tạo với giá trị 0, chương trình bao gồm 2 tiến trình: PQ tương ứng gán biến n giá trị 1 hoặc 2 và in ra tên tiến trình và giá trị của n.

Chạy chương trình trong ví dụ 2.26 trên ở chế độ Random, chương trình không có lỗi và nhận được kết quả:

Starting P with pid 0

0: proc - (:root:) creates proc 0 (P) Starting Q with pid 1

0: proc - (:root:) creates proc 1 (Q) 1 Q 7 n = 2 Process Statement n 0 P 3 n = 1 2 Process P, n=1 0 P 4 printf('Proces 1 Process Q, n=1 1 Q 8 printf('Proces 1 4: proc 1 (Q) terminates 4: proc 0 (P) terminates 2 processes created

Trong ví dụ 2.26, đầu tiên PQ lần lượt được tạo với pid (process id) là 0 và 1. Các lệnh trong cả hai tiến trình được thực thi xen kẽ một cách tùy ý. Xspin hiển thị trạng thái của chương trình sau mỗi câu lệnh được thực thi (theo thứ tự: pid, tên tiến trình chứa câu lệnh, vị trí câu lệnh, nội dung câu lệnh đã được cắt ngắn, giá trị của biến).

Trong lần chạy ở trên các câu lệnh được thực hiện theo thứ tự: (adsbygoogle = window.adsbygoogle || []).push({});

n=2 n=1 prinf(Q) prinf(P)

Do vậy hai hàm printf đều in ra n=1

2.2.1.5. Kiểm chứng (Verify)

Assertion là cách đơn giản để kiểm tra chương trình. Một assertion là một mệnh đề được đặt trong 1 chương trình mà ta cho rằng mệnh đề sẽ luôn đúng tại vị trí đó. Spin sẽ tính toán các assertion trong quá trình tìm kiếm phản ví dụ trong không gian trạng thái của chương trình.

Ví dụ 2.27. Tìm số lớn nhất trong 2 số active proctype P() { int a = 5, b = 5; int max; if :: a >= b -> max = a :: b >= a -> max = b fi;

assert (a >= b -> max == a : max == b) }

Đoạn mã trong ví dụ 2.27 tìm số lớn nhất trong 2 số ab, trong câu lệnh

if, nếu a >=b biến max sẽ được gán giá trị a, nếu b>=a biến max sẽ được gán giá trị b, ở cuối chương trình ta kiểm tra lại bởi biểu thức logic (a >= b -> max = = a : max = = b).

Chạy đoạn mã trong ví dụ 2.27 ở chế độ Verify, kết quả là không có lỗi vi phạm nào được thông báo từ chương trình.

(Spin Version 4.3.0 -- 22 June 2007) + Partial Order Reduction

Full statespace search for:

never claim - (none specified) assertion violations +

cycle checks - (disabled by -DSAFETY) invalid end states +

State-vector 24 byte, depth reached 2, ••• errors: 0 ••• 3 states, stored

1 states, matched

4 transitions (= stored+matched) 0 atomic steps

hash conflicts: 0 (resolved) 2.302 memory usage (Mbyte) unreached in proctype P (0 of 8 states)

Ví dụ 2.28: Chương trình có chứa lỗi

active proctype P() { int a = 5, b = 6; int max;

:: a >= b -> max = a :: b >= a -> max = b+1 fi;

assert (a >= b -> max == a : max == b) }

Trong ví dụ 2.28, ta cũng tìm số lớn nhất trong 2 số a, b nhưng khi b>=a, biến max lại được gán giá trị b+1, do vậy biểu thức (a >= b -> max = = a : max = = b) không được thỏa mãn.

Khi chạy Verify đoạn mã trong ví dụ 2.28 sẽ đưa ra thông báo assertion bị vi phạm.

pan: assertion violated ( ((a>=b)) ? ((max==a)) : ((max==b)) ) (at depth 0)

pan: wrote max.pml.trail

(Spin Version 4.3.0 -- 22 June 2007) Warning: Search not completed + Partial Order Reduction Full statespace search for:

never claim - (none specified) assertion violations +

cycle checks - (disabled by -DSAFETY) invalid end states +

State-vector 24 byte, depth reached 2, ••• errors: 1 ••• 3 states, stored

0 states, matched (adsbygoogle = window.adsbygoogle || []).push({});

3 transitions (= stored+matched) 0 atomic steps

hash conflicts: 0 (resolved) 2.302 memory usage (Mbyte)

2.2.2. Giao diện người dùng Xspin

Màn hình chính của Xspin là một cửa sổ văn bản hiển thị các tập tin được sử dụng, nó giống như một trình soạn thảo văn bản. Xspin có giao diện thân thiện người dùng cung cấp khả năng chỉnh sửa và tìm kiếm.

Hình 2.3: Màn hình cửa sổ chính của XSpin

Các chức năng trong menu File, Edit, View, Help trợ giúp việc mở file, lưu file, các thao tác sao chép, chỉnh sửa, hiển thị, và thông tin trợ giúp. Menu Run chứa các chức năng chính để kiểm tra, mô phỏng, và xác minh mô hình qua chương trình.

Mỗi chức năng trong menu Run thực hiện nhiệm vụ riêng:

 Run Syntax Check: Luôn là bước được thực hiện đầu tiên sau mỗi sự thay đổi của chương trình. Chức năng này sẽ kiểm tra cú pháp của chương trình viết bằng ngôn ngữ Promela.

 Run Slicing Algorithm: Xác định những thành phần không ảnh hưởng đến các thuộc tình trong mô hình. Nó thể hiện sự phân tích lưu lượng dữ liệu.

 Set Simulation Parameters: Là chức năng hỗ trợ gỡ lỗi quan trọng. Chức năng này sẽ thiết lập các thông số hiển thị:

 MSC Panel (Message Sequence Chart): Bảng điều khiển các thông số hiển thị của biểu đồ tuần tự thông điệp.

 Time Sequence Panel - with: Bảng điều khiển các thông số giao tiếp tuần tự theo thời gian.

 Data Values Panel: Điều khiển trình bày giá trị dữ liệu. Tùy chọn gồm các kênh đệm các biến địa phương và biến toàn cục.

 Random : Yêu cầu người sử dụng cung cấp giá trị trong Seed Value.

 Run Simulation

 Việc thiết lập các thông số hiển thị phải được thực hiện ít nhất một lần trước khi thực hiện Run Simulation.

 Việc thiết lập mặc định thông số hiển thị sẽ sinh ra 3 cửa sổ sau:

o Simulation Output: Cung cấp 2 phương thức là chạy từng bước (Single Step) hoặc chạy liên tục (Run).

o Data Values: Hiển thị kết quả các giá trị dữ liệu.

o Sequence Chart: Đưa ra biểu đồ tuần tự.

Hình 2.6: Cửa sổ khi chạy chức năng Run Simulation

 Set Verification Parameters: Thiết lập các tham số để xác minh hệ thống:

 Correctness Properties: Safety, Liveness.

 Search mode.

 A full queue.

 Verify an LTL property.

Hình 2.7: Cửa sổ chính chức năng Set Verification Parameters

 Run Verification: Thực hiện xác minh hệ thống qua chương trình.

 Linear Time Temporal Logic Formulae: Công thức logic thời gian tuyến tính, chức năng này cho phép: Nhập vào công thức logic thời gian tuyến tính (thuộc tính cần kiểm duyệt). Chỉ ra có hay không thuộc tính cần giữ, bằng cách lựa chọn all executions (desired behaviour) hay no executions (error behaviour). Nhập vào một định nghĩa đối với mỗi hằng số mệnh đề trong cửa sổ phụ “Symbol Definitions” (nếu cần). Nhấn “Generate” để tạo cấu trúc Never Claim và nhấn “Run Verification” để xác minh.

Hình 2.9: Cửa sổ khi chạy chức năng LTL Property Manager (adsbygoogle = window.adsbygoogle || []).push({});

 View Spin Automaton for each proctype (FSM View): Đưa ra sự chuyển đổi giữa các trạng thái trong từng tiến trình.

2.2.3. Logic thời gian tuyến tính (LTL - Linear Temporal Logic) trong Spin

Khi sử dụng assertion, Spin sẽ tính toán assertion tại một vị trí nhất định trong chương trình mà ở đó assertion được thêm vào, do đó assertion bị hạn chế trong việc biểu diễn tính chất của mô hình.

Từ đó cần dùng đến logic thời gian tuyến tính LTL, LTL mạnh mẽ hơn trong việc biểu diễn tính chất của mô hình hệ thống. Với LTL ta có thể diễn tả những tính chất chung cần được thỏa mãn mà không liên quan đến một vị trí nào trong chương trình.

LTL phù hợp với các hệ thống tương tác khi tính đúng đắn của hệ thống không chỉ thể hiện ở kết quả tính toán mà ta phải kiểm tra sự giao tiếp và thực thi các tiến trình trong hệ thống [2].

2.2.3.1. Cú pháp Logic thời gian tuyến tính

Các công thức LTL được tạo ra từ các phép toán mệnh đề, công thức các phép toán mệnh đề được tạo ra từ mệnh đề nguyên thủy (p, q,…) và các phép toán trong bảng 2.3:

Bảng 2.3: Các phép toán mệnh đề trong LTL [6]

Operator Math Spin

not ¬ !

and  &&

or  ||

implies → ->

equivalent ↔ <->

LTL hình thức hóa các tính chất về thời gian bởi các toán tử thời gian. Bảng 2.4: Các phép toán thời gian của LTL [6]

Operator Math Spin

always □ [ ]

eventully ◊ < >

until U U

Các phép toán □ và ◊ là phép toán một ngôi, phép toán U là phép toán hai ngôi. Các phép toán thời gian và phép toán mệnh đề được kết hợp tự do với nhau. Chẳng hạn công thức:

□ ( (p ∧ q) → r U (p ∨ r) ) , [] ( (p && q) -> r U (p || r) ) [ ] A: hệ thống luôn luôn mang tính chất A.

<> A: nếu hệ thống có tính chất A tại một thời điểm nào đó trong tương lai thì ta nói hiện tại hệ thống có tính chất <> A.

A U B: tại thời điểm hiện tại hệ thống có tính chất A U B có nghĩa là: nếu trong một thời điểm nào đó trong tương lai hệ thống có tính chất B thì hệ thống có tính chất A tại tất cả các thời điểm từ hiện tại cho tới khi nó mang tính chất B.

Thời gian trong LTL là thời gian “trừu tượng” do LTL quan niệm thời gian một cách rời rạc, chỉ bao bao gồm những thời điểm đơn lẻ [2].

2.2.3.2. Biểu diễn tính chất bất biến của hệ thống bằng LTL

Trong nhiều trường hợp, hệ thống xây dựng phải thỏa mãn một tính chất bất biến nào đó. Với LTL ta biểu diễn tính chất đó bởi toán tử [].

Ví dụ 2.29: Tính chất “mỗi yêu cầu (request) cuối cùng đều dẫn tới một phản hồi (response)” ta biểu diễn như sau:

2.2.4. Cấu trúc Never claim

Có những tính chất mà ta mong muốn nó không bao giờ được xuất hiện trong hệ thống. Trong Promela nó được biểu diễn bởi never claim.

Ví dụ 2.30 (adsbygoogle = window.adsbygoogle || []).push({});

#define A (divisor > 0) never { /* !([] a) */ T0_init:

if

:: (! ((A))) -> goto accept_all :: (1) -> goto T0_init

fi;

accept_all: skip }

Ở ví dụ 2.30 hệ thống cần thỏa mãn rằng biến divisor luôn phải lớn hơn 0, do vậy trường hợp ngược lại không bao giờ được xảy ra hay !(a) luôn phải nhận giá trị false.

Nhãn T0_init đảm bảo trong khi chương trình được chạy (và sinh ra các trạng thái), cho đến khi nào A còn đúng, lệnh goto thứ hai luôn luôn được chọn và Spin sẽ liên tục kiểm tra A.

Khi thuật toán của chúng ta là đúng và chương trình không chứa lỗi, Spin sẽ kết thúc sau khi sinh ra tất cả các trạng thái và thông báo không có trạng thái nào vi phạm được tìm thấy.

Nhưng nếu chương trình tính toán đến một trạng thái mà ở đó A sai (divisor

nhỏ hơn hoặc bằng 0) lệnh goto thứ nhất sẽ được thực hiện, Spin nhảy tới nhãn

accept_all và kết thúc chương trình.

Trong Spin ta chỉ cần biểu diễn tính chất của hệ thống dưới dạng một biểu thức LTL sau đó đưa vào Spin, Spin sẽ tự động chuyển biểu thức LTL sang cấu trúc never claim của Promela dùng vào việc kiểm chứng.

Biểu thức LTL được lưu lại trong tệp .prp có tên trùng với tên chương trình. Đoạn mã never claim được Spin lưu lại trong tệp .ltl.

CHƯƠNG 3: ỨNG DỤNG

Trong chương này sẽ xây dựng biến và tiến trình đồng hồ để thiết lập và đo thời gian, mô tả hệ thống báo động, báo cháy, mô hình hóa hệ thống đó bằng ngôn ngữ Promela sau đó sử dụng kỹ thuật kiểm duyệt mô hình kết hợp với tiến trình đồng hồ xây dựng được để kiểm chứng tính đúng đắn hệ thống báo động, báo cháy qua công cụ kiểm chứng Spin.

3.1. Xây dựng biến và tiến trình đồng hồ

Bàn về kỹ thuật kiểm duyệt mô hình cho hệ thống không có ràng buộc thời gian và có ràng buộc thời gian, có thể đưa ra nhận xét: Với kỹ thuật kiểm duyệt mô hình để kiểm duyệt hệ thống có ràng buộc thời gian thường phức tạp, tốn thời gian nghiên cứu. Ngoài ra nó còn đòi hỏi thời gian chạy lâu và chỉ áp dụng cho những hệ thống nhỏ, bởi hệ thống càng lớn thì số trạng thái càng tăng dẫn tới việc bùng nổ không gian trạng thái. Bùng nổ không gian trạng thái xảy ra khi số trạng thái tăng theo cấp số nhân so với số các biến của hệ thống, chẳng hạn cho biến N với miền giá trị k, khi đó số các trạng thái có thể tăng lên tới kN trạng thái. Với hệ thống song song, hệ thống thời gian thực thì không gian trạng thái dễ dàng vượt ra khỏi giới hạn cho phép. Với kỹ thuật kiểm duyệt mô hình để kiểm duyệt hệ thống không có ràng buộc thời gian dễ tìm hiểu hơn, và hạn chế được phần nào vấn đề bùng nổ không gian trạng thái. Hơn nữa, các kỹ thuật kiểm chứng trợ giúp việc kiểm chứng các tính chất thời gian tổng quát, trong khi các hệ thống có ràng buộc thời gian thực tế thường chỉ đòi hỏi kiểm chứng các tính chất đơn giản ở dạng deadline. Từ những nhận xét trên cho thấy, có thể sử dụng kỹ thuật kiểm duyệt mô hình cho hệ thống không có ràng buộc thời gian kết hợp với kỹ thuật xây dựng biến, tiến trình đồng hồ để kiểm chứng hệ thống có ràng buộc thời gian, cụ thể là hệ thống báo động, báo cháy.

Kỹ thuật kiểm duyệt mô hình được áp dụng để kiểm chứng rất nhiều hệ

Một phần của tài liệu Kiểm chứng tính đúng đắn hệ thống tính toán của chương trình bằng kiểm duyệt mô hình (Trang 32)