Time Travel Debugging (in Python)

This video introduces the time traveling debugging for Python I've been working up to today. It show what it's like to code using time traveling debugging, how my implementation works, as well as a proof of concept debugging UI called the zoom debugger. The time traveling debugger project can be found at: https://github.com/airportyh/time-traveling-debugger .

The following transcript was automatically generated by an algorithm.

  • 00:00 : let me show you how time travel
  • 00:01 : debugging works
  • 00:03 : let's say you get a weird error like
  • 00:04 : this one
  • 00:07 : what you can do now is go back to the
  • 00:09 : point in time when this error happened
  • 00:11 : and look at the state of the program
  • 00:14 : x not in list what is in the list
  • 00:18 : oh right we have this bracket
  • 00:22 : so zero is not going to be in the list
  • 00:26 : oh what i probably meant to do is remove
  • 00:28 : the item at index zero
  • 00:31 : not remove the item zero it gets better
  • 00:35 : you can also rewind and replay the
  • 00:37 : events leading up to the error
  • 00:41 : assertion error okay let's step
  • 00:44 : backwards into the function call the
  • 00:47 : return value is zero
  • 00:50 : uh we're expecting it to be negative 42.
  • 00:53 : stepping backwards so char
  • 00:57 : is the negative sign which is
  • 01:00 : clearly not a digit oh right i never
  • 01:03 : implemented logic that handles negative
  • 01:06 : numbers
  • 01:07 : oops so let's set up a sine variable
  • 01:11 : and we're gonna set it to either
  • 01:13 : negative one
  • 01:14 : or one depending if we get a negative
  • 01:17 : sign
  • 01:18 : let's go still know
  • 01:23 : what's going on stepping backwards
  • 01:26 : uh looks like we have set up the sign
  • 01:28 : correctly
  • 01:29 : oh okay you just forgot to multiply the
  • 01:32 : sign into the result
  • 01:34 : duh what you're seeing
  • 01:37 : is a time traveling debugger prototype
  • 01:39 : for python programs
  • 01:41 : how does it work well first to run your
  • 01:44 : program
  • 01:44 : instead of using the standard python 3
  • 01:47 : executable
  • 01:48 : you use pi rewind a customized version
  • 01:51 : of python 3.
  • 01:52 : pi rewind creates a log file which
  • 01:55 : leaves a trail of everything that
  • 01:56 : happened during the running of the
  • 01:58 : program
  • 01:58 : such as function calls variable
  • 02:00 : assignments and updates to data
  • 02:02 : structures such as
  • 02:03 : lists and dictionaries then the recreate
  • 02:07 : program reads back the log file
  • 02:08 : line by line and recreates every
  • 02:11 : historical state of the program
  • 02:13 : and saves them into a sql lite database
  • 02:16 : we call this database file the history
  • 02:18 : file
  • 02:19 : and it can be used to drive a debugger
  • 02:21 : front end such as this one
  • 02:24 : on the surface this looks like a normal
  • 02:26 : step debugger but
  • 02:27 : it's not executing the code line by line
  • 02:30 : but rather it's just navigating the data
  • 02:32 : in the history file
  • 02:33 : because of that it has the ability to
  • 02:35 : step backwards in time
  • 02:40 : the fact that you have access to every
  • 02:42 : point in time in history
  • 02:44 : gives rise to some interesting
  • 02:45 : possibilities one possibility
  • 02:48 : is you can use database queries to
  • 02:50 : answer questions about what your program
  • 02:52 : did
  • 02:54 : another possibility is you can
  • 02:55 : re-imagine what a debugger's user
  • 02:57 : interface can be
  • 02:59 : this is a debugger front-end called the
  • 03:01 : zoom debugger
  • 03:03 : it was inspired by the mandelbrot set
  • 03:05 : and google earth
  • 03:06 : within it you can look at a program's
  • 03:08 : execution from different levels of
  • 03:10 : elevation
  • 03:12 : the top level is the module the entry
  • 03:14 : point of every python program
  • 03:22 : we have a hero and we have two enemies
  • 03:26 : the goblin and the wizard there's a
  • 03:29 : battle engine
  • 03:30 : a shopping engine and then it's looping
  • 03:34 : through the
  • 03:34 : enemies the goblin is the first enemy
  • 03:38 : and looks like a battle happened here
  • 03:41 : and the aftermath hero has health 8
  • 03:44 : after the battle
  • 03:46 : goblin has held negative four
  • 03:50 : down from six over here
  • 03:54 : and we did some shopping after the
  • 03:57 : battle
  • 03:58 : and then we do the second battle with
  • 04:00 : the wizard
  • 04:02 : uh we beat the wizard too
  • 04:05 : and then we did some more shopping at
  • 04:07 : the end
  • 04:09 : and we won all right let's zoom into the
  • 04:11 : first battle
  • 04:14 : okay so hiro attacks the enemy
  • 04:18 : uh the goblin and the goblins health was
  • 04:21 : down to
  • 04:22 : one after just one single attack
  • 04:26 : how is that determined let's go in
  • 04:30 : so to attack an enemy we have to first
  • 04:33 : ask the enemy to receive the damage
  • 04:37 : interesting uh here we're asking them to
  • 04:40 : receive
  • 04:41 : self that power self is the hero
  • 04:44 : and hero's power is five okay so let's
  • 04:47 : go in again
  • 04:49 : so now we're inside the receive damage
  • 04:52 : method of the goblin
  • 04:53 : and we're just going to subtract the
  • 04:56 : points
  • 04:57 : from our health so since we started with
  • 05:00 : a held of
  • 05:01 : six now we're down to one
  • 05:04 : that makes sense imagine if you could
  • 05:07 : see a visualization like this while
  • 05:09 : working with
  • 05:10 : or reviewing a new piece of code you
  • 05:12 : haven't seen before
  • 05:13 : the prototype you saw is pi rewind and
  • 05:16 : is a part of the time traveling debugger
  • 05:18 : project which you can find here
  • 05:20 : the concept of time travel debugging is
  • 05:23 : an active area
  • 05:24 : of research there are active projects
  • 05:26 : commercial products as well as research
  • 05:29 : papers in this area
  • 05:31 : links to these can be found on the
  • 05:32 : project page as well
  • 05:34 : if you like to experience what it's like
  • 05:36 : to code with time travel debugging
  • 05:38 : try using pi rewind to solve a code
  • 05:41 : challenge on lead code or a similar site

Time-Travel Debugging Production Code

Loren

Loren Sands-Ramshaw

Developer Relations Engineer

In this post, I’ll give an overview of time-travel debugging (what it is, its history, how it’s implemented) and show how it relates to debugging your production code.

Normally, when we use debuggers, we set a breakpoint on a line of code, we run our code, execution pauses on our breakpoint, we look at values of variables and maybe the call stack, and then we manually step forward through our code’s execution. In time-travel debugging , also known as reverse debugging , we can step backward as well as forward. This is powerful because debugging is an exercise in figuring out what happened: traditional debuggers are good at telling you what your program is doing right now, whereas time-travel debuggers let you see what happened. You can wind back to any line of code that executed and see the full program state at any point in your program’s history.

History and current state

It all started with Smalltalk-76, developed in 1976 at Xerox PARC . ( Everything started at PARC 😄.) It had the ability to retrospectively inspect checkpointed places in execution. Around 1980, MIT added a “retrograde motion” command to its DDT debugger , which gave a limited ability to move backward through execution. In a 1995 paper, MIT researchers released ZStep 95, the first true reverse debugger, which recorded all operations as they were performed and supported stepping backward, reverting the system to the previous state. However, it was a research tool and not widely adopted outside academia.

