Perseus14
Perseus14

Reputation: 487

Executing linux time command inside python

I want to calculate the time taken to execute a c program inside a python script. I used os.system() function for this.

os.system("{ time ./test.out < inp;} > out 2> exe_time")

The result I get in exe_time is something like this

0.00user 0.00system 0:00.00elapsed ?%CPU (0avgtext+0avgdata 1416maxresident)k 0inputs+8outputs (0major+65minor)pagefaults 0swaps

But when I execute { time ./test.out < inp;} > out 2> exe_time in terminal I get in the exe_time file

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

How do I get the second version of output by using python?

Upvotes: 2

Views: 2409

Answers (2)

Charles Duffy
Charles Duffy

Reputation: 295423

Invoke your code with bash, not /bin/sh (as is default for system()):

subprocess.Popen(['bash', '-c', '{ time ./test.out < inp;} > out 2> exe_time'])

Note however that the above code is not safe to parameterize to work with arbitrary filenames. A better-practices implementation might instead look like:

o, e = subprocess.Popen(['bash', '-c', 'time "$@" 2>&1', '_', './test.out'],
                        stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()

print("Output from command is:")
sys.stdout.write(o + "\n")
print("Output from time is:")
sys.stdout.write(e + "\n")

Note:

  • We're explicitly invoking bash, and thus ensuring that its built-implementation of time is used.
  • Passing arguments out-of-band from the shell script makes it safe to pass arbitrary arguments to the script being run without worrying about whether those arguments contain attempted shell injection attacks.
  • Redirecting 2>&1 within the shell script ensures that any stderr written by test.out is joined with other output, not mixed in with the output from the time command.
  • If we did want to redirect output to files, the better-practice approach would be to do that from Python, as with stdout=open('out', 'w'), stderr=open('exe_time', 'w').

Upvotes: 1

Blender
Blender

Reputation: 298186

os.system() uses /bin/sh. Bash has its own time builtin that it uses instead of the time binary:

$ /usr/bin/time ls /asd
ls: /asd: No such file or directory
        0.00 real         0.00 user         0.00 sys
$ time ls /asd
ls: /asd: No such file or directory

real    0m0.018s
user    0m0.008s
sys     0m0.013s

If you want to see how long it takes for a command to be executed, just use subprocess:

import time
import subprocess

with open('inp', 'rb') as input_file:
    with open('out', 'wb') as output_file:
        start = time.time()
        subprocess.call(['./test.out'], stdin=input_file, stdout=output_file)
        runtime = time.time() - start

Upvotes: 1

Related Questions