Linux PC with a terminal window open
Fatmawati Achmad Zaenuri/Shutterstock.com

Want to know how long a process runs and a whole lot more? The Linux time command returns time statistics, giving you cool insights into the resources used by your programs.

time Has Many Relatives

There are many Linux distributions and different Unix-like operating systems. Each of these has a default command shell. The most common default shell in modern Linux distributions is the bash shell. But there are many others, such as the Z shell (zsh) and the Korn shell (ksh).

All of these shells incorporate their own time command, either as a built-in command or as a reserved word. When you type time in a terminal window the shell will execute its internal command instead of using the GNU time binary which is provided as part of your Linux distribution.

We want to use the GNU version of time because it has more options and is more flexible.

Which time Will Run?

You can check which version will run by using the type command. type will let you know whether the shell will handle your instruction itself, with its internal routines, or pass it on to the GNU binary.

in a terminal window type the word type, a space, and then the word time and hit Enter.

type time

type time in a bash terminal window

We can see that in the bash shell time is a reserved word. This means Bash will use its internaltime routines by default.

type time

type time in a zsh terminal window

In the Z shell (zsh) time is a reserved word, so the internal shell routines will be used by default.

type time

type time in a Korn shell window

In the Korn shell time is a keyword. An internal routine will be used instead of the GNU time command.

RELATED: What is ZSH, and Why Should You Use It Instead of Bash?

Running the GNU time Command

If the shell on your Linux system has an internal time routine you’ll need to be explicit if you wish to use the GNU time binary. You must either:

  • Provide the whole path to the binary, such as  /usr/bin/time. Run the which time command to find this path.
  • Use command time.
  • Use a backslash like \time.

time command output in a terminal window

The which time command gives us the path to the binary.

We can test this by using /usr/bin/time as a command to launch the GNU binary. That works. We get a response from the time command telling us we didn’t provide any command line parameters for it to work on.

Typing command time also works, and we get the same usage information from time. The command command tells the shell to ignore the next command so that it is processed outside of the shell.

Using a \ character before the command name is the same as using command before the command name.

The simplest way to ensure you are using the GNU time binary is to to use the backslash option.

time
\time

time and \time output in a terminal window

time invokes the shell version of time. \time uses the time binary.

Using The time Command

Let’s time some programs. We’re using two programs called loop1 and loop2. They were created from loop1.c and loop2.c. They don’t do anything useful apart from demonstrating the effects of one type of coding inefficiency.

This is loop1.c. The length of a string is required within the two nested loops. The length is obtained in advance, outside of the two nested loops.

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

int main (int argc, char* argv[])
{
 int i, j, len, count=0;
 char szString[]="how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek";

 // get length of string once, outside of loops
 len = strlen( szString );  

 for (j=0; j<500000; j++) {

 for (i=0; i < len; i++ ) {

  if (szString[i] == '-')
    count++;
   }
 }

 printf("Counted %d hyphens\n", count);

 exit (0);

} // end of main

This is loop2.c. The length of the string is obtained time after time for every cycle of the outer loop. This inefficiency ought to show up in the timings.

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

int main (int argc, char* argv[])
{
 int i, j, count=0;
 char szString[]="how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek";

 for (j=0; j<500000; j++) {

 // getting length of string every
 // time the loops trigger
 for (i=0; i < strlen(szString); i++ ) {

   if (szString[i] == '-')
    count++;
   }
 }

 printf("Counted %d hyphens\n", count);

 exit (0);

} // end of main

Let’s fire up the loop1 program and use time to measure its performance.

\time ./loop1

time results for loop1 in a terminal window

Now let’s do the same for loop2.

\time ./loop2

time output for loop2 in a terminal window

That’s given us two sets of results, but they’re in a really ugly format. We can do something about that later, but let’s pick a few bits of information out of the results.

When programs run there are two execution modes that they are switched back and forth between. These are called user mode and kernel mode.

Briefly put, a process in user mode cannot directly access hardware or reference memory outside of its own allocation. In order to get access to such resources, the process must make requests to the kernel. If the kernel approves the request the process enters kernel mode execution until the requirement has been satisfied. The process is then switched back to user mode execution.

The results for loop1 tell us that loop1 spent 0.09 seconds in user mode. It either spent zero time in kernel mode or the time in kernel mode is too low a value to register once it has been rounded down. The total elapsed time was 0.1 seconds. loop1 was awarded an average of 89% of CPU time over the duration of its total elapsed time.

The inefficient loop2 program took three times longer to execute. Its total elapsed time is 0.3 seconds. The duration of the processing time in user mode is 0.29 seconds. Nothing is registering for kernel mode. loop2 was awarded an average of 96% of CPU time for the duration of its run.

Formatting The Output

You can customize the output from time using a format string. The format string can contain text and format specifiers. The list of format specifiers can be found on the man page for time. Each of the format specifiers represents a piece of information.

When the string is printed the format specifiers are replaced by the actual values they represent. For example, the format specifier for the percentage of CPU is the letter P . To indicate to time that a format specifier is not just a regular letter, add a percentage sign to it, like %P . Let’s use it in an example.

The -f (format string) option is used to tell time that what follows is a format string.

Our format string is going to print the characters “Program: ” and the name of the program (and any command line parameters that you pass to the program). The %C format specifier stands for “Name and command-line arguments of the command being timed”. The \n causes the output to move to the next line.

There are a lot of formats specifiers and they are case sensitive, so make sure you are entering them correctly when you’re doing this for yourselves.

Next, we’re going to print the characters “Total time: ” followed by the value of the total elapsed time for this run of the program (represented by %E).

We use \n to give another new line. We’ll then print the characters “User Mode (s) “, followed by the value of the CPU time spent in user mode, signified by the %U.

We use \n to give another new line. This time we are preparing for the kernel time value. We print the characters “Kernel Mode (s) “, followed by the format specifier for CPU time spent in kernel mode, which is %S.

Finally, we are going to print the characters “\nCPU: ” to give us a new line and the title for this data value. The %P format specifier will give the average percentage of CPU time used by the timed process.

The whole format string is wrapped in quotation marks. We could have included some \t characters to place tabs in the output if we were fussy about the alignment of the values.

\time -f "Program: %C\nTotal time: %E\nUser Mode (s) %U\nKernel Mode (s) %S\nCPU: %P" ./loop1

Output from format string for loop1 in a terminal window

Sending The Output To A File

To keep a record of the timings from the tests you have conducted you can send the output from time to a file. To do this use the -o (output) option. The output from your program will still display in the terminal window. It is only the output from time that is redirected to the file.

We can re-run the test and save the output to the test_results.txt file as follows:

\time -o test_results.txt -f "Program: %C\nTotal time: %E\nUser Mode (s) %U\nKernel Mode (s) %S\nCPU: %P" ./loop1
cat test_results.txt

Output from format string for loop1 piped to file in a terminal window

The loop1 program output is displayed in the terminal window and the results from time go to the test_results.txt file.

If you want to capture the next set of results in the same file, you must use the -a (append) option as follows:

\time -o test_results.txt -a -f "Program: %C\nTotal time: %E\nUser Mode (s) %U\nKernel Mode (s) %S\nCPU: %P" ./loop2
cat test_results.txt

Output from format string for loop2 appended to file in a terminal window

It should now be apparent why we used the %C format specifier to include the name of the program in the output from the format string.

And We’re Out Of time

Probably of most use to programmers and developers for fine-tuning their code, the time command is also useful for anyone wanting to discover a bit more about what goes on under the hood each time you launch a program.

Dave McKay Dave McKay
Dave McKay first used computers when punched paper tape was in vogue, and he has been programming ever since. He is now a Data Protection Officer and has worked as a freelance programmer, manager of an international software development team, and an IT services project manager. Dave is a Linux evangelist and open source advocate.
Read Full Bio »