ODB, the Omniscient Debugger , was a Java reverse debugger that was introduced in 2003, marking the first instance of time-travel debugging in a widely used programming language. GDB (perhaps the most well-known command-line debugger, used mostly with C/C++) added it in 2009.

Now, time-travel debugging is available for many languages, platforms, and IDEs, including:

  • Replay for JavaScript in Chrome, Firefox, and Node, and Wallaby for tests in Node
  • WinDbg for Windows applications
  • rr for C, C++, Rust, Go, and others on Linux
  • Undo for C, C++, Java, Kotlin, Rust, and Go on Linux
  • Various extensions (often rr- or Undo-based) for Visual Studio, VS Code, JetBrains IDEs, Emacs, etc.

Implementation techniques

There are three main approaches to implementing time-travel debugging:

  • Record & Replay : Record all non-deterministic inputs to a program during its execution. Then, during the debug phase, the program can be deterministically replayed using the recorded inputs in order to reconstruct any prior state.
  • Snapshotting : Periodically take snapshots of a program’s entire state. During debugging, the program can be rolled back to these saved states. This method can be memory-intensive because it involves storing the entire state of the program at multiple points in time.
  • Instrumentation : Add extra code to the program that logs changes in its state. This extra code allows the debugger to step the program backwards by reverting changes. However, this approach can significantly slow down the program’s execution.

rr uses the first (the rr name stands for Record and Replay), as does Replay . WinDbg uses the first two, and Undo uses all three (see how it differs from rr ).

Time-traveling in production

Traditionally, running a debugger in prod doesn’t make much sense. Sure, we could SSH into a prod machine and start the process handling requests with a debugger and a breakpoint, but once we hit the breakpoint, we’re delaying responses to all current requests and unable to respond to new requests. Also, debugging non-trivial issues is an iterative process: we get a clue, we keep looking and find more clues; discovery of each clue is typically rerunning the program and reproducing the failure. So, instead of debugging in production, what we do is replicate on our dev machine whatever issue we’re investigating and use a debugger locally (or, more often, add log statements 😄), and re-run as many times as required to figure it out. Replicating takes time (and in some cases a lot of time, and in some cases infinite time), so it would be really useful if we didn’t have to.

While running traditional debuggers doesn’t make sense, time-travel debuggers can record a process execution on one machine and replay it on another machine. So we can record (or snapshot or instrument) production and replay it on our dev machine for debugging (depending on the tool, our machine may need to have the same CPU instruction set as prod). However, the recording step generally doesn’t make sense to use in prod given the high amount of overhead—if we set up recording and then have to use ten times as many servers to handle the same load, whoever pays our AWS bill will not be happy 😁.

But there are a couple scenarios in which it does make sense:

  • Undo only slows down execution 2–5x , so while we don’t want to leave it on just in case, we can turn it on temporarily on a subset of prod processes for hard-to-repro bugs until we have captured the bug happening, and then we turn it off.
  • When we’re already recording the execution of a program in the normal course of operation.

The rest of this post is about #2, which is a way of running programs called durable execution .

Durable execution

What’s that.

First, a brief backstory. After Amazon (one of the first large adopters of microservices) decided that using message queues to communicate between services was not the way to go (hear the story first-hand here ), they started using orchestration. And once they realized defining orchestration logic in YAML/JSON wasn’t a good developer experience, they created AWS Simple Workfow Service to define logic in code. This technique of backing code by an orchestration engine is called durable execution, and it spread to Azure Durable Functions , Cadence (used at Uber for > 1,000 services ), and Temporal (used by Stripe, Netflix, Datadog, Snap, Coinbase, and many more).

Durable execution runs code durably—recording each step in a database, so that when anything fails, it can be retried from the same step. The machine running the function can even lose power before it gets to line 10, and another process is guaranteed to pick up executing at line 10, with all variables and threads intact.[^1] It does this with a form of record & replay: all input from the outside is recorded, so when the second process picks up the partially-executed function, it can replay the code (in a side-effect–free manner) with the recorded input in order to get the code into the right state by line 10.

Durable execution’s flavor of record & replay doesn’t use high-overhead methods like software JIT binary translation , snapshotting, or instrumentation. It also doesn’t require special hardware. It does require one constraint: durable code must be deterministic (i.e., given the same input, it must take the same code path). So it can’t do things that might have different results at different times, like use the network or disk. However, it can call other functions that are run normally ( “volatile functions” , as we like to call them 😄), and while each step of those functions isn’t persisted, the functions are automatically retried on transient failures (like a service being down).

Only the steps that require interacting with the outside world (like calling a volatile function, or calling sleep('30 days') , which stores a timer in the database) are persisted. Their results are also persisted, so that when you replay the durable function that died on line 10, if it previously called the volatile function on line 5 that returned “foo”, during replay, “foo” will immediately be returned (instead of the volatile function getting called again). While yes, it adds latency to be saving things to the database, Temporal supports extremely high throughput (tested up to a million recorded steps per second). And in addition to function recoverability and automatic retries, it comes with many more benefits , including extraordinary visibility into and debuggability of production.

Debugging prod

With durable execution, we can read through the steps that every single durable function took in production. We can also download the execution’s history, checkout the version of the code that’s running in prod, and pass the file to a replayer (Temporal has runtimes for Go, Java, JavaScript, Python, .NET, and PHP) so we can see in a debugger exactly what the code did during that production function execution. Read this post or watch this video to see an example in VS Code.[^2]

Being able to debug any past production code is a huge step up from the other option (finding a bug, trying to repro locally, failing, turning on Undo recording in prod until it happens again, turning it off, then debugging locally). It’s also a (sometimes necessary) step up from distributed tracing.

💬 Discuss on Hacker News , Reddit , Twitter , or LinkedIn .

I hope you found this post interesting! If you’d like to learn more about durable execution, I recommend reading:

  • Building reliable distributed systems
  • How durable execution works

and watching:

  • Introduction to Temporal
  • Why durable execution changes everything

Thanks to Greg Law, Jason Laster, Chad Retz, and Fitz for reviewing drafts of this post.

[^1]: Technically, it doesn’t have line-by-line granularity. It only records certain steps that the code takes—read on for more info ☺️. [^2]: The astute reader may note that our extension uses the default VS Code debugger, which doesn’t have a back button 😄. I transitioned from talking about TTD to methods of debugging production code via recording, so while Temporal doesn’t have TTD yet, it does record all the non-deterministic inputs to the program and is able to replay execution, so it’s definitely possible to implement. Upvote this issue or comment if you have thoughts on implementation!

Help shaping the future of The Debugging Book and take part in our 2024 reader survey!

Project: Time Travel Debugger ¶

In this project you will build your own Time Travel Debugger for Python. Please read the Chapter on Debuggers beforehand, notably Exercise 1.

Update[26.11.2020] : the project description was amended to include answers to most of the student's questions. Clarifications are highlighted with blue color. Changes/additions are highlighted with red color.

A time travel debugger records a log of the process execution (including call stack and values of all variables at each step), so that it is possible to run it later with both forward and backward commands. The interactive session does not execute the code statements, but just replays all actions taken from the recorded execution. A time travel debugger can restore a full snapshot of each program state at any point in time and either continue the execution from then on, or run the program backward. As normal execution changes values of variables along the run, the backward execution reverts variables to the previous values and "un-executes" functions.

