COIN-OR::LEMON - Graph Library

Ticket #618: 7a1a282efbb4.patch

File 7a1a282efbb4.patch, 8.2 KB (added by Balazs Dezso, 6 years ago)
  • lemon/time_measure.h

    # HG changeset patch
    # User Balazs Dezso <deba@google.com>
    # Date 1544952166 -3600
    #      Sun Dec 16 10:22:46 2018 +0100
    # Node ID 7a1a282efbb4187d6b0cf5000eafe3c3c7b50f95
    # Parent  8c567e298d7f3fad82cc66754f2fb6c4a420366b
    Time constrained time measure function
    
    diff -r 8c567e298d7f -r 7a1a282efbb4 lemon/time_measure.h
    a b  
    3131#include <unistd.h>
    3232#include <sys/times.h>
    3333#include <sys/time.h>
     34#include <csignal>
    3435#endif
    3536
     37#include <cstring>
    3638#include <string>
    3739#include <fstream>
    3840#include <iostream>
     41#include <vector>
     42#include <lemon/error.h>
    3943#include <lemon/math.h>
    4044
    4145namespace lemon {
     
    604608    return full/total;
    605609  }
    606610
     611  /// Base exception for time measure functions
     612  class TimeMeasureException : public Exception {
     613  public:
     614    /// Constructor
     615    TimeMeasureException() throw() {}
     616    /// Virtual destructor
     617    virtual ~TimeMeasureException() throw() {}
     618    ///A short description of the exception
     619    virtual const char* what() const throw() {
     620      return "lemon::TimeMeasureException";
     621    }
     622  };
     623
     624  /// Exception thrown when time measuring fails
     625  class TimeMeasureError : public TimeMeasureException {
     626  public:
     627    /// Constructor
     628    TimeMeasureError() throw() {}
     629    /// Virtual destructor
     630    virtual ~TimeMeasureError() throw() {}
     631    ///A short description of the exception
     632    virtual const char* what() const throw() {
     633      return "lemon::TimeMeasureError";
     634    }
     635  };
     636
     637  /// Exception thrown when the executed function times out
     638  class TimeoutException : public TimeMeasureException {
     639  public:
     640    /// Constructor
     641    TimeoutException() throw() {}
     642    /// Virtual destructor
     643    virtual ~TimeoutException() throw() {}
     644    ///A short description of the exception
     645    virtual const char* what() const throw() {
     646      return "lemon::TimeoutException";
     647    }
     648  };
     649
     650  /// Exception thrown when the executed function throws an exception
     651  class ExecutionException : public TimeMeasureException {
     652  private:
     653    std::string _message;
     654    mutable std::string _what;
     655  public:
     656    /// Constructor
     657    ExecutionException(const char* message, std::size_t len) throw() {
     658      try {
     659        _message.clear();
     660        _message.assign(message, len);
     661      } catch (...) {}
     662    }
     663    /// Virtual destructor
     664    virtual ~ExecutionException() throw() {}
     665    ///A short description of the exception
     666    virtual const char* what() const throw() {
     667      try {
     668        _what.clear();
     669        std::ostringstream oss;
     670        oss << "lemon::ExecutionException: " << _message;
     671        _what = oss.str();
     672        return _what.c_str();
     673      } catch (...) {}
     674      return "lemon::ExecutionException";
     675    }
     676  };
     677
     678  namespace _time_measure_bits {
     679#ifndef LEMON_WIN32
     680    inline bool write_full(int fd, const void* buffer, std::size_t len) {
     681      std::size_t offset = 0;
     682      while (offset < len) {
     683        ssize_t ret = write(fd, static_cast<const char*>(buffer) + offset, len - offset);
     684        if (ret < 0) {
     685          return false;
     686        }
     687        offset += ret;
     688      }
     689      return true;
     690    }
     691
     692    inline bool read_full(int fd, void* buffer, std::size_t len) {
     693      std::size_t offset = 0;
     694      while (offset < len) {
     695        ssize_t ret = read(fd, static_cast<char*>(buffer) + offset, len - offset);
     696        if (ret < 0) {
     697          return false;
     698        }
     699        offset += ret;
     700      }
     701      return true;
     702    }
     703#endif
     704  }
     705
     706  /// Tool to measure the running time with a time constraint.
     707
     708  /// This function executes \c f on a forked subprocess, and if the subprocess
     709  /// does not terminate in the given time constraint then it is killed by the
     710  /// master process. Because \c f is executed in a subprocess, the side-effects
     711  /// are not affecting the master process.
     712  ///
     713  /// Because WIN32 API does not have efficient \c fork() implementation, this
     714  /// function is not implemented for Windows.
     715
     716  /// \param f the function object to be measured.
     717  /// \param max_time the maximum total running time of \c f in seconds.
     718  ///\return The running time of \c f reported by the subprocess.
     719  template<class F>
     720  TimeStamp constrainedRunningTimeTest(F f, double max_time)
     721  {
     722#ifndef LEMON_WIN32
     723    int pipefd[2];
     724    if (pipe(pipefd) == -1) {
     725      throw TimeMeasureError();
     726    }
     727
     728    pid_t cpid = fork();
     729    if (cpid == -1) {
     730      close(pipefd[0]);
     731      close(pipefd[1]);
     732      throw TimeMeasureError();
     733    }
     734
     735    if (cpid == 0) {
     736      close(pipefd[0]);
     737      try {
     738        Timer t;
     739        f();
     740        TimeStamp ts = t;
     741        bool success = true;
     742        _time_measure_bits::write_full(pipefd[1], &success, sizeof(success));
     743        _time_measure_bits::write_full(pipefd[1], &ts, sizeof(ts));
     744      } catch (const std::exception& e) {
     745        const char* message = e.what();
     746        size_t len = strlen(message);
     747        bool success = false;
     748        _time_measure_bits::write_full(pipefd[1], &success, sizeof(success));
     749        _time_measure_bits::write_full(pipefd[1], &len, sizeof(len));
     750        _time_measure_bits::write_full(pipefd[1], message, len);
     751      } catch (...) {
     752        static const char* message = "Unknown exception";
     753        size_t len = strlen(message);
     754        bool success = false;
     755        _time_measure_bits::write_full(pipefd[1], &success, sizeof(bool));
     756        _time_measure_bits::write_full(pipefd[1], &len, sizeof(len));
     757        _time_measure_bits::write_full(pipefd[1], message, len);
     758      }
     759      close(pipefd[1]);
     760      _exit(0);
     761    } else {
     762      close(pipefd[1]);
     763
     764      fd_set rfds;
     765      FD_ZERO(&rfds);
     766      FD_SET(pipefd[0], &rfds);
     767
     768      double sec_int, sec_frac;
     769      sec_int = modf(max_time, &sec_frac);
     770      struct timeval tv;
     771      tv.tv_sec = sec_int;
     772      tv.tv_usec = sec_frac * 1000000;
     773
     774      int sel = select(pipefd[0] + 1, &rfds, NULL, NULL, &tv);
     775
     776      if (sel < -1) {
     777        close(pipefd[0]);
     778        kill(cpid, SIGKILL);
     779        throw TimeMeasureError();
     780      }
     781
     782      if (sel == 0) {
     783        close(pipefd[0]);
     784        kill(cpid, SIGKILL);
     785        throw TimeoutException();
     786      } else {
     787        bool success = false;
     788        _time_measure_bits::read_full(pipefd[0], &success, sizeof(bool));
     789        if (success) {
     790          TimeStamp ts;
     791          _time_measure_bits::read_full(pipefd[0], &ts, sizeof(ts));
     792          close(pipefd[0]);
     793          return ts;
     794        } else {
     795          size_t len;
     796          _time_measure_bits::read_full(pipefd[0], &len, sizeof(len));
     797          std::vector<char> buffer(len);
     798          _time_measure_bits::read_full(pipefd[0], buffer.data(), len);
     799          throw ExecutionException(buffer.data(), len);
     800        }
     801      }
     802    }
     803#else
     804    throw TimeMeasureError();
     805#endif
     806  }
     807
     808
    607809  /// @}
    608810
    609811
  • test/time_measure_test.cc

    diff -r 8c567e298d7f -r 7a1a282efbb4 test/time_measure_test.cc
    a b  
    1919#include <lemon/time_measure.h>
    2020#include <lemon/concept_check.h>
    2121
     22#include "test_tools.h"
     23
    2224using namespace lemon;
    2325
    2426void f()
     
    3941    }
    4042}
    4143
     44void h() {
     45  while (true) {}
     46}
     47
     48void i() {
     49  throw std::exception();
     50}
     51
    4252int main()
    4353{
    4454  Timer T;
     
    5666  std::cout << t << " (" << n << " tests)\n";
    5767  std::cout << "Total: " << full << "\n";
    5868
     69#ifndef LEMON_WIN32
     70  t=constrainedRunningTimeTest(f, 1);
     71  std::cout << t << std::endl;
     72
     73  t=constrainedRunningTimeTest(g, 1);
     74  std::cout << t << std::endl;
     75
     76  T.restart();
     77  bool timed_out = false;
     78  try {
     79    t=constrainedRunningTimeTest(h, 1);
     80  } catch (TimeoutException& e) {
     81    std::cout << e.what() << std::endl;
     82    timed_out = true;
     83  }
     84  check(timed_out, "Infinite loop has to time out.");
     85  std::cout << T << std::endl;
     86
     87  T.restart();
     88  bool execution_failed = false;
     89  try {
     90    t=constrainedRunningTimeTest(i, 1);
     91  } catch (ExecutionException& e) {
     92    std::cout << e.what() << std::endl;
     93    execution_failed = true;
     94  }
     95  check(execution_failed, "Exception during the function execution.");
     96  std::cout << T << std::endl;
     97#endif
     98
    5999  return 0;
    60100}