Use fifo for IPC instead of shm

... so memory usage scales with number of traced accesses, instead of a
fixed sized buffer.

Note fifo is used instead of unnamed pipe, because the later would
sometimes encounter EBADF (bad file descriptor) in emitOp.

Naive benchmark suggests fifos are sometimes even faster:

No trace:
➜ fsatrace (pipe) ✗  for _ in {1..10}; do time sh -c 'for _ in {1..5000}; do touch /tmp/blah; done'; done
sh -c 'for _ in {1..5000}; do touch /tmp/blah; done'  5.32s user 3.86s system 106% cpu 8.642 total
sh -c 'for _ in {1..5000}; do touch /tmp/blah; done'  5.42s user 3.78s system 93% cpu 9.867 total
sh -c 'for _ in {1..5000}; do touch /tmp/blah; done'  5.37s user 3.78s system 106% cpu 8.612 total
sh -c 'for _ in {1..5000}; do touch /tmp/blah; done'  5.33s user 3.86s system 106% cpu 8.665 total
sh -c 'for _ in {1..5000}; do touch /tmp/blah; done'  5.38s user 3.88s system 105% cpu 8.786 total
sh -c 'for _ in {1..5000}; do touch /tmp/blah; done'  5.45s user 3.75s system 106% cpu 8.670 total
sh -c 'for _ in {1..5000}; do touch /tmp/blah; done'  5.28s user 3.81s system 106% cpu 8.565 total
sh -c 'for _ in {1..5000}; do touch /tmp/blah; done'  5.40s user 3.81s system 106% cpu 8.655 total
sh -c 'for _ in {1..5000}; do touch /tmp/blah; done'  5.30s user 3.87s system 93% cpu 9.799 total
sh -c 'for _ in {1..5000}; do touch /tmp/blah; done'  5.47s user 3.84s system 106% cpu 8.749 total

shm (without this patch):
➜ fsatrace (main) ✗  for _ in {1..10}; do time ./fsatrace rwmdt /tmp/test.trace -- sh -c 'for _ in {1..5000}; do touch /tmp/blah; done'; done
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.57s user 6.10s system 104% cpu 12.151 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.64s user 6.15s system 104% cpu 12.271 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.70s user 5.90s system 104% cpu 12.073 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.95s user 5.67s system 103% cpu 12.161 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.65s user 6.11s system 96% cpu 13.247 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.40s user 6.26s system 104% cpu 12.146 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.76s user 5.94s system 104% cpu 12.148 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.72s user 6.02s system 104% cpu 12.182 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.53s user 6.15s system 104% cpu 12.161 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.65s user 6.06s system 104% cpu 12.184 total

fifo (with this patch):
➜ fsatrace (pipe) ✗  for _ in {1..10}; do time ./fsatrace rwmdt /tmp/test.trace -- sh -c 'for _ in {1..5000}; do touch /tmp/blah; done'; done
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.65s user 5.36s system 112% cpu 10.667 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.67s user 5.40s system 112% cpu 10.734 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.49s user 5.36s system 98% cpu 12.049 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.67s user 5.40s system 90% cpu 13.332 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.77s user 5.29s system 85% cpu 14.171 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.64s user 5.23s system 93% cpu 12.636 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.52s user 5.46s system 112% cpu 10.681 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.62s user 5.48s system 112% cpu 10.767 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.62s user 5.49s system 112% cpu 10.736 total
./fsatrace rwmdt /tmp/test.trace -- sh -c   6.58s user 5.50s system 112% cpu 10.745 total

core.x64 build shm (without this patch):
real 4m8.011s   user 140m27.589s  sys 26m28.352s
real 4m8.011s   user 140m27.589s  sys 26m28.352s
real 4m5.437s   user 138m15.811s  sys 27m30.292s

core.x64 build fifo (with this patch):
real 4m6.144s   user 139m51.914s  sys 27m59.581s
real 4m6.491s   user 139m55.589s  sys 27m32.088s
real 4m4.018s   user 141m1.785s   sys 27m0.168s

Bug: 95360

Change-Id: Ifc0ca8550618efe105ac75fc3635305623e3aab9
11 files changed
tree: c9b610f7e596b16eb0bbc1f2003a936e7101c44a
  1. src/
  2. test/
  3. .clang-format
  4. .ghci
  5. .gitignore
  6. .travis.yml
  7. appveyor.yml
  8. LICENSE
  9. Makefile
  10. README.fuchsia
  11. README.md
  12. unix.mk
  13. win.mk
README.md

Filesystem Access Tracer

This tool injects code into other applications in order to trace file accesses.

Why?

This can be useful for things like build systems, since it allows to automatically generate dependencies in a toolchain-agnostic way or to ensure declared dependencies match the real ones.

Compiling

On Unix, type make to generate the fsatrace executable and the fsatrace.so shared library.

On Windows, you'll need recent 64-bit and 32-bit versions of mingw. You can either adapt the Makefile to point to your compilers or, alternatively, install https://github.com/commercialhaskell/stack and run the following sequence to get the required compilers:

stack setup --resolver ghc-8.6.5 --arch=x86_64
stack setup --resolver ghc-8.6.5 --arch=i386
stack exec -- pacman -S make

After that, invoke:

stack exec -- make

That should generate fsatrace.exe, fsatracehelper.exe, fsatrace32.dll and fsatrace64.dll.

Usage

Make sure the .dll or .so files are in the same path as the fsatrace executable and run:

fsatrace <options> <output-file> -- <command>

Options is a combination of the following characters:

  • v: print args vector
  • r: dump read operations
  • w: dump write operations
  • m: dump file move operations
  • d: dump file delete operations
  • q: dump file stat operations
  • t: dump touch operations

Environment Variables

  • FSAT_BUF_SIZE: when set, overwrites size of buffer for trace output.

macOS usage

In order to use fsatrace on systems newer than OS X 10.10, System Integrity Protection must be disabled as detailed in https://developer.apple.com/library/content/documentation/Security/Conceptual/System_Integrity_Protection_Guide/ConfiguringSystemIntegrityProtection/ConfiguringSystemIntegrityProtection.html

Use at your own risk!

Output format

Newline-separated sequence with the following possibilities:

  • r|path-to-file-opened-for-write
  • w|path-to-file-opened-for-read
  • m|path-to-destination-of-move|path-to-source-of-move
  • d|path-to-deleted-file
  • q|path-to-queried-file
  • t|path-to-touched-file