Practical Object-Oriented Back-in-Time Debugging

543 views

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
543
On SlideShare
0
From Embeds
0
Number of Embeds
36
Actions
Shares
0
Downloads
9
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Practical Object-Oriented Back-in-Time Debugging

  1. 1. Practical Object-Oriented Back-in-Time Debugging Adrian Lienhard, Tudor Gîrba and Oscar Nierstrasz Software Composition Group University of Bern, Switzerland
  2. 2. Debugger call stack class Account { Money balance; void deposit(Money amount) { NullPointerException >> this.balance += money; } ... } ..................
  3. 3. Debugger call stack class Account { Money balance; void deposit(Money amount) { NullPointerException >> this.balance += money; } ... } class Company { void pay(Money money, Person person) { person.account().deposit(money); } } ... where does the account object come from?
  4. 4. Debugger call stack class Account { Money balance; void deposit(Money amount) { NullPointerException >> this.balance += money; } ... } class Company { void pay(Money money, Person person) { person.account().deposit(money); } } ... where does the return account object come from?
  5. 5. Debugger call stack class Account { Money balance; void deposit(Money amount) { NullPointerException >> this.balance += money; } ... } class Company { void pay(Money money, Person person) { person.account().deposit(money); } } ... where does the field read return account object come from?
  6. 6. Debugger call stack class Account { Money balance; void deposit(Money amount) { this.balance += money; } ... } class Person { class Company { void createAccount(Bank bank) { void pay(Money money, Person perso this.account = bank.openAccount(); person.account().deposit(money); } } } } ... where doe return field write field read return account o come from
  7. 7. class Acc Money b void de this. } ... } class Bank { class Person { class Com Account openAccount() { void createAccount(Bank bank) { void pa return new Account(); this.account = bank.openAccount(); perso } } } } } } ... allocation return field write field read
  8. 8. Debugger call stack class Account { Money balance; void deposit(Money amount) { NullPointerException >> this.balance += money; } ... } class Bank { class Person { class Company { Account openAccount() { void createAccount(Bank bank) { void pay(Money money, Person person) { return new Account(); this.account = bank.openAccount(); person.account().deposit(money); } } } } } } ... where does the allocation return field write field read return account object come from? In 50% of the cases the execution stack contains essentially no information about the bug’s cause. [Liblit PLDI’05]
  9. 9. class Bank { class Person { class Company { Account openAccount() { void createAccount(Bank bank) { void pay(Money money, Person person) { return new Account(); this.account = bank.openAccount(); person.account().deposit(money); } } } } } } ... where does the allocation return field write field read return account object come from? History recorded by a back-in-time debugger t Challenges: amount of data execution overhead
  10. 10. Approaches Omniscient Trace-oriented Trace-oriented Debugger1 debugger2 (partial) debugger2 (full) + limited memory usage – requires extensive hardware resources – loss of old history – loss of history + complete history – overhead 100x + overhead 10x – overhead 100x 1) Lewis AADEBUG’03 2) Pothier etal. OOPSLA’07
  11. 11. Approaches Omniscient Trace-oriented Trace-oriented Debugger1 debugger2 (partial) debugger2 (full) st o f all? Be dm emor y + limite erhead v + low o histor y te + co mple + limited memory usage – requires extensive hardware resources – loss of old history – loss of history + complete history – overhead 100x + overhead 10x – overhead 100x 1) Lewis AADEBUG’03 2) Pothier etal. OOPSLA’07
  12. 12. Approaches Omniscient Trace-oriented Trace-oriented Debugger1 debugger2 (partial) debugger2 (full) st o f all? Be emor y ited m ead + lim overh + low istory e vant h + rel + limited memory usage – requires extensive hardware resources – loss of old history – loss of history + complete history – overhead 100x + overhead 10x – overhead 100x 1) Lewis AADEBUG’03 2) Pothier etal. OOPSLA’07
  13. 13. At runtime delete history when it gets irrelevant Relevant questions: How was this object passed here? What were the previous values of a field and where (call stack) were they assigned? Only history of live objects needed! Efficient mechanism required to identify irrelevant datapoints at runtime
  14. 14. How we can do it VM that models history as first-class objects Keep history together with regular objects in memory Use GC to efficiently delete no longer needed history
  15. 15. First-class references Typical model: object Object Flow VM: references are references as direct pointers represented as alias objects regular objects alias header header header header field_1 field_1 header ... value field_2 field_2 ... context .... .... field_n pointer field_n origin predecessor ...
  16. 16. Object Flow VM model caller 0..1 MethodInvocation * context 1 target parameter field or array * 1 element Value Alias value *
  17. 17. Object Flow VM model caller 0..1 MethodInvocation * context 1 target parameter field or array * 1 element predecessor Value Alias value * 0..1 0..1 * 0..1 origin
  18. 18. Historical object state account = new Account() t1 balance value :Account init@t1 null
  19. 19. Historical object state account = new Account() t1 ... account.balance = 17 t2 value init@t1 null predecessor balance value :Account field-write@t2 17
  20. 20. Historical object state account = new Account() t1 ... account.balance = 17 t2 ... account.balance = 42 t3 value init@t1 null predecessor value field-write@t2 17 predecessor balance value :Account field-write@t3 42
  21. 21. Object Flow allocation class Person { return field write field read field read parameter return void printOn(Stream stream) { stream.print(this.account); } } return field-write field-read field-read return parameter allocation active invocation Legend running/completed method invocation alias alias origin
  22. 22. Effect of GC snapshot 1 active invocation garbage collection snapshot 2 Legend running/completed method invocation alias alias origin
  23. 23. Evaluation memory usage (1) 2.5e+09 1e+07 Number of aliases allocated (left Y-axis) Number of aliases in memory (right Y-axis) Number of objects in memory (right Y-axis) 2e+09 8e+06 1.5e+09 6e+06 1e+09 4e+06 5e+08 2e+06 0 0 0 200 400 600 800 1000 #classes
  24. 24. Evaluation memory usage (2) 7e+06 50 Number of aliases allocated Number of aliases in memory 6e+06 Number of objects in memory Ratio between aliases in 40 memory and allocated 5e+06 30 4e+06 % 3e+06 20 2e+06 10 1e+06 0 0 0 2 4 6 8 10 12 14 16 18 #samples
  25. 25. Evaluation memory usage (3) 1e+07 Number of aliases allocated 9e+06 Number of aliases in memory Number of objects in memory 8e+06 7e+06 6e+06 5e+06 4e+06 3e+06 2e+06 1e+06 0 5 10 15 20 25 #requests
  26. 26. Evaluation run-time overhead Overhead GC Recording off 1.15 1.6% Recording on 3.84 27.6% Average over 6 standard Smalltalk benchmarks Largest overhead: 6.91
  27. 27. Conclusion ✔ Retains important history – even if old ✔ Memory consumption limited in the best case, slowly growing in the worst case ✔ Relative low run-time overhead ✖ Missing control flow dependencies

×