The project can be approached in two ways: either as a single-person project or a pair project. The single-person project comprises the implementation of a command line interface, whereas the pair project requires the implementation of a graphical user interface.

To be successful, you must obtain at least 15 points by implementing features listed in "Must-have Requirements"; otherwise, you will not be awarded any points for the project.

To fully enjoy coding (and get maximum points) feel free to additionally implement some (or all) features from the "May-Have Requirements".

Submission details ¶

The deadline for this project is on the 18th of December, 2020 at 11:59pm CET All files packaged in a zip archive must be uploaded via the CMS system. The project should be a self-contained bundle with the TimeTravelDebugger.ipynb Jupyter notebook and supplementary files.

General Requirements ¶

The project should be implemented in a Jupyter notebook with a step-by-step explanation of the implemented features (like the notebooks from the lecture). The notebook should also include a "Presentation" section containing demo interactions which show how to use each feature.

Your project should come with a working environment via either virtualenv ( requirements.txt file) or pipenv ( Pipfile.lock file) tools.

Your code should follow PEP 8 style conventions. You can use %%pycodestyle command from the pycodestyle package to check files for PEP 8 compliance.

The time travel debugger should be implemented as a class that can be executed as follows:

where foo(args) can be an arbitrary function under debugging, implemented either in the same notebook or imported from another file. Do not let the debugger escape the context and also debug commands outside the with block (e.g., methods of the Jupyter framework).

Part 1: Command-Line Debugger ¶

If you work as a single-person , this is the part you will have to build.

The implementation should include an interactive command line interface like the one presented in the Chapter on Debugging . Make use of the Debugger class, notably its execute() infrastructure, to easily tie commands to methods.

Must-Have Requirements (20 Points) ¶

Your time travel debugger should support the following features:

Basics ¶

/R1/ quit Exit the interactive session (or resume execution until function return)

/R2/ help Prints all available commands and their description and arguments

/R3/ Missing or bad arguments should result in specific error messages.

Navigation Commands ¶

After each navigation command, the current line should be printed.

/R4/ step Step to the next executed line. Execute a program until it reaches the next executable statement. If the current line has a list comprehension statement, it should step into it, but remain at the current line (do not show <listcomp> source). If the current source line includes a function call, step into the called function and stop at the beginning of this function.

/R5/ backstep Step to the previous executed line. Execute a program until it reaches the previous executable statement. If the current line has a list comprehension statement, it should step into it, but remain at the current line. If the current source line includes a function call, step into the called function and stop at the last statement invoked in this function (usually a return statement)

/R6/ next Step over function calls going to the next line. Execute a program until it reaches the next source line. Any function calls (and list comprehension) in the current line should be executed without stopping. Starting from the last line of a function, this command should take you to its call site.

/R7/ previous Step over function calls going to the previous line. Execute a program until it reaches the previous source line. If the line contains a function call, it should be “un-executed” restoring previous values of global variables. Starting from the first line of a function, previous should take you back to the caller of that function, before the function was called. Hint: The difference between step and next is that step will go inside a called function, while next stops at the next line of the current function.

/R8/ finish Execute until return. Takes you forward to the point where the current function returns. If finish is executed at the last line of a function, it should stay at that line and print it again.

/R9/ start Execute backwards until a function start. Takes you backwards to the first instruction of the function. If start is executed at the first line of a function, it should stay at that line and print it again.

/R10/ Execute forwards until a certain point:

  • /R100/ until <line_number> Resume execution until a line greater than <line_number> is reached. If <line_number> is not given, resume execution until a line greater than the current is reached. This is useful to avoid stepping through multiple loop iterations. If 'line_number' is not given and the execution jumps to another function, act as next
  • /R101/ until <filename>:<line_number> Execute a program forward until it reaches the line with the number <line_number> in the file <filename> .
  • /R102/ until <function_name> Execute a program forward until it reaches the line with a call to the function named <function_name> declared in the current file.
  • /R103/ until <filename>:<function_name> Execute a program forward until it reaches the line with a call to the function named <function_name> declared in the file <filename> .
  • Expl: If the execution is already at the specified line/function, it should look for the next occurrence or run till the end.

/R11/ Execute backwards until a certain point:

  • /R110/ backuntil <line_number> Resume execution backwards until a line lower than <line_number> in the current file is reached. If <line_number> is not given, resume execution backwards until a line lower than the current is reached. If 'line_number' is not given and the execution jumps to another function, act as previous
  • /R111/ backuntil <filename>:<line_number> Execute a program backward until it reaches the line with the number <line_number> in the <filename> .
  • /R112/ backuntil <function_name> Execute a program backward until it reaches the line with a call to the function named <function_name> declared in the current file.
  • /R113/ backuntil <filename>:<function_name> Execute a program backward until it reaches the line with a call to the function named <function_name> declared in the <filename> .
  • Expl: If the execution is already at the specified line/function, it should look for the next occurrence or run till the start.

/R12/ continue Continue execution forward until a breakpoint is hit, or the program finishes.

/R13/ reverse Continue execution backward until a breakpoint is hit, or the program starts.

  • Hint: Ignore the command if the debugger reaches start/end of the execution and cannot go further. (Optionally: print an appropriate message.)

Call Stack ¶

/R14/ Print call stack:

  • /R141/ where Print the whole call stack
  • /R142/ where <number> Print the <number> of leading and trailing lines from the call stack surrounding the current frame if any.

/R15/ Navigate the call stack

  • up and down Move up (and down) the call stack towards callers (and callees): print the code of the previous (next) frame and mark the currently executed line.

Inspecting Code and Variables ¶

  • /R161/ list Print 2 lines before and 2 lines after the current line
  • /R162/ list <number> Print <number> lines before and <number> lines after the current line
  • /R163/ list <above> <below> Print <above> lines before and <below> lines after the current line
  • Expl: Lines are limited to the current function body

/R17/ Inspect the value of a variable

  • /R171/ print Print values of all local variables (including values of member variables)
  • /R172/ print <var_name> Print the value of a variable with name <var_name> . If the variable <var_name> is not defined, print an error message.

/R18/ print <expr>

  • Like print <var_name> , but allow for arbitrary Python expressions
  • The code expression should be evaluated in the current environment of the code being debugged.
  • Keep in mind that this requires to evaluate the expression during the interactive session, which may produce exceptions.

Watchpoints ¶

  • /R190/ watch <var_name> Creates a numbered watchpoint for the given variable: If its value changes after a navigation command, its value should be printed.
  • /R191/ watch Show all watchpoints and associated variables.
  • /R192/ unwatch <watch_id> Remove a watchpoint.

