220 likes | 297 Views
Verifying Transactional Programs with Programmer-Defined Conflict Detection. O mer Subasi (Koç University ) , T ayfun Elmas ( University of California, Berkeley) , S erdar Tasiran (Koç University ). Motivation: Linked List from Genome. Insert 5. 5. Head. 3. 1. 9. 12. 6. 17.
E N D
Verifying Transactional Programs withProgrammer-Defined Conflict Detection OmerSubasi (Koç University), TayfunElmas (University of California, Berkeley), SerdarTasiran (Koç University)
Motivation: Linked List from Genome Insert 5 5 Head 3 1 9 12 6 17 15 16 Insert 16
Head 3 1 9 12 6 17 15 READ
5 WRITE Head 3 1 9 12 6 17 15 READ
Write-After-Readconflict! 5 WRITE Head 3 1 9 12 6 17 15 WRITE READ 16
Write-After-Readconflict! • Conventional TM conflict detection • Insertions conflict often 5 WRITE Head 3 1 9 12 6 17 15 WRITE READ 16
But, both insertions OK even if we ignore WAR conflict • Relaxed conflict detection 5 Head 3 1 9 12 6 17 15 16
User-Defined Conflict Detection • Ignore write-after-read conflicts (Titos et al): atomic[!WAR]{ insert method body }
Linked List: Insert list_insert(list_t *listPtr, node_t *node) { atomic { *curr = listPtr->head; do { prev = curr; curr = curr->next; } while (curr != NULL && curr->key < node->key); node->next = curr; prev->next = node; } }
Linked List: Insert list_insert(list_t *listPtr, node_t *node) { atomic { *curr = listPtr->head; do { prev = curr; curr = curr->next; } while (curr != NULL && curr->key < node->key); node->next = curr; prev->next = node; assert(node is in the list && list is sorted); } } Strict conflict detection:Can reason about transaction code sequentially.
Linked List: Insert list_insert(list_t *listPtr, node_t *node) { atomic [!WAR]{ *curr = listPtr->head; do { prev = curr; curr = curr->next; } while (curr != NULL && curr->key < node->key); node->next = curr; prev->next = node; assert(node is in the list && list is sorted); } } • Ignore Write-After-Readconflicts: • Writes by others can occur between read phase and write phase • Lost ability to reasonsequentially 5 3 1 6 WRITE READ
Making !WAR block atomic list_insert(list_t *listPtr, node_t *node) { atomic [!WAR]{ *curr = listPtr->head; do { prev = curr; curr = curr->next; } while (curr != NULL && curr->key < node->key); node->next = curr; prev->next = node; assert(node is in the list && list is sorted); } } • Would like this action to be “right mover” • Can commute to the right of any actionby another thread
Right Mover commutates to the right of if ; goes to state S then ; goes to same state S. If is right-mover: ; ;
Making !WAR block atomic Ignored WAR conflict:currT1 = currT1->next; does not move to the right of nodeT2->next = curr; list_insert(list_t *listPtr, node_t *node) { atomic [!WAR]{ *curr = listPtr->head; do { prev = curr; currT1 = currT1->next; } while (curr != NULL && curr->key < node->key); node->next = curr; prev->next = node; assert(node is in the list && list is sorted); } } nodeT2->next = curr; Solution: Abstraction
Want to read 6 again! Abstraction intuition 5 5 5 5 ABSTRACT READ 6; WRITE 5 WRITE 5; ABSTRACT READ 6 WRITE 5; READ 5 Need to jump over 5. READ 6; WRITE 5 ABSTRACT READ: Read anything forward but do not pass the key. 3 3 3 3 1 1 1 1 6 6 6 6
Want to read 6 again! Abstraction intuition 5 5 5 5 curr= curr->next; with curr= curr->next*; but don’t go past key. ABSTRACT READ 6; WRITE 5 WRITE 5; ABSTRACT READ 6 WRITE 5; READ 5 Need to jump over 5. READ 6; WRITE 5 3 3 3 3 1 1 1 1 6 6 6 6
Abstraction Solution: Abstraction Replace currT1= currT1->next; with currT1 = currT1->next*; but don’t go past key. list_insert(list_t *listPtr, node_t *node) { atomic [!WAR]{ *curr = listPtr->head; do { prev = curr; currT1 = currT1->next*; } while (curr != NULL && curr->key < node->key); node->next = curr; prev->next = node; assert(node is in the list && list is sorted); } } • Now the block is atomic. • Can do sequential verification. • Use a sequential verification tool such as HAVOC, VCC…
1. Sequentially prove the original code list_insert(list_t *listPtr, node_t *node) { *curr = listPtr->head; do { prev = curr; curr = curr->next; } while (curr != NULL && curr->key < node->key); node->next = curr; prev->next = node; assert(node is in the list && list is sorted); } }
2. Apply the program transformation list_insert(list_t *listPtr, node_t *node) { *curr = listPtr->head; do { prev = curr; curr = curr->next*; } while (curr != NULL && curr->key < node->key); node->next = curr; prev->next = node; assert(node is in the list && list is sorted); } } • Do global readabstractions Abstract transaction becomes atomic .
3. Prove sequentially properties on abstract code list_insert(list_t *listPtr, node_t *node) { *curr = listPtr->head; do { prev = curr; curr = curr->next*; } while (curr != NULL && curr->key < node->key); node->next = curr; prev->next = node; assert(node is in the list && list is sorted); } } Finally: Soundness theorem says properties hold on original code, with !WAR ignored.
Other proofs • Labyrinth from STAMP. • StringBuffer pool. • Can apply to any program that has the pattern where: • a large portion of the shared data is read first • local computations is done and then • a small portion of shared data is updated
Conclusion • We provided a modeling and static verification method for programs using transactions with relaxed conflict detection which is: • tool-supported • HAVOC, VCC, any sequential verification tool supporting non-determinism • based on program abstraction • enables programmers to reason sequentially • Applied our method to Labyrinth and Genome benchmarks from STAMP suite.