Fastest draw in the west! We're going rootin' tootin' cow-poke shootin!
This is a simple contest, first program to draw their pistol wins.
How it works:

I require 2 things from you, an executable, and a command to be run
from a bash terminal.
The executable needs to do one thing: wait
until it receives 'draw!' from STDIN, and then print 'bang!' as fast
as possible, and exit.
The executable can do anything else in the
meantime, even print to STDOUT, as long as it doesn't print 'bang!',
or feed itself from STDIN. It also can't use a standard loophole.
Printing 'bang!' early, or exiting without printing 'bang!' is not allowed (you'll be one dead son of a gun).
Bash, and other sh derivatives, including sh scripts are not allowed, we don't settle things on native land.

How I measure your boot size:

Using the golang runtime, I shall execute your command 1,000 times, the time it takes after feeding 'draw!' into STDIN to print 'bang!' will be your score, within +/- 2 nanoseconds. Your program will be given 500ms(+/-100ms of randomness) to stabilize, and load into memory. The program shall be run on ubuntu 20.04 server with only the necessary components to run your program installed.
There will be the following categories: Max time, Min time, Avg time, and Median time, all with lower times being the best.

At the end of the month, the fastest gun in the wild west will be chosen. Best of luck!
section .text

global _start

_start:
  xor r8, r8
  xor r9, r9
  xor r10, r10

_do_while:

_getchar:
  cmp r9, r10

  jne _getchar_done

_getchar_read_buffer:
  xor r9, r9

  xor eax, eax
  xor edi, edi
  mov rsi, in_buf
  mov rdx, inbuf_maxlen

  syscall

  mov r10, rax

_getchar_done:
  mov al, [in_buf + r9]
  inc r9


_do_while_cont:
  cmp al, [req + r8]

  jne _reset

_increment:
  inc r8

  cmp r8, 5

  jne _do_while

  mov rax, 1
  mov rdi, 1
  mov rsi, ans
  mov rdx, 5

  syscall

_end:
  mov rax, 60
  xor rdi, rdi

  syscall

_reset:
  xor r8, r8

  cmp al, 'd'

  jne _do_while

  inc r8

  jmp _do_while

section .rodata
  inbuf_maxlen equ 1000000

  req db &quot;draw!&quot;

ALIGN 8
  ans db &quot;bang!&quot;

section .bss
  in_buf resb inbuf_maxlen


A little hand-written assembly. Compile with:
nasm -felf64 foobar.s &amp;&amp; ld foobar.o -o foobar

Edit: move in_bi into a register and use xor.
Edit: used the wrong jump, my code was wrong...
Edit: the previous code had a bug where it would read garbage if the read syscall did not return a full buffer. This version is more efficient (and correct)...
Edit: make sure to process ddraw! correctly. Thanks to Anders Kaseorg for the test case.
Edit: re-structure to move getchar out of a function and to jump less.
Edit: don't xor the high bits of the registers at the suggestion of Cody Gray
Edit: align (thanks to Joshua) and move into .rodata