Vim Tips Wiki
Register
Advertisement
Tip 1164 Printable Monobook Previous Next

created 2006 · complexity intermediate · author Salman Halim · version 6.0


Here is a function to determine how long something takes to execute – it's useful for determining which of a number of ways of doing something is faster.

Sample call: echo HowLong("echo 'test'", 100)

This will execute "echo 'test'" 100 times and display the number of seconds it took to do so.

Multiple commands can be separated by a |.

" Times the number of times a particular command takes to execute the specified number of times (in seconds).
function! HowLong( command, numberOfTimes )
  " We don't want to be prompted by a message if the command being tried is
  " an echo as that would slow things down while waiting for user input.
  let more = &more
  set nomore
  let startTime = localtime()
  for i in range( a:numberOfTimes )
    execute a:command
  endfor
  let result = localtime() - startTime
  let &more = more
  return result
endfunction

Comments[]

What is it intended for? Wouldn't it be more reliable to use build-in profiling functionality for tuning purposes?


No doubt, but internal profiling requires a HUGE compilation, which isn't the default on Windows (BIG is). The biggest reason why I wrote this at all was that there was a function I used all the time that recently made it into the latest Vim 7 build, potentially making mine redundant. However, the internal one LOOKED like it was actually doing more work than was necessary, so I ran this method on a large number of iterations of the function call. Certainly, it wasn't anywhere near as accurate as using the internal profiling (for one thing, it can only provide accuracy to the second), but it was sufficient to indicate which way was faster.


Here's the function I use:

function! Time(com, ...)
  let time = 0.0
  let numberOfTimes = a:0 ? a:1 : 50000
  for i in range(numberOfTimes + 1)
    let t = reltime()
    execute a:com
    let time += reltime(t)[1]
    echo i.' / '.numberOfTimes
    redraw
  endfor
  echo 'Average time: '.string(numberOfTimes / i)
endfunction

Timing a search[]

The following has been moved here from VimTip516; it needs a clean up.

I wanted to test how quickly various searches are. I used a 20MB file containing a list of email headers, which was 450k lines, and ran the test function shown below, with these results:

  • 1870 matches in 1s for ^\(.*www\&.*x\)
  • 1870 matches in 1s for ^\(.*www\)\@=\(.*x\)\@=
  • 1870 matches in 5s for .*www\&.*x
  • 1870 matches in 9s for www.*x\|x.*www
  • 1870 matches in 18s for \(www.*x\)\|\(x.*www\)

Omitting the parens in \(www.*x\)\|\(x.*www\) roughly doubles its speed, by avoiding the overhead of filling in back-references internally.

While being the shortest pattern, .*www\&.*x is not the fastest. It can be sped up to the same level as ^\(.*www\)\@=\(.*x\)\@= (the fastest pattern) with only a slight increase in complexity (anchoring it to the start of the line), though.

The benchmark function used was:

function TimeSearch(re)
  let c = 0
  let t = localtime()
  exec 'g/'.a:re.'/let c=c+1'
  return c.' matches in '.(localtime()-t).'s for '.a:re
endfunction
Advertisement