Breakpoints ¶

  • /R201/ break <line_number> Create a numbered breakpoint at line with number <line_number>
  • /R202/ break <function_name> Set a breakpoint which hits when a function with the name <function_name> is called (or returned in case of backward execution). The execution should stop at the beginning (or the end) of the function.
  • /R203/ break <file_name>:<function_name> Set a breakpoint which hits when a function with the name <function_name> in file <file_name> is called (or returned in case of backward execution). The execution should stop at the beginning (or the end) of the function.
  • /R204/ breakpoints Display all available breakpoints Depending on the type of the breakpoint the output can be the following: breakpoint_id line file_name:line_number is_active breakpoint_id func file_name:func_name is_active breakpoint_id cond file_name:line_number is_active cond_expression
  • /R205/ delete <breakpoint_id> Delete a breakpoint with the index <breakpoint_id> from the list of breakpoints
  • /R206/ disable <breakpoint_id> Suspend a breakpoint with the index <breakpoint_id> from the list of breakpoints
  • /R207/ enable <breakpoint_id> Re-enable a breakpoint with the index <breakpoint_id> from the list of breakpoints
  • /R208/ cond <line> <condition> . Conditional breakpoints. Set a breakpoint at which the execution is stopped at line <line> if a condition <condition> is true. A condition can include local variables (e.g., tag == "b" or tag.startswith(b) ), but not function calls from a debugged program.
  • Hint: keep in mind that breakpoints may be set in different modules (files) and sometimes cannot be set (e.g., in for comment lines).
  • , continue, etc.)

May-Have Requirements (10 Points) ¶

Fulfilling these additional requirements gains extra points.

Extended Watchpoints ¶

  • watch <expression> Like watch <variable> , but allow for arbitrary expressions.

Extended Breakpoints ¶

  • cond <line> <expression_code> Conditional-breakpoints with complex expressions (see conditional-breakpoints from Must-haves and expression )
  • bpafter <breakpoint_id> <line_number> Disable a breakpoint after hitting another specified breakpoint
  • bpuntil <breakpoint_id> <line_number> Disable a breakpoint until hitting another specified breakpoint
  • Step into my code: inspect function calls only if they are defined in modules located in the current folder
  • Inspect members of complex objects
  • bpwrite <variable_name> Write access breakpoints A breakpoint hits each time a certain variable <variable_name> is changed
  • alias <breakpoint_id> <breakpoint_name> Create aliases for breakpoints (refer to a breakpoint by name instead of an index) The 'breakpoints' command should then output breakpoint names instead of breakpoint ids when available
  • Support for inline breakpoints (e.g., for lambda functions, list comprehension) if a line contains multiple statements such as filter(lambda x: x % 2 == 0, [x**2 for x in range(10)])

More Features ¶

  • Watch I/O interaction
  • Stand-alone command line debugger, which can be used outside Jupyter notebooks
  • Some other cool feature of your own design

Assessing Requirements ¶

Your command line debugger will be evaluated by well-documented functionality as listed above.

A "well-documented" functionality has readable code whose effect is illustrated by at least one example in the notebook.

The functionality itself will be validated by a set of tests consisting of a series of commands with expected results. Here is an example of how to run your debugger with predefined commands; you can also use this in your notebook to demonstrate features.

Example Interaction ¶

In this section, we give you some sample interactions.

Part 2: GUI-Based Debugger ¶

If you work as a team of two , this is the part you will also have to build.

To create a GUI in Jupyter notebooks, one can follow two paths:

  • Use embeddings of plain HTML/JS into the notebook (see Exercise 3 in the chapter on interactive debuggers . This has the advantage of not requiring Python in the final result; your time travel debugger can execute in any browser. You may follow this path if you already have experience with Web design and programming.
  • Use Jupyter widgets to create a user interface. This has the advantage that you can use Python all along the way. Your debugger, however, can only be run in the notebook; not in, say, a Web page.

Your GUI-based time travel debugger should implement similar features as the command line debugger, but its functionality should be accessible via a graphical user interface (instead of typing in the commands).

For instance, a user may be able to step backward by clicking a ◀ button, or set a breakpoint by clicking on a line in the code view.

The "Presentation" section should include a video/YouTube (up to 1 min each) embedded in Jupyter Notebook, which shows a demo of each implemented feature.

Must-Have Requirements (20 Points): ¶

Note that your GUI need not implement all features of your command-line debugger; ease of use and discoverability have priority. Choose wisely!

The GUI-based debugger should allow inspecting and navigating through

  • /R31/ The source code currently being executed, where the current line and breakpoints are highlighted.
  • /R32/ Users should be able to scroll through the code of the current module.
  • /R33/ Variables.
  • /R34/ The list of watchpoints (if any).
  • /R35/ The call stack.
  • /R36/ The list of breakpoints (if any).

The debugger should provide the following controls:

  • /R37/ An interactive timeline (e.g., a slider) which allows moving along the execution back and forth.
  • /R38/ Automatic execution replay (forward and backward) at various speed
  • /R39/ Search for specific events in the timeline (a breakpoint hit, a variable changed etc.)
  • /R40/ Search results should be selectable by the user, moving the timeline to the associated event

Here is a demo of how a basic GUI may look like:

May-Have Requirements (10 Points): ¶

  • Syntax-highlight the source code
  • Show values of the variables in the source code.
  • Show events (e.g., breakpoints) on the timeline.
  • Visualize and explore data structures.
  • Produce an interactive session which can be run uniquely with HTML + JavaScript, such that Python is not required (excludes the evaluation of expressions) (worth up to 10 points).
  • Implement the debugger as a custom Jupyter widget (worth up to 10 points).
  • Some other cool feature of your design.

Your interactive debugger will be evaluated for well-documented and discoverable functionality as listed above.

A "well-documented" functionality has readable code whose effect is described in the notebook (possibly with examples).

A "discoverable" functionality can be found quickly by ordinary users by exploring the GUI. Extra functionality (keyboard shortcuts, etc.) should be made available as part of a help screen or as a tutorial in your notebook.

The functionality itself will be validated manually by test users.

Example Notebook Structure ¶

Personal information ¶.

Start with these fields:

As an example:

Implementation ¶

Feature /R17/:

/R171/: A print command that prints all variables of the current frame.

Presentation ¶

/R171/: A print command allows printing all variables of the current frame.

The command sequence "step", "step", "step", "print" should print three variables:

The command sequence "step", "step", "print" should print just two variables:

Summary ¶

Creative Commons License

How to Cite this Work

Andreas Zeller: " Project: Time Travel Debugger ". In Andreas Zeller, " The Debugging Book ", https://www.debuggingbook.org/beta/html/Time_Travel_Debugger.html . Retrieved 2023-11-11 18:05:06+01:00.

The Practice of Cloud System Administration

Awesome Conferences

  • Mar 3-4, 2020: DevOpsDays New York City, NYC, NY, USA
  • Dec 7-9, 2020: Usenix SREcon20 Americas, Virtual

Introducing the Python Time Travel Debugger

Today I'm open sourcing a productivity tool that I've been very excited about: A time-travel extension to the Python Debugger (PDB).

Have you ever been using PDB to step through a program and suddenly realize you wish you could jump back in time and know what a variable used to contain?

This version of PDB adds the ability to jump back in time to the state of your program as it was in the past. You can examine variables and even continue execution from that point forward (though that is dangerous because it may harm the time space continuum.)

How it works:

As you know, time is the 4th dimension. Every moment is another universe. Pretty trippy, eh?

TTPDB simply records a pointer to the current universe before displaying the input prompt. As you step through your program, each step records a pointer to the past universes. The last 100 pointers are remembered. You can jump into any of those universes. Once in those universes you can examine variables. Heck you can do anything you want because you are really in that universe.

Once you are done with that universe you can "pop up" back to the universe you left thanks to our time portal technology.

I've released the source code. You can find it on Github:

https://github.com/TomOnTime/timetravelpdb

--Tom Limoncelli

Posted by Tom Limoncelli in Python

  • Comments (6)
  • | Trackbacks (0)

No TrackBacks

TrackBack URL: https://everythingsysadmin.com/cgi-bin/mt-tb.cgi/1737

6 Comments | Leave a comment

This is awesome. I can't wait to have something similar in the Perl debugger!

Hey, this is actually pretty cool! Totally planning on messing with this more later.

I'm just gonna leave this here though, for anyone else who might need it ...

kill -SIGQUIT `ps -ef | grep "python2 -m timetravelpdb" | awk '{print $2}'`

(Thanks to http://oracleflash.com/20/How-to-kill-all-processes-with-one-command-in-Linux.html )

(Be a bit careful with that command by the way.)

Hi, have you seen the Python Omniscient Debugger ?

https://github.com/rodsenra/pode

I guess this uses copy on write underneath ? Does it use a lot of RAM, what are the implications for having many more than 100 runs ?

Ability to jump back is very helpful feature of Python Debugger

Leave a comment

Best of blog.

  • Assessing Progress with "DevOps Look-for's"
  • So your management fails at IT, huh?
  • 4 unix commands I abuse every day
  • a list of dumb things to check
  • April showers bring May Flowers... but May brings...
  • The right answer
  • Tips for Technical Resumes
  • Ordering Information
  • Articles by the authors
  • Time Management Wiki
  • TPOSANA Wiki
  • Privacy Policy

Recent Entries

  • Article: "Split Your Overwhelmed Teams"
  • Usenix LISA is no more. Here's my retrospective.
  • 20 years of The Practice of System and Network Administration!
  • Hear Tom on The Software Engineering Daily Podcast
  • Updated BP Texas City Animation
  • What to give your loved one for April Fools Day?
  • Thu, Nov 19 NYCDEVOPS meetup: John Allspaw on "Learning From Incidents"
  • Oct 15 NYC DevOps Meetup: "Introduction to Site Reliability Engineering" by Nathen Harvey
  • Adarsh Shah on "Continuous Delivery for Machine Learning" (September NYCDEVOPS Meetup)

Search blog entries:

  • November 2022
  • October 2021
  • November 2020
  • October 2020
  • September 2020
  • August 2020
  • February 2020
  • December 2019
  • October 2019
  • More Archives

Syndicate this site (XML)

  • Powered by: Movable Type 8.0.2
  • Bandwidth by: DataBasement.org
  • Site design by: Mihai Bocsaru
  • Movable Type development by: PRO IT Service
  • Movable Type upgrade by: MovableTypeUpgrade.com

Creative Commons License

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Time Travel Debugging - Overview

  • 1 contributor

Time travel debugging logo featuring a clock.

What is Time Travel Debugging?

Time Travel Debugging is a tool that allows you to capture a trace of your process as it executes and then replay it later both forwards and backwards. Time Travel Debugging (TTD) can help you debug issues easier by letting you "rewind" your debugger session, instead of having to reproduce the issue until you find the bug.

TTD allows you to go back in time to better understand the conditions that lead up to the bug and replay it multiple times to learn how best to fix the problem.

TTD can have advantages over crash dump files, which often miss the state and execution path that led to the ultimate failure.

In the event you can't figure out the issue yourself, you can share the trace with a coworker and they can look at exactly what you're looking at. This can allow for easier collaboration than live debugging, as the recorded instructions are the same, whereas the address locations and code execution will differ on different PCs. You can also share a specific point in time to help your coworker figure out where to start.

TTD is efficient and works to add as little as possible overhead as it captures code execution in trace files.

TTD includes a set of debugger data model objects to allow you to query the trace using LINQ. For example, you can use TTD objects to locate when a specific code module was loaded or locate all of the exceptions.

Screenshot of WinDbg with Time Travel Debugging command and three timelines.

Requirements

Time Travel Debugging is integrated with WinDbg , providing seamless recording and replay experience.

To use TTD, you need to run the debugger elevated. Install WinDbg using an account that has administrator privileges and use that account when recording in the debugger. In order to run the debugger elevated, select and hold (or right-click) the WinDbg icon in the Start menu, and then select More > Run as Administrator.

The recording may contain personally identifiable or security related information

The created trace file that contains the recording may contain personally identifiable or security related information, including but not necessarily limited to file paths, registry, memory or file contents. Exact information depends on target process activity while it was recorded. Be aware of this when sharing recording files with other people.

TTD.exe command line recording utility

In addition to recording traces in the WinDbg UI, there is a TTD.exe command line utility available to record a trace.

You may have scenarios where only the TTD command line recorder is required: recording on a PC without installing the debugger, advanced recording scenarios, test automation, etc. In these scenarios you can install just the TTD command line recorder through a URL. For more information, see Time Travel Debugging - TTD.exe command line utility .

Comparison of Debugging Tools

This table summarizes the pros and cons of the different debugging solutions available.

Video Training

To learn more about TTD see these videos.

Defrag Tools 185 - Ivette and JamesP go over the basics of TTD and demo some features in WinDbg

Defrag Tools 186 - Jordi and JCAB demo more great features of TTD in WinDbg

CppCon (YouTube) - Jordi, Ken and JamesM presented TTD in WinDbg at CppCon 2017

Trace file basics

Trace file size.

The trace file can get big and the user of TTD needs to make sure that there is adequate free space available. If you record a program for even a few minutes, the trace files can quickly grow to be several gigabytes. TTD does not set a maximum size of trace files to allow for complex long running scenarios. Quickly re-creating the issue, will keep the trace file size as small as possible.

Trace and index files

A trace file ( .run ) stores the code execution during recording.

Once the recording is stopped, an index file ( .idx ) is created to optimize access to the trace information. Index files are also created automatically when WinDbg opens trace files.

Index files can also be large, typically twice as large as the trace file.

You can recreate the index file from the trace file using the !tt.index command.

Recording errors and other recording output is written to a WinDbg log file.

All of the output files are stored in a location configured by the user. The default location is in the users document folder. For example, for User1 the TTD files would be stored here:

For more information on working the trace files, see Time Travel Debugging - Working with trace files .

Things to look out for

Anti-virus incompatibilities.

You may encounter incompatibilities because of how TTD hooks into process to record them. Typically issues arise with anti-virus or other system software that is attempting to track and shadow system memory calls. If you run into issues of with recording, such as an insufficient permission message, try temporarily disabling any anti-virus software.

Other utilities that attempt to block memory access, can also be problematic, for example, the Microsoft Enhanced Mitigation Experience Toolkit.

Another example of an environment that conflicts with TTD, would be the electron application framework. In this case the trace may record, but a deadlock or crash of the process being recorded is also possible.

User mode only

TTD currently supports only user mode operation, so tracing a kernel mode process is not possible.

Read-only playback

You can travel back in time, but you can't change history. You can use read memory commands, but you can't use commands that modify or write to memory.

System Protected Processes

Some Windows system protected processes, such as Protected Process Light (PPL) process are protected, so the TTD cannot inject itself into the protected process to allow for the recording of the code execution.

Performance impact of recording

Recording an application or process impacts the performance of the PC. The actual performance overhead varies based upon the amount and type of code being executed during recording. You can expect about a 10x-20x performance hit in typical recording scenarios. Sometimes there will not be a noticeable slowdown but for more resource intensive operations (i.e. File Open dialog) you can see the impact of recording.

Trace file errors

There are some cases where trace file errors can occur. For more information, see Time Travel Debugging - Troubleshooting .

Advanced Features of Time Travel Debugging

Here's some of the most notable TTD advanced features.

Timelines are a visual representation of events that happen during the execution. These events can be locations of: breakpoints, memory read/writes, function calls and returns, and exceptions. For more information about timelines, see WinDbg - Timelines .

Debugger data model support

  • Built in data model support - TTD includes data model support. Using LINQ queries to analyze application failures can be a powerful tool. You can use the data model window in WinDbg to work with an expandable and browsable version of ‘dx’ and ‘dx -g’, letting you create tables using NatVis, JavaScript, and LINQ queries.

For general information about the debugger data model, see WinDbg - Data model . For information about working with the TTD debugger object model, see Time Travel Debugging - Introduction to Time Travel Debugging objects .

Scripting support

  • Scripting Automation - Scripting support for JavaScript and NatVis allows for the automation of problem investigation. For more information, see Time Travel Debugging - JavaScript Automation .

For general information about working with JavaScript and NatVis, see WinDbg - Scripting .

TTD.exe Command line utility

The TTD.exe command line utility to record traces is available. For more information, see Time Travel Debugging - TTD.exe command line utility .

Managed code TTD support

You can use the SOS debugging extension (sos.dll) running in 64 bit mode to debug managed code using TTD in WinDbg. For more information, see Debugging Managed Code Using the Windows Debugger .

Getting started with TTD

Review these topics to record and replay a trace file as well as for information on working with trace files and troubleshooting.

  • Time Travel Debugging - Record a trace
  • Time Travel Debugging - Replay a trace
  • Time Travel Debugging - Working with trace files
  • Time Travel Debugging - Troubleshooting
  • Time Travel Debugging - Sample App Walkthrough

These topics describe additional advanced functionality in time travel debugging.

  • Time Travel Debugging - Introduction to Time Travel Debugging objects
  • Time Travel Debugging - JavaScript Automation

Was this page helpful?

Additional resources

DEV Community

DEV Community

Temporal profile image

Posted on Aug 8, 2023

Time-Travel Debugging Production Code

In this post, I’ll give an overview of time travel debugging (what it is, its history, how it’s implemented) and show how it relates to debugging your production code.

Normally, when we use debuggers, we set a breakpoint on a line of code, we run our code, execution pauses on our breakpoint, we look at values of variables and maybe the call stack, and then we manually step forward through our code's execution. In time-travel debugging , also known as reverse debugging , we can step backward as well as forward. This is powerful because debugging is an exercise in figuring out what happened: traditional debuggers are good at telling you what your program is doing right now, whereas time-travel debuggers let you see what happened. You can wind back to any line of code that executed and see the full program state at any point in your program’s history.

History and current state

It all started with Smalltalk-76, developed in 1976 at Xerox PARC . ( Everything started at PARC 😄.) It had the ability to retrospectively inspect checkpointed places in execution. Around 1980, MIT added a "retrograde motion" command to its DDT debugger , which gave a limited ability to move backward through execution. In a 1995 paper, MIT researchers released ZStep 95, the first true reverse debugger, which recorded all operations as they were performed and supported stepping backward, reverting the system to the previous state. However, it was a research tool and not widely adopted outside academia.

ODB, the Omniscient Debugger , was a Java reverse debugger that was introduced in 2003, marking the first instance of time-travel debugging in a widely used programming language. GDB (perhaps the most well-known command-line debugger, used mostly with C/C++) added it in 2009.

Now, time-travel debugging is available for many languages, platforms, and IDEs, including:

  • Replay for JavaScript in Chrome, Firefox, and Node, and Wallaby for tests in Node
  • WinDbg for Windows applications
  • rr for C, C++, Rust, Go, and others on Linux
  • Undo for C, C++, Java, Kotlin, Rust, and Go on Linux
  • Various extensions (often rr- or Undo-based) for Visual Studio, VS Code, JetBrains IDEs, Emacs, etc.

Implementation techniques

There are three main approaches to implementing time-travel debugging:

  • Record & Replay : Record all non-deterministic inputs to a program during its execution. Then, during the debug phase, the program can be deterministically replayed using the recorded inputs in order to reconstruct any prior state.
  • Snapshotting : Periodically take snapshots of a program's entire state. During debugging, the program can be rolled back to these saved states. This method can be memory-intensive because it involves storing the entire state of the program at multiple points in time.
  • Instrumentation : Add extra code to the program that logs changes in its state. This extra code allows the debugger to step the program backwards by reverting changes. However, this approach can significantly slow down the program's execution.

rr uses the first (the rr name stands for Record and Replay), as does Replay . WinDbg uses the first two, and Undo uses all three (see how it differs from rr ).

Time-traveling in production

Traditionally, running a debugger in prod doesn't make much sense. Sure, we could SSH into a prod machine and start the process handling requests with a debugger and a breakpoint, but once we hit the breakpoint, we're delaying responses to all current requests and unable to respond to new requests. Also, debugging non-trivial issues is an iterative process: we get a clue, we keep looking and find more clues; discovery of each clue is typically rerunning the program and reproducing the failure. So, instead of debugging in production, what we do is replicate on our dev machine whatever issue we're investigating and use a debugger locally (or, more often, add log statements 😄), and re-run as many times as required to figure it out. Replicating takes time (and in some cases a lot of time, and in some cases infinite time), so it would be really useful if we didn't have to.

While running traditional debuggers doesn't make sense, time-travel debuggers can record a process execution on one machine and replay it on another machine. So we can record (or snapshot or instrument) production and replay it on our dev machine for debugging (depending on the tool, our machine may need to have the same CPU instruction set as prod). However, the recording step generally doesn't make sense to use in prod given the high amount of overhead—if we set up recording and then have to use ten times as many servers to handle the same load, whoever pays our AWS bill will not be happy 😁.

But there are a couple scenarios in which it does make sense:

  • Undo only slows down execution 2–5x , so while we don't want to leave it on just in case, we can turn it on temporarily on a subset of prod processes for hard-to-repro bugs until we have captured the bug happening, and then we turn it off.
  • When we're already recording the execution of a program in the normal course of operation.

The rest of this post is about #2, which is a way of running programs called durable execution .

Durable execution

What's that.

First, a brief backstory. After Amazon (one of the first large adopters of microservices) decided that using message queues to communicate between services was not the way to go (hear the story first-hand here ), they started using orchestration. And once they realized defining orchestration logic in YAML/JSON wasn't a good developer experience, they created AWS Simple Workfow Service to define logic in code. This technique of backing code by an orchestration engine is called durable execution, and it spread to Azure Durable Functions , Cadence (used at Uber for > 1,000 services ), and Temporal (used by Stripe, Netflix, Datadog, Snap, Coinbase, and many more).

Durable execution runs code durably—recording each step in a database, so that when anything fails, it can be retried from the same step. The machine running the function can even lose power before it gets to line 10, and another process is guaranteed to pick up executing at line 10, with all variables and threads intact. 1 It does this with a form of record & replay: all input from the outside is recorded, so when the second process picks up the partially-executed function, it can replay the code (in a side-effect–free manner) with the recorded input in order to get the code into the right state by line 10.

Durable execution's flavor of record & replay doesn't use high-overhead methods like software JIT binary translation , snapshotting, or instrumentation. It also doesn't require special hardware. It does require one constraint: durable code must be deterministic (i.e., given the same input, it must take the same code path). So it can't do things that might have different results at different times, like use the network or disk. However, it can call other functions that are run normally ( "volatile functions" , as we like to call them 😄), and while each step of those functions isn't persisted, the functions are automatically retried on transient failures (like a service being down).

Only the steps that require interacting with the outside world (like calling a volatile function, or calling sleep('30 days') , which stores a timer in the database) are persisted. Their results are also persisted, so that when you replay the durable function that died on line 10, if it previously called the volatile function on line 5 that returned "foo", during replay, "foo" will immediately be returned (instead of the volatile function getting called again). While yes, it adds latency to be saving things to the database, Temporal supports extremely high throughput (tested up to a million recorded steps per second). And in addition to function recoverability and automatic retries, it comes with many more benefits , including extraordinary visibility into and debuggability of production.

Debugging prod

With durable execution, we can read through the steps that every single durable function took in production. We can also download the execution’s history, checkout the version of the code that's running in prod, and pass the file to a replayer (Temporal has runtimes for Go, Java, JavaScript, Python, .NET, and PHP) so we can see in a debugger exactly what the code did during that production function execution. Read this post or watch this video to see an example in VS Code. 2

Being able to debug any past production code is a huge step up from the other option (finding a bug, trying to repro locally, failing, turning on Undo recording in prod until it happens again, turning it off, then debugging locally). It's also a (sometimes necessary) step up distributed tracing.

I hope you found this post interesting! If you'd like to learn more about durable execution, I recommend reading:

  • Building reliable distributed systems
  • How durable execution works

and watching:

  • Introduction to Temporal
  • Why durable execution changes everything

Thanks to Greg Law, Jason Laster, Chad Retz, and Fitz for reviewing drafts of this post.

Technically, it doesn't have line-by-line granularity. It only records certain steps that the code takes—read on for more info ☺️.  ↩

The astute reader may note that our extension uses the default VS Code debugger, which doesn’t have a back button 😄. I transitioned from talking about TTD to methods of debugging production code via recording, so while Temporal doesn’t have TTD yet, it does record all the non-deterministic inputs to the program and is able to replay execution, so it’s definitely possible to implement. Upvote this issue or comment if you have thoughts on implementation!  ↩

Top comments (0)

pic

Templates let you quickly answer FAQs or store snippets for re-use.

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink .

Hide child comments as well

For further actions, you may consider blocking this person and/or reporting abuse

kiolk profile image

Developer diary #17. How does it work?

Kiolk - Aug 31

vivekalhat profile image

Building a simple load balancer in Go

Vivek Alhat - Sep 7

samuel_kinuthia profile image

The Developer’s Guide to Speeding Up Development with Mock Service Worker (MSW)

Samuel Kinuthia - Sep 4

mdarifulhaque profile image

2699. Modify Graph Edge Weights

MD ARIFUL HAQUE - Aug 30

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Navigation Menu

Search code, repositories, users, issues, pull requests..., provide feedback.

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly.

To see all available qualifiers, see our documentation .

  • Notifications You must be signed in to change notification settings

record & replay or time travel debugging

taowen/awesome-debugger

Folders and files, repository files navigation.

  • Django: kolo
  • Redux: DevTools
  • https://meiosis.js.org/tracer/
  • https://elm-lang.org/news/time-travel-made-easy
  • http://pythontutor.com/
  • https://pytrace.com/
  • https://viztracer.readthedocs.io/en/latest/
  • https://revdebug.gitbook.io/revdebug/supported-langauges/python
  • https://undo.io/solutions/products/java/
  • https://arthas.aliyun.com/doc/tt
  • https://www.cs.cmu.edu/~NatProg/whyline-java.html
  • https://revdebug.gitbook.io/revdebug/supported-langauges/java
  • https://github.com/alibaba/jvm-sandbox-repeater
  • https://chrononsystems.com/
  • https://revdebug.gitbook.io/revdebug/supported-langauges/c
  • https://github.com/didi/sharingan

javascript & browser

  • https://wallabyjs.com/docs/intro/time-travel-debugger.html
  • https://logrocket.com/
  • https://revdebug.gitbook.io/revdebug/supported-langauges/javascript
  • https://replay.io/
  • https://developer.chrome.com/docs/devtools/recorder/
  • https://www.highlight.io/
  • https://rr-project.org/
  • https://pernos.co/
  • https://github.com/didi/rdebug
  • https://azmr.itch.io/whitebox
  • https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/time-travel-debugging-overview
  • https://totalview.io/products/totalview
  • http://www.simulics.com/index_en.php
  • https://lldb.llvm.org/use/intel_pt.html

virtual machine

  • https://wiki.qemu.org/Features/record-replay
  • https://github.com/panda-re/panda/blob/dev/panda/docs/time-travel.md
  • PIX: https://devblogs.microsoft.com/pix/download/
  • nsight: https://developer.nvidia.com/nsight-graphics
  • spector.js: https://spector.babylonjs.com/
  • webgl-recorder: https://github.com/evanw/webgl-recorder
  • safari: https://webkit.org/blog/8452/canvas-debugging/
  • https://renderdoc.org/
  • Reverse History Part One http://jakob.engbloms.se/archives/1547
  • Reverse History Part Two – Research http://jakob.engbloms.se/archives/1554
  • Reverse History Part Three – Products http://jakob.engbloms.se/archives/1564
  • Studying the Advancement in Debugging Practice https://jakob.engbloms.se/archives/3077
  • If I Only Changed the Software, why is the Phone on Fire http://jakob.engbloms.se/archives/1917
  • Debugging – the 9 Indispensable Rules for Finding Even the Most Elusive Software and Hardware Problems https://jakob.engbloms.se/archives/1923
  • My Hairiest Bug War Stories https://www.researchgate.net/publication/27297655_My_Hairiest_Bug_War_Stories
  • https://medium.com/machine-words/scientific-debugging-part-1-8890b73b6c4c
  • https://medium.com/machine-words/scientific-debugging-part-2-difficult-observations-bba84772d3d1
  • https://medium.com/machine-words/scientific-debugging-part-3-space-and-time-75ae28a7b9d7

Contributors 2

Time Travel Debug in VS Code

Time Travel Debug in VS Code

Debugging in VS Code

We’re happy to announce that time travel debugging is now available in Visual Studio Code (VS Code) via the Time Travel Debug for C/C++ plugin.

Time Travel Debug for C/C++ places time travel debugging capabilities at the fingertips of developers using VS Code. The technology is based on the UDB time travel debugger .

With this plugin, developers can now travel forward and backward through full code execution in order to:

  • Get full visibility into the state of the code they’re working on – at any point in its execution
  • Understand complex code and how it all hangs together
  • Accelerate root cause analysis and reduce bug-fix time

By debugging this way, programmers can conduct effective root-cause analysis (without needing to predict ahead of time what to log), and avoid disruptive redeployments.

How does it work?

The plugin adds a time travel debugging toolbar to your VS Code interface so that you can step through the code forward and backward and watch variable and memory changes as your navigate forward and in reverse to understand what the software did.

VS Code time travel debugging toolbar

How to get started with Time Travel Debug for C/C++

Key features

Here’s a summary of the key feature capabilities added to VS Code:

  • Navigate backward and forward through code execution: Reverse Step In/Out/Over joins the familiar Step In/Out/Over
  • Launch, Attach, or Replay a  LiveRecorder  recording
  • Continue and Reverse Continue , stopping at Breakpoints / Conditional Breakpoints / Watchpoints
  • Inspect global and local variable values at any point in your program’s execution history
  • Timeline  – visually navigate and zoom through the execution flow
  • Bookmarks  – set bookmarks at any point in your program’s execution history. These appear on the timeline and can be easily jumped to
  • Undo  your last navigation action
  • Evaluate expressions and call functions in the  Debug Console  at any point in your program’s execution history

Making VS Code better for developers

Microsoft’s IDE provides a rich development environment, including debugging capabilities such as variable inspection, stepping into code, and displaying the call stack. The great thing about VS Code is that it is highly extensible. With this integration we’ve taken advantage of that extensibility, and by adding time travel debugging superpowers, we’ve made it substantially quicker and easier to understand complex C/C++ codebases and the conditions that led to a specific error.

Try it out for yourself

Give it a try and don’t forget to leave your review on the VS Code marketplace.

Get the extension

UDB and Time Travel Debug extension for VS Code - try it now

Stay informed. Get the latest in your inbox.

Hit enter to search or ESC to close

IMAGES

  1. Time Travel Debugging (in Python)

    time travel debugging python

  2. PyTrace

    time travel debugging python

  3. PyTrace

    time travel debugging python

  4. Debugging In Python

    time travel debugging python

  5. PyTrace

    time travel debugging python

  6. Time Travel Debugging

    time travel debugging python

VIDEO

  1. Python: Debugging using Idle, Spyder, iPython, Notebook

  2. Using Time Travel Debugging to Reanimate a Zombie in Doom​ #cpp #cplusplusprogramming #cplusplus

  3. Time Travel in DBOS

  4. Step-by-Step Guide to Debugging in VS Code

  5. UDB Time Travel Debugging (Demo)

  6. Dart Day 5: Debugging Time! 🛠️🎮

COMMENTS

  1. PyTrace

    2. Add attribute @trace to the method you want to record. some_code() Your recording will be stored in your working directory. 3. Open your recording in to analyze. PyTrace is a time travel recorder/analyzer for Python. It records code execution, variables and stack frames. Debugging has never been so easy.

  2. Time Travel Debugging in Python

    I was recently wondering about Time Travel Debugging in relation to Python. I found information about tools like: RevPDB - unfortunately the last recorded activity is from 2016. timetravelpdb - unfortunately the last recorded activity is in 2015. Since the projects were updated so long ago, I was wondering if the tools used for TTD had changed ...

  3. PyTrace

    Go to the end of the method: Shift + Left Click. Scope to method: Command + Left Click. (press Command + Left Click again on upper frame to exit or change method scope) PyTrace is a time travel recorder/analyzer for Python. It records code execution, variables and stack frames. Debugging has never been so easy.

  4. How I debug Python code with a Time Travel Debugger

    The debugger isn't aware of any of the Python functions or variables inside our program. Luckily, the cpython project maintains a library of GDB extensions that give GDB the ability to understand Python code. The libpython.py library knows how to inspect the internal structures of cpython in order to present the state of the Python program to the user.

  5. Time Traveling Debugger

    Time Traveling Debugger. This project is an attempt to build a usable, practical, useful and viable time-travel debugger. A time-traveling debugger works by recording the each state in the execution of a program into a database - we call that the history file - and then allowing the programmer to navigate through this file to investigate the ...

  6. How to Use Python to Time Travel: Exploring Datetime

    Pitfalls and Wormholes 🕳️ Disclaimer: Please remember that though we have gallivanted through time, there is one thing Python datetime won't save you from: the Y10K problem, a.k.a. the Year 10,000 problem. Someday computers might not be able to handle a five-digit year. But let's be real - that's a problem for the cyborgs of the future.

  7. TomOnTime/timetravelpdb: The Time Travel Python Debugger

    Enhances the Python Debugger to add the ability to travel back in time. Have you ever been using PDB to step through a program and suddenly realize you wish you could jump back in time and know what a variable used to contain? This version of PDB adds the ability to jump back in time to the state of your program as it was in the past.

  8. Introduction to time travel debugging

    Time Travel vs. Step-through. It can be difficult to understand the differences between a time traveling debugger and a browser debugger. Let's take a look at some example code:

  9. Time travel debugging

    Time travel debugging

  10. Time Travel Debugging (in Python)

    Time Travel Debugging (in Python) Published on Mar 24th 2021 • Duration: 05:44 • Watch on YouTube. This video introduces the time traveling debugging for Python I've been working up to today. It show what it's like to code using time traveling debugging, how my implementation works, as well as a proof of concept debugging UI called the zoom ...

  11. Time Travel Debugging (in Python)

    This video introduces the time traveling debugging for Python I've been working up to today. It show what it's like to code using time traveling debugging, h...

  12. Time-Travel Debugging Production Code

    Time-Travel Debugging Production Code

  13. gleb-sevruk/pycrunch-trace: Time Travel Debugging for Python

    Time Travel Debugging for Python pytrace.com. Topics. python debugging profiler tracing time-travel Resources. Readme License. MIT license Activity. Stars. 151 stars Watchers. 5 watching Forks. 12 forks Report repository Releases No releases published. Packages 0. No packages published . Contributors 4 . Languages.

  14. Project: Time Travel Debugger

    A time travel debugger records a log of the process execution (including call stack and values of all variables at each step), so that it is possible to run it later with both forward and backward commands. The interactive session does not execute the code statements, but just replays all actions taken from the recorded execution.

  15. PyTrace

    Visit site for quick starthttps://pytrace.com/Interactive demo:https://app.pytrace.com/?open=v0.1-interactive-demo

  16. 6 Things You Need to Know About Time Travel Debugging

    6 Things You Need to Know About Time Travel Debugging

  17. The Time Travel Method of Debugging Software

    The Time Travel Method of Debugging Software. Apr 29th, 2022 10:54am by Starr Campbell. Photo by Fatih Turan from Pexels. Developing programs that run seamlessly isn't a linear task. The more intricate and complex the code, the more bugs that engineers potentially have to deal with. Studies have shown that software developers spend 35-50% of ...

  18. Introducing the Python Time Travel Debugger

    This version of PDB adds the ability to jump back in time to the state of your program as it was in the past. You can examine variables and even continue execution from that point forward (though that is dangerous because it may harm the time space continuum.) How it works: As you know, time is the 4th dimension. Every moment is another universe.

  19. How to move one step back in VS Code debugging mode in Python?

    You can change next executing line with Debug: Jump to Cursor command. Note: you can bind this action to some hotkey like (ctrl + f8) doc. This does not solve the problem. If you change a variable then step to a line of code before you changed this variable, this variable is still changed and will act this way.

  20. Time Travel Debugging

    Time Travel Debugging - Overview - Windows drivers

  21. Time-Travel Debugging Production Code

    ODB, the Omniscient Debugger, was a Java reverse debugger that was introduced in 2003, marking the first instance of time-travel debugging in a widely used programming language. GDB (perhaps the most well-known command-line debugger, used mostly with C/C++) added it in 2009. Now, time-travel debugging is available for many languages, platforms ...

  22. taowen/awesome-debugger: record & replay or time travel debugging

    About. record & replay or time travel debugging. visualization debugger debugging awesome awesome-list. Readme. CC0-1.0 license. Activity. 62 stars. 5 watching. 5 forks.

  23. Time Travel Debug in VS Code

    We're happy to announce that time travel debugging is now available in Visual Studio Code (VS Code) via the Time Travel Debug for C/C++ plugin.. Time Travel Debug for C/C++ places time travel debugging capabilities at the fingertips of developers using VS Code. The technology is based on the UDB time travel debugger.. With this plugin, developers can now travel forward and backward through ...