# dettrace - Dynamic determinism enforcement

## Overview

dettrace uses a combination of lightweight containerization and system call interception to identify and compensate for potentially random behavior that may occur during the execution of a given program or command. In this way, dettrace can be used to launch arbitrary programs and run them in a way that is deterministic and reproducible.

Future dettrace releases will include additional features, particularly record-replay features.  This alpha package provides only the core deterministic container concept, and it is useful primarily for deterministic builds and software tests.

## Installation

dettrace can be built from [source](https://github.com/dettrace/dettrace.git). Kernel 4.8+ is recommended, details on how to build can be found at project's [README](https://github.com/dettrace/dettrace/blob/master/README.md).

## Basic Usage

Typical usage of the dettrace tool consists of simply placing `dettrace` at the beginning of the command that is to be executed. For example, running the script `my-example.sh` would be achieved by the following command:
```shell
dettrace ./my-example.sh
```

Similarly, we could run `dettrace ls -l`, revealing that the process run under dettrace can still by default access the full file system, including `/bin/ls`. More detailed control over the starting conditions of the deterministic computation is enabled with additional command line flags. To see these flags and how to use them, please refer to the command line help info:

```shell
dettrace --help
```

## Examples
The dettrace installation will generate a directory of example scripts located at `<installDir>/dettrace/examples`
which highlight some of the ways that dettrace can be used to enforce determinism.

To run these scripts, first go to the examples directory:
```shell
cd /usr/share/dettrace/examples
```

Next, run one of the examples a few times. For example,
running `./rand.py` should output a new series of random numbers on each execution:

```shell
$ ./rand.py
57 55 68 49 11 68 88 43 2 97
$ ./rand.py
17 12 63 1 92 76 75 68 13 81
$ ./rand.py
98 44 97 98 35 40 40 10 36 19
```

Finally, run the same script a few more times, but this time, use `dettrace` to
enforce determinism:

```shell
$ dettrace ./rand.py
55 8 80 78 8 35 14 60 71 78
$ dettrace ./rand.py
55 8 80 78 8 35 14 60 71 78
$ dettrace ./rand.py
55 8 80 78 8 35 14 60 71 78
```

Notice the key difference here: every execution returns the same results!

In addition to `rand.py`, you can also try the following example scripts:

- `race.sh`: Creates two simultaneously-running processes, one printing `a`
and the other printing `b`. Normally, this generates an output string of
randomly interleaved `a`s and `b`s, but calling this script with `dettrace`
results in a consistent, reproducible output string.

- `date.sh`: Retrieves the current date and time via the `date` command.
Normally, the output of this command would change on subsequent calls as
time elapses. However, running with `dettrace` ensures that the same
date output is received on every call.

- `devrand.sh`: Generates random numbers similar to `rand.py`, but uses
`/dev/random` as the source of its data. **Note:** Reading from `/dev/random`
will block until sufficient entropy is available to generate the random output,
so this example can take a while to run.

It is highly reccommended to take a look at the contents of these example
scripts to see what is being tested.

It is also worthwhile to experiment with running arbitrary commands in
`dettrace`. One such experiment could be reading directly from `/dev/urandom`:

```shell
$ head -c 16 /dev/urandom | hexdump
0000000 9808 6ead 7593 4497 6435 a7d9 876d 8720
0000010
$ head -c 16 /dev/urandom | hexdump
0000000 31b6 8790 f480 8c05 62c5 653f fdbd 27ba
0000010
$ head -c 16 /dev/urandom | hexdump
0000000 e8aa f3e1 95be 0780 4cce 2a15 edf9 d6c9
0000010
```

Again, we see random data being generated. Next, run the same command with
`dettrace`:
```shell
$ dettrace -- head -c 16 /dev/urandom | hexdump
0000000 3211 d873 5fc1 a37b d83b cf8d ea15 69c2
0000010
$ dettrace -- head -c 16 /dev/urandom | hexdump
0000000 3211 d873 5fc1 a37b d83b cf8d ea15 69c2
0000010
$ dettrace -- head -c 16 /dev/urandom | hexdump
0000000 3211 d873 5fc1 a37b d83b cf8d ea15 69c2
0000010
```

As expected, the command is now running deterministically and generates
the same output on each execution.
