3

I have to write the time it takes for several C programs to run on several files using:

time ./program filename

to a spread sheet and am using subprocess.check_output to get the stdout as a string. I should get something along the lines of:

real    0m0.001s
user    0m0.001s
sys     0m0.000s

but I get:

b'0.00user 0.00system 0:00.00elapsed ?%CPU (0avgtext+0avgdata 
1388maxresident)k\n0inputs+0outputs (0major+60minor)pagefaults 
0swaps\n'

I see the user and system time but they get cut off after two decimal places. Is there a way to make sure the output reads all 3 decimal places? Here is my code:

import xlwt
import subprocess

files = ('100KB.txt', '1MB.txt', '10MB.txt', '100MB.txt')
programs = ('./10kBuffer', './step2', './step3', './step4')

command = ['time', programs[0], files[0]]
out = subprocess.check_output(command, stderr=subprocess.STDOUT)
print(out)
omikes
  • 8,064
  • 8
  • 37
  • 50
DMatza
  • 63
  • 4
  • 2
    try with `['time', '-p', programs[0], files[0]]` you may have an alias. -p option is the one you're looking for. Also do `print(out.decode())` to get proper string output – Jean-François Fabre Mar 08 '19 at 21:15

2 Answers2

2

that's because GNU time uses the default format string, more detailed, but you need -p option.

Quoting the manual:

The default format string is:

%Uuser %Ssystem %Eelapsed %PCPU (%Xtext+%Ddata %Mmax)k %Iinputs+%Ooutputs (%Fmajor+%Rminor)pagefaults %Wswaps

When the -p option is given, the (portable) output format is used:

real %e
user %U
sys %S

You also need to decode the output or you'll get bytes instead of str, and newlines won't be interpreted. ex:

>>> print(b'hello\nworld\n')
b'hello\nworld\n'
>>> print('hello\nworld\n')
hello
world

So I would fix your code as is:

command = ['time', '-p', programs[0], files[0]]
out = subprocess.check_output(command, stderr=subprocess.STDOUT)
print(out.decode())

EDIT: the other answer seems to help fixing the missing decimals by using shell built-in. You can mix both answers to get the output you need as string, with enough decimals.

Note that it doesn't seem you can do much better, unless you want to use a profiler for your command (see How do I get time of a Python program's execution?)

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • Thank you.That fixes the formatting but it still cuts off at 2 decimal places. Is that jsut something I'll have to live with(its only that very small files like 100KB that need 3+ decimal places)? Should I look into the time manual or the subprocess manual – DMatza Mar 08 '19 at 21:22
  • gla3dr answer seems to provide the information which was missing from this answer. – Jean-François Fabre Mar 09 '19 at 06:57
  • With `universal_newlines=True` or `text=True` (Python 3.7+) you don't have to separately `decode` anything. If your Python is too old to have these, maybe think about upgrading. – tripleee Mar 09 '19 at 07:43
2

It looks like you are running into confusion between GNU time getting used by your python script and the time shell built-in being used on command line.

This comes from the man page for GNU time:

Note: some shells (e.g., bash(1)) have a built-in time command that provides less functionality than the command described here. To access the real command, you may need to specify its pathname (something like /usr/bin/time).

Based on the output you were expecting, it looks like you are wanting the bash built-in, which gives 3 decimal places:

$ bash -c time time

real    0m0.000s
user    0m0.000s
sys     0m0.000s

$ sh -c time time
user    0m0.00s
sys     0m0.00s

$ ksh -c time time
user    0m0.00s
sys     0m0.00s

$ tcsh -c time time
0.016u 0.011s 0:00.02 100.0%    0+0k 0+0io 0pf+0w

So in order to specify the bash built-in rather than GNU time, you can change your command to:

command = ['bash', '-c', 'time', programs[0], files[0]]

and you should get the output you were expecting.

gla3dr
  • 2,179
  • 16
  • 29