#compdef perf
# ------------------------------------------------------------------------------
# Description
# -----------
#
#  Completion script for Linux performance counters 3.3 (perf.wiki.kernel.org).
#
# ------------------------------------------------------------------------------
# Authors
# -------
#
#  * Julien Nicoulaud <julien.nicoulaud@gmail.com>
#
# ------------------------------------------------------------------------------


_perf() {
  local context curcontext="$curcontext" state line
  typeset -A opt_args

  local ret=1

  _arguments -C \
    '(- : *)--version[show version number and exit]' \
    '(- : *)--help[show help]: :_perf_cmds' \
    '1: :_perf_cmds' \
    '*::arg:->args' \
  && ret=0

  case $state in
    (args)
      curcontext="${curcontext%:*:*}:perf-cmd-$words[1]:"
      case $line[1] in
        (annotate)
          # TODO Complete CPU list
          # TODO Complete disassembler style
          _arguments \
            '(- : *)'{-a,--all}'[prints all the available commands on the standard output]' \
            '(-i --input)'{-i,--input=}'[input file name]: :_files' \
            '(-d --dsos)'{-d,--dsos=}'[only consider symbols in these dsos]:dso list' \
            '(-s --symbol)'{-s,--symbol=}'[symbol to annotate]:symbol' \
            '(-f --force)'{-f,--force}'[do not complain, do it]' \
            '(-v --verbose)'{-v,--verbose}'[be more verbose]' \
            '(-D --dump-raw-trace)'{-D,--dump-raw-trace}'[dump raw trace in ASCII]' \
            '(-k --vmlinux)'{-k,--vmlinux=}'[vmlinux pathname]: :_files' \
            '(-m --modules)'{-m,--modules}'[load module symbols]' \
            '(-l --print-line)'{-l,--print-line}'[print matching source lines]' \
            '(-P --full-paths)'{-P,--full-paths}'[don'\''t shorten the displayed pathnames]' \
            '--stdio[use the stdio interface]' \
            '--tui[use the TUI interface]' \
            '(-C --cpu)'{-C,--cpu}'[only report samples for the list of CPUs provided]:CPU list' \
            '--asm-raw[show raw instruction encoding of assembly instructions]' \
            '(--no-source)--source[interleave source code with assembly code]' \
            '(--source)--no-source[don'\''t interleave source code with assembly code]' \
            '--symfs=[look for files with symbols relative to this directory]: :_files -/' \
            '(-M --disassembler-style)'{-M,--disassembler-style=}'[set disassembler style for objdump]:disassembler style' \
            '1::symbol name' \
            && ret=0
        ;;
        (archive)
          _arguments \
            '1: :_files' \
            && ret=0
        ;;
        (bench)
          # TODO Complete subsystems
          # TODO Complete suites
          _arguments \
            '(-f --format)'{-f,--format=}'[specify format style]: :((default\:mainly\ for\ human\ reading simple\:friendly\ for\ automated\ processing\ by\ scripts))' \
            '1::subsystem' \
            '2::suite' \
            && ret=0
        ;;
        (buildid-cache)
          _arguments \
            '(-a --add)'{-a,--add=}'[add specified file to the cache]: :_files' \
            '(-r --remove)'{-r,--remove=}'[remove specified file from the cache]: :_files' \
            '(-v --verbose)'{-v,--verbose}'[be more verbose]' \
            && ret=0
		;;
        (buildid-list)
          _arguments \
            '(-H --with-hits)'{-H,--with-hits}'[show only DSOs with hits]' \
            '(-i --input)'{-i,--input=}'[input file name]: :_files' \
            '(-f --force)'{-f,--force}'[don'\''t do ownership validation]' \
            '(-k --kernel)'{-k,--kernel}'[show running kernel build id]' \
            '(-v --verbose)'{-v,--verbose}'[be more verbose]' \
            && ret=0
        ;;
        (diff)
          _arguments \
            '(-M --displacement)'{-M,--displacement}'[show position displacement relative to baseline]' \
            '(-D --dump-raw-trace)'{-D,--dump-raw-trace}'[dump raw trace in ASCII]' \
            '(-m --modules)'{-m,--modules}'[load module symbols]' \
            '(-d --dsos)'{-d,--dsos=}'[only consider symbols in these dsos]:dso list' \
            '(-C --comms)'{-C,--comms=}'[only consider symbols in these comms]:comm list' \
            '(-S --symbols)'{-S,--symbols=}'[only consider these symbols]:symbol list' \
            '(-s --sort)'{-s,--sort=}'[sort by key(s)]: :_values -s , key pid comm dso symbol' \
            '(-t --field-separator)'{-t,--field-separator=}'[use a special separator character and don'\''t pad with spaces]:separator' \
            '(-v --verbose)'{-v,--verbose}'[be verbose, for instance, show the raw counts in addition to the diff]' \
            '(-f --force)'{-f,--force}'[don'\''t complain, do it]' \
            '--symfs=[look for files with symbols relative to this directory]: :_files -/' \
            '1:old file:_files' \
            '2:new file:_files' \
            && ret=0
        ;;
        (evlist)
          _arguments \
            '(-i --input)'{-i,--input=}'[input file name]: :_files' \
            && ret=0
        ;;
        (inject)
          _arguments \
            '(-b --build-ids)'{-b,--build-ids=}'[inject build-ids into the output stream]:build-id list' \
            '(-v --verbose)'{-v,--verbose}'[be more verbose]' \
            && ret=0
        ;;
        (kmem)
          # TODO Complete 'record' command
          _arguments \
            '(-i --input)'{-i,--input=}'[input file name]: :_files' \
            '--caller[show per-callsite statistics]' \
            '--alloc[show per-allocation statistics]' \
            '(-s --sort)'{-s,--sort=}'[sort by output]: :_values -s , key frag hit bytes' \
            '(-n --lines)'{-n,--lines}'[print n lines only]:number' \
            '1:command:((record\:record\ the\ kmem\ events\ of\ an\ arbitrary\ workload stat\:report\ kernel\ memory\ statistics))' \
            && ret=0
        ;;
        (kvm)
          _arguments \
            '(-i --input)'{-i,--input=}'[input file name]: :_files' \
            '(-o --output)'{-o,--output=}'[output file name]: :_files' \
            '--host=[collect host side performance profile]:host' \
            '--guest=[collect guest side performance profile]:guest' \
            '--guestmount=[guest os root file system mount directory]: :_files -/' \
            '--guestkallsyms=[guest os /proc/kallsyms file copy]: :_files' \
            '--guestmodules=[guest os /proc/modules file copy]: :_files' \
            '--guestvmlinux=[guest os kernel vmlinux]: :_files' \
            '1:command:((top record report diff buildid-list))' \
            && ret=0
        ;;
        (list)
          _arguments \
            '1:event type:((hw\:hardware\ events hardware\:hardware\ events sw\:software\ events software\:software\ events cache\:cache\ events hwcache\:cache\ events tracepoint\:tracepoint\ events))' \
            && ret=0
        ;;
        (lock)
          # TODO Complete 'record' command
          # TODO Complete 'report' command options
          _arguments \
            '(-i --input)'{-i,--input=}'[input file name]: :_files' \
            '(-v --verbose)'{-v,--verbose}'[be more verbose]' \
            '(-D --dump-raw-trace)'{-D,--dump-raw-trace}'[dump raw trace in ASCII]' \
            '1:command:((record\:record\ lock\ events trace\:show\ raw\ lock\ events report\:report\ statistical\ data))' \
            && ret=0
        ;;
        (probe)
          # TODO not implemented
        ;;
        (record)
          # TODO not implemented
        ;;
        (report)
          # TODO not implemented
        ;;
        (sched)
          # TODO Complete 'record' command
          _arguments \
            '(-i --input)'{-i,--input=}'[input file name]: :_files' \
            '(-v --verbose)'{-v,--verbose}'[be more verbose]' \
            '(-D --dump-raw-trace)'{-D,--dump-raw-trace}'[dump raw trace in ASCII]' \
            '1:command:((record\:record\ scheduling\ events script\:see\ a\ detailed\ trace replay\:simulate\ the\ workload map\:print\ a\ textual\ context-switching\ outline))' \
            && ret=0
        ;;
        (script)
          # TODO not implemented
        ;;
        (stat)
          # TODO not implemented
        ;;
        (test)
          _arguments \
            '(-v --verbose)'{-v,--verbose}'[be more verbose]' \
            && ret=0
        ;;
        (timechart)
          # TODO Complete 'record' command
          _arguments \
            '(-i --input)'{-i,--input=}'[input file name]: :_files' \
            '(-o --output)'{-o,--output=}'[output file name]: :_files' \
            '(-w --width)'{-w,--width=}'[select the width of the SVG file]:width' \
            '(-P --power-only)'{-P,--power-only}'[only output the CPU power section of the diagram]' \
            '(-p --process)'{-p,--process}'[select the processes to display, by name or PID]:process' \
            '--symfs=[look for files with symbols relative to this directory]: :_files -/' \
            '1:command:((record))' \
            && ret=0
        ;;
        (top)
          # TODO not implemented
        ;;
        (help)
          _arguments \
            '(- : *)'{-a,--all}'[prints all the available commands on the standard output]' \
            '1: :_perf_cmds' \
            && ret=0
          ;;
        *)
          _call_function ret _perf_cmd_$words[1] && ret=0
          (( ret )) && _message 'no more arguments'
        ;;
      esac
    ;;
  esac
}

# FIXME Parse 'perf --help' instead of hard-coding.
(( $+functions[_perf_cmds] )) ||
_perf_cmds() {
  local commands; commands=(
    'annotate:read perf.data (created by perf record) and display annotated code'
    'archive:create archive with object files with build-ids found in perf.data file'
    'bench:general framework for benchmark suites'
    'buildid-cache:manage build-id cache'
    'buildid-list:list the buildids in a perf.data file'
    'diff:read two perf.data files and display the differential profile'
    'evlist:list the event names in a perf.data file'
    'inject:filter to augment the events stream with additional information'
    'kmem:tool to trace/measure kernel memory(slab) properties'
    'kvm:tool to trace/measure kvm guest os'
    'list:list all symbolic event types'
    'lock:analyze lock events'
    'probe:define new dynamic tracepoints'
    'record:run a command and record its profile into perf.data'
    'report:read perf.data (created by perf record) and display the profile'
    'sched:tool to trace/measure scheduler properties (latencies)'
    'script:read perf.data (created by perf record) and display trace output'
    'stat:run a command and gather performance counter statistics'
    'test:runs sanity tests'
    'timechart:tool to visualize total system behavior during a workload'
    'top:system profiling tool'
    'help:show command usage information'
  )
  _describe -t commands 'command' commands "$@"
}

_perf "$@"

# Local Variables:
# mode: Shell-Script
# sh-indentation: 2
# indent-tabs-mode: nil
# sh-basic-offset: 2
# End:
# vim: ft=zsh sw=2 ts=2 et
