README.md
Last active
February 28, 2018 15:11
-
-
Save CristianCantoro/c7a8cc7f03c6ccb7e270b45d9f6da712 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ignore executables | |
test_signal | |
test_setitimer | |
# ignore input and output files | |
input.txt | |
output.txt | |
For background see issue #851 @ cms-dev/cms
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <chrono> | |
#include <iostream> | |
#include <unistd.h> | |
#include <csignal> | |
#include <sys/time.h> | |
#include <sys/resource.h> | |
#include "test_itimer.h" | |
using namespace std; | |
/* | |
* Very simple debugger, enabled at compile time with -DDEBUG. | |
* If enabled, it prints on stderr, otherwise it does nothing (it does not | |
* even evaluate the expression on its right-hand side). | |
* | |
* Main ideas taken from: | |
* - C++ enable/disable debug messages of std::couts on the fly | |
* (https://stackoverflow.com/q/3371540/2377454) | |
* - Standard no-op output stream | |
* (https://stackoverflow.com/a/11826787/2377454) | |
*/ | |
#ifdef DEBUG | |
#define debug true | |
#else | |
#define debug false | |
#endif | |
#define debug_logger if (!debug) \ | |
{} \ | |
else \ | |
cerr << "[DEBUG] helpers::" | |
// conversion factor betwen seconds and nanoseconds | |
#define NANOS 1000000000 | |
// signal to handle | |
#define SIGNAL SIGVTALRM | |
#define TIMELIMIT ITIMER_VIRTUAL | |
namespace helpers { | |
long long start_time = -1; | |
volatile sig_atomic_t timeout_flag = false; | |
unsigned const timelimit = 2; // soft limit on CPU time (in seconds) | |
void setup_signal(void); | |
void setup_time_limit(void); | |
static void signal_handler(int signum); | |
} | |
/* | |
* This could be a function factory where and a closure of the signal-handling | |
* function so that we could explicitly pass the output ofstream and close it. | |
* C++ support closures only for lambdas, alas, at the moment we also need | |
* the signal-handling function to be a pointer to a function and lambaa are | |
* a different object that can not be converted. See: | |
* - Passing lambda as function pointer | |
* (https://stackoverflow.com/a/28746827/2377454) | |
*/ | |
void helpers::signal_handler(int signum) { | |
helpers::timeout_flag = true; | |
debug_logger << "signal_handler:\t" << "signal " << signum \ | |
<< " received" << endl; | |
debug_logger << "signal_handler:\t" << "exiting after " \ | |
<< helpers::get_elapsed_time() << " microseconds" << endl; | |
exit(0); | |
} | |
/* | |
* Set function signal_handler() as handler for SIGXCPU using sigaction. See | |
* - https://stackoverflow.com/q/4863420/2377454 | |
* - https://stackoverflow.com/a/17572787/2377454 | |
*/ | |
void helpers::setup_signal() { | |
debug_logger << "set_signal:\t" << "set_signal() called" << endl; | |
struct sigaction new_action; | |
//Set the handler in the new_action struct | |
new_action.sa_handler = signal_handler; | |
// Set to empty the sa_mask. It means that no signal is blocked | |
// while the handler run. | |
sigemptyset(&new_action.sa_mask); | |
// Block the SIGXCPU signal, while the handler run, SIGXCPU is ignored. | |
sigaddset(&new_action.sa_mask, SIGNAL); | |
// Remove any flag from sa_flag | |
new_action.sa_flags = 0; | |
// Set new action | |
sigaction(SIGNAL, &new_action, NULL); | |
if(debug) { | |
struct sigaction tmp; | |
// read the old signal associated to SIGXCPU | |
sigaction(SIGNAL, NULL, &tmp); | |
debug_logger << "set_signal:\t" << "action.sa_handler: " \ | |
<< tmp.sa_handler << endl; | |
} | |
return; | |
} | |
/* | |
* Set soft CPU time limit. | |
* RLIMIT_CPU set teg CPU time limit in seconds.. | |
* See: | |
* - https://www.go4expert.com/articles/ | |
* getrlimit-setrlimit-control-resources-t27477/ | |
* - https://gist.github.com/Leporacanthicus/11086960 | |
*/ | |
void helpers::setup_time_limit(void) { | |
debug_logger << "set_limit:\t\t" << "set_limit() called" << endl; | |
struct itimerval old_limit, new_limit; | |
if (getitimer(TIMELIMIT, &old_limit) != 0) { | |
perror("error calling getitimer()"); | |
exit(EXIT_FAILURE); | |
} | |
debug_logger << "set_limit:\t\t" << "old_limit.it_value.tv_sec: " \ | |
<< old_limit.it_value.tv_sec << endl; | |
debug_logger << "set_limit:\t\t" << "old_limit.it_value.tv_usec: " \ | |
<< old_limit.it_value.tv_usec << endl; | |
new_limit.it_value.tv_sec = helpers::timelimit; | |
new_limit.it_value.tv_usec = 0; | |
new_limit.it_interval.tv_sec = helpers::timelimit; | |
new_limit.it_interval.tv_usec = 0; | |
if (setitimer(TIMELIMIT, &new_limit, &old_limit) != 0) { | |
perror("error calling setitimer()"); | |
exit(EXIT_FAILURE); | |
} | |
if (debug) { | |
struct itimerval tmp; | |
getitimer(TIMELIMIT, &tmp); | |
debug_logger << "set_limit:\t\t" << "current limit:" << endl; | |
debug_logger << "set_limit:\t\t" << "tmp.it_value.tv_sec: " \ | |
<< tmp.it_value.tv_sec << endl; | |
debug_logger << "set_limit:\t\t" << "tmp.it_value.tv_usec: " \ | |
<< tmp.it_value.tv_usec << endl; | |
debug_logger << "set_limit:\t\t" << "tmp.it_interval.tv_sec: " \ | |
<< tmp.it_interval.tv_sec << endl; | |
debug_logger << "set_limit:\t\t" << "tmp.it_interval.tv_usec: " \ | |
<< tmp.it_interval.tv_usec << endl; | |
} | |
return; | |
} | |
void helpers::setup(void) { | |
struct timespec start; | |
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start)) { | |
exit(EXIT_FAILURE); | |
} | |
start_time = start.tv_sec*NANOS + start.tv_nsec; | |
setup_signal(); | |
setup_time_limit(); | |
return; | |
} | |
long long helpers::get_elapsed_time(void) { | |
struct timespec current; | |
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ¤t)) { | |
exit(EXIT_FAILURE); | |
} | |
long long current_time = current.tv_sec*NANOS + current.tv_nsec; | |
long long elapsed_micro = (current_time - start_time)/1000 + \ | |
((current_time - start_time) % 1000 >= 500); | |
return elapsed_micro; | |
} | |
bool helpers::has_reached_timeout(void) { | |
return helpers::timeout_flag; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef HELPERS_HPP | |
#define HELPERS_HPP | |
using namespace std; | |
namespace helpers { | |
long long get_elapsed_time(void); | |
bool has_reached_timeout(void); | |
void setup(void); | |
} | |
#endif | |
#pragma once |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Test program for signal handling on CMS. | |
* | |
* Compile with: | |
* /usr/bin/g++ [-DDEBUG] -Wall -std=c++11 -O2 -pipe -static -s \ | |
* -o test_signal test_signal.cpp helpers.cpp | |
* | |
* The option -DDEBUG activates some debug logging in the helpers library. | |
*/ | |
#include <iostream> | |
#include <fstream> | |
#include <random> | |
#include "test_itimer.h" | |
using namespace std; | |
namespace { | |
unsigned const minrand = 5; | |
unsigned const maxrand = 20; | |
int const numcycles = 5000000; | |
}; | |
int main() { | |
helpers::setup(); | |
ifstream in("input.txt"); | |
in.close(); | |
ofstream out("output.txt"); | |
random_device rd; | |
mt19937 eng(rd()); | |
uniform_int_distribution<> distr(minrand, maxrand); | |
int i = 0; | |
while(!helpers::has_reached_timeout()) { | |
int nmsec; | |
for(int n=0; n<numcycles; n++) { | |
nmsec = distr(eng); | |
} | |
/* | |
for (int i=0; i<10; i++) { | |
for(int n=0; n<250000; n++) { | |
cout << "x" << '\b'; | |
} | |
cout << '.'; | |
} | |
cout << "->" << '\t'; | |
*/ | |
cout << "i: " << i << "\t- nmsec: " << nmsec << "\t- "; | |
out << "i: " << i << "\t- nmsec: " << nmsec << "\t- "; | |
cout << "program has been running for " << \ | |
helpers::get_elapsed_time() << " microseconds" << endl; | |
out << "program has been running for " << \ | |
helpers::get_elapsed_time() << " microseconds" << endl; | |
i++; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment