0

I am trying to limit the CPU usage of one python script using ulimit -t. The script contains one time.sleep() statement and it is not killed after the specified time limit. Here is the simplified python script named test.py:

import time

while True:
    time.sleep(0.1)

and I run the command as following:

ulimit -v 400000; ulimit -t 30; python test.py

The script keeps running forever. Are there any explanations for this? Thanks.

The answer of mata is correct. I updated my real code which contains a hidden thing that ulimit -t does not count the running time of spawned subprocesses.

#!/usr/bin/env python
# Run: python smt.py filename.smt2 timeout
# timeout is in seconds

import os
import subprocess
import sys
import stat
import time

current_path = os.path.dirname(os.path.realpath(__file__))

def remove_tmp (filename, version):
  try:
    os.remove(filename + '.' + version + '.tmp')
  except OSError:
    pass

  try:
    os.remove(os.path.splitext(filename)[0] + '.' + version +  '.out')
  except OSError:
    pass

  try:
    os.remove(os.path.splitext(filename)[0] + '.' + version +  '.in')
  except OSError:
    pass

def run_raSAT (filename, bounds, sbox, timeout):
  startTime = time.time()  

  raSATResult = "unknown"

  # remove tmps files:
  remove_tmp(filename, "0.2")
  remove_tmp(filename, "0.3")

  proc2 = subprocess.Popen([os.path.join(current_path, "./raSAT-0.2"), filename, bounds, 'sbox=' + str(sbox), 'tout=' + str(timeout-(time.time() - startTime))])
  proc3 = subprocess.Popen([os.path.join(current_path, "./raSAT-0.3"), filename, bounds])
  while True:
    if proc2.poll():
      # try read output of 0.2
      try:
        with open(filename + '.0.2.tmp', 'r') as outfile:
          raSATResult = outfile.read().rstrip()
          outfile.close()
          if raSATResult == "unknown":
            sbox /= 10
            remove_tmp(filename, "0.2")
            proc2 = subprocess.Popen([os.path.join(current_path, "./raSAT-0.2"), filename, bounds, 'sbox=' + str(sbox), 'tout=' + str(timeout-(time.time() - startTime))])
      except IOError:
        pass  

    if proc3.poll():      
      # try read output of 0.3
      try:
        with open(filename + '.0.3.tmp', 'r') as outfile:
          raSATResult = outfile.read().rstrip()
          outfile.close()
      except IOError:
        pass

    if raSATResult == "sat" or raSATResult == "unsat":
      if not proc3.poll():
        proc3.kill()
      if not proc2.poll():
        proc2.kill()
      break

    time.sleep(0.01)


  return raSATResult, sbox

def run(filename, initLowerBound, initUpperBound, sbox, timeout):
  lowerBound = initLowerBound
  upperBound = initUpperBound
  raSATResult = "unknown"
  startTime = time.time()
  while (raSATResult == 'unknown'):
    (raSATResult, sbox) = run_raSAT(filename, 'lb=' + str(lowerBound) + ' ' + str(upperBound), sbox, timeout - (time.time() - startTime))
    if raSATResult == 'unsat':
      (raSATResult, sbox) = run_raSAT(filename, 'lb=-inf inf', sbox, timeout - (time.time() - startTime))  
  print (raSATResult)

  # remove tmps files:
  remove_tmp(filename, "0.2")
  remove_tmp(filename, "0.3")

# get timeout from environment
timeout = float(os.environ.get('STAREXEC_CPU_LIMIT'))

run(sys.argv[1], -10, 10,  0.1, timeout)
Xuan Tung Vu
  • 972
  • 9
  • 18
  • I've tried to improve the title: The original made it clear which two components were involved, but not which aspect of their behavior or interaction the question was about. – Charles Duffy Aug 20 '16 at 19:30

1 Answers1

4

ulimit -t sets the CPU time limit. While your program is sleeping it doesn't use any CPU time, so that time doesn't count. It will only occupy a few CPU cycles to go to sleep again, that's why it's not killed.

You can't specify a real time limit using ulimit.

mata
  • 67,110
  • 10
  • 163
  • 162
  • To implement a realtime limit, schedule a thread which sleeps for the timeout and exit the process when it expires. – wallyk Aug 20 '16 at 18:42
  • Thanks, that's exactly the problem in my program. I just discovered that ulimit -t will apply the same value for each of the spawned process, not the cumulative across the spawned subprocesses. I updated the real code. Do you have any ideas for limitting cumulative time across the current process and all the spawned “subprocesses”? – Xuan Tung Vu Aug 20 '16 at 20:08
  • No, not from the top of my head. Resource limits set by ulimit are always per process. Your edited question is quite different from your initial one, you might want to open a new one. – mata Aug 20 '16 at 23:05