in OpsWorks/sample-cookbooks/cpulimit-ruby/files/default/cpulimit-master/src/cpulimit.c [173:299]
void limit_process(pid_t pid, double limit, int include_children)
{
//slice of the slot in which the process is allowed to run
struct timespec twork;
//slice of the slot in which the process is stopped
struct timespec tsleep;
//when the last twork has started
struct timeval startwork;
//when the last twork has finished
struct timeval endwork;
//initialization
memset(&twork, 0, sizeof(struct timespec));
memset(&tsleep, 0, sizeof(struct timespec));
memset(&startwork, 0, sizeof(struct timeval));
memset(&endwork, 0, sizeof(struct timeval));
//last working time in microseconds
unsigned long workingtime = 0;
//generic list item
struct list_node *node;
//counter
int c = 0;
//get a better priority
increase_priority();
//build the family
init_process_group(&pgroup, pid, include_children);
if (verbose) printf("Members in the process group owned by %d: %d\n", pgroup.target_pid, pgroup.proclist->count);
//rate at which we are keeping active the processes (range 0-1)
//1 means that the process are using all the twork slice
double workingrate = -1;
while(1) {
update_process_group(&pgroup);
if (pgroup.proclist->count==0) {
if (verbose) printf("No more processes.\n");
break;
}
//total cpu actual usage (range 0-1)
//1 means that the processes are using 100% cpu
double pcpu = -1;
//estimate how much the controlled processes are using the cpu in the working interval
for (node = pgroup.proclist->first; node != NULL; node = node->next) {
struct process *proc = (struct process*)(node->data);
if (proc->cpu_usage < 0) {
continue;
}
if (pcpu < 0) pcpu = 0;
pcpu += proc->cpu_usage;
}
//adjust work and sleep time slices
if (pcpu < 0) {
//it's the 1st cycle, initialize workingrate
pcpu = limit;
workingrate = limit;
twork.tv_nsec = TIME_SLOT * limit * 1000;
}
else {
//adjust workingrate
workingrate = MIN(workingrate / pcpu * limit, 1);
twork.tv_nsec = TIME_SLOT * 1000 * workingrate;
}
tsleep.tv_nsec = TIME_SLOT * 1000 - twork.tv_nsec;
if (verbose) {
if (c%200==0)
printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n");
if (c%10==0 && c>0)
printf("%0.2lf%%\t%6ld us\t%6ld us\t%0.2lf%%\n", pcpu*100, twork.tv_nsec/1000, tsleep.tv_nsec/1000, workingrate*100);
}
//resume processes
node = pgroup.proclist->first;
while (node != NULL)
{
struct list_node *next_node = node->next;
struct process *proc = (struct process*)(node->data);
if (kill(proc->pid,SIGCONT) != 0) {
//process is dead, remove it from family
if (verbose) fprintf(stderr, "SIGCONT failed. Process %d dead!\n", proc->pid);
//remove process from group
delete_node(pgroup.proclist, node);
remove_process(&pgroup, proc->pid);
}
node = next_node;
}
//now processes are free to run (same working slice for all)
gettimeofday(&startwork, NULL);
nanosleep(&twork, NULL);
gettimeofday(&endwork, NULL);
workingtime = timediff(&endwork, &startwork);
long delay = workingtime - twork.tv_nsec/1000;
if (c>0 && delay>10000) {
//delay is too much! signal to user?
//fprintf(stderr, "%d %ld us\n", c, delay);
}
if (tsleep.tv_nsec>0) {
//stop processes only if tsleep>0
node = pgroup.proclist->first;
while (node != NULL)
{
struct list_node *next_node = node->next;
struct process *proc = (struct process*)(node->data);
if (kill(proc->pid,SIGSTOP)!=0) {
//process is dead, remove it from family
if (verbose) fprintf(stderr, "SIGSTOP failed. Process %d dead!\n", proc->pid);
//remove process from group
delete_node(pgroup.proclist, node);
remove_process(&pgroup, proc->pid);
}
node = next_node;
}
//now the processes are sleeping
nanosleep(&tsleep,NULL);
}
c++;
}
close_process_group(&pgroup);
}