int main(void) { pthread_attr_t attr; pthread_t th; struct params p; int ret; unsigned int i; ret = set_affinity_single(); if (ret) { n_threads = get_ncpu(); if (n_threads == -1) { printf("Cannot get number of CPUs\n"); return PTS_UNRESOLVED; } printf("INFO: Affinity not supported, running %i threads.\n", n_threads); } else { printf("INFO: Affinity works, will use only one thread.\n"); n_threads = 1; } for (i = 0; i < ARRAY_SIZE(tcases); i++) { p.sched_policy = tcases[i].sched_policy; p.sched_priority = get_prio(&tcases[i]); init_attr(&attr, p.sched_policy, p.sched_priority); printf("INFO: Testing %s prio %i\n", sched_policy_name(p.sched_policy), p.sched_priority); ret = pthread_create(&th, &attr, do_test, &p); if (ret) { fprintf(stderr, "pthread_create(): %s\n", strerror(ret)); return PTS_UNRESOLVED; } pthread_join(th, NULL); pthread_attr_destroy(&attr); } printf("Test PASSED\n"); return 0; }
/* We hold the allocation lock. */ void GC_thr_init(void) { # ifndef GC_DARWIN_THREADS int dummy; # endif GC_thread t; if (GC_thr_initialized) return; GC_thr_initialized = TRUE; # ifdef HANDLE_FORK /* Prepare for a possible fork. */ pthread_atfork(GC_fork_prepare_proc, GC_fork_parent_proc, GC_fork_child_proc); # endif /* HANDLE_FORK */ # if defined(INCLUDE_LINUX_THREAD_DESCR) /* Explicitly register the region including the address */ /* of a thread local variable. This should include thread */ /* locals for the main thread, except for those allocated */ /* in response to dlopen calls. */ { ptr_t thread_local_addr = (ptr_t)(&dummy_thread_local); ptr_t main_thread_start, main_thread_end; if (!GC_enclosing_mapping(thread_local_addr, &main_thread_start, &main_thread_end)) { ABORT("Failed to find mapping for main thread thread locals"); } GC_add_roots_inner(main_thread_start, main_thread_end, FALSE); } # endif /* Add the initial thread, so we can stop it. */ t = GC_new_thread(pthread_self()); # ifdef GC_DARWIN_THREADS t -> stop_info.mach_thread = mach_thread_self(); # else t -> stop_info.stack_ptr = (ptr_t)(&dummy); # endif t -> flags = DETACHED | MAIN_THREAD; GC_stop_init(); /* Set GC_nprocs. */ { char * nprocs_string = GETENV("GC_NPROCS"); GC_nprocs = -1; if (nprocs_string != NULL) GC_nprocs = atoi(nprocs_string); } if (GC_nprocs <= 0) { # if defined(GC_HPUX_THREADS) GC_nprocs = pthread_num_processors_np(); # endif # if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) \ || defined(GC_SOLARIS_THREADS) || defined(GC_GNU_THREADS) GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN); if (GC_nprocs <= 0) GC_nprocs = 1; # endif # if defined(GC_IRIX_THREADS) GC_nprocs = sysconf(_SC_NPROC_ONLN); if (GC_nprocs <= 0) GC_nprocs = 1; # endif # if defined(GC_NETBSD_THREADS) GC_nprocs = get_ncpu(); # endif # if defined(GC_OPENBSD_THREADS) GC_nprocs = 1; # endif # if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS) int ncpus = 1; size_t len = sizeof(ncpus); sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0);
int main(int argc, char **argv) { int c; int sts; int samples; int pauseFlag = 0; int lines = 0; char *source; const char *host; info_t info; /* values to report each sample */ char timebuf[26]; /* for pmCtime result */ setlinebuf(stdout); while ((c = pmGetOptions(argc, argv, &opts)) != EOF) { switch (c) { case 'P': pauseFlag++; break; default: opts.errors++; break; } } if (pauseFlag && opts.context != PM_CONTEXT_ARCHIVE) { pmprintf("%s: pause can only be used with archives\n", pmProgname); opts.errors++; } if (opts.errors || opts.optind < argc - 1) { pmUsageMessage(&opts); exit(1); } if (opts.context == PM_CONTEXT_ARCHIVE) { source = opts.archives[0]; } else if (opts.context == PM_CONTEXT_HOST) { source = opts.hosts[0]; } else { opts.context = PM_CONTEXT_HOST; source = "local:"; } if ((sts = c = pmNewContext(opts.context, source)) < 0) { if (opts.context == PM_CONTEXT_HOST) fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n", pmProgname, source, pmErrStr(sts)); else fprintf(stderr, "%s: Cannot open archive \"%s\": %s\n", pmProgname, source, pmErrStr(sts)); exit(1); } /* complete TZ and time window option (origin) setup */ if (pmGetContextOptions(c, &opts)) { pmflush(); exit(1); } host = pmGetContextHostName(c); ncpu = get_ncpu(); if ((opts.context == PM_CONTEXT_ARCHIVE) && (opts.start.tv_sec != 0 || opts.start.tv_usec != 0)) { if ((sts = pmSetMode(PM_MODE_FORW, &opts.start, 0)) < 0) { fprintf(stderr, "%s: pmSetMode failed: %s\n", pmProgname, pmErrStr(sts)); exit(1); } } get_sample(&info); /* set a default sampling interval if none has been requested */ if (opts.interval.tv_sec == 0 && opts.interval.tv_usec == 0) opts.interval.tv_sec = 5; /* set sampling loop termination via the command line options */ samples = opts.samples ? opts.samples : -1; while (samples == -1 || samples-- > 0) { if (lines % 15 == 0) { if (opts.context == PM_CONTEXT_ARCHIVE) printf("Archive: %s, ", opts.archives[0]); printf("Host: %s, %d cpu(s), %s", host, ncpu, pmCtime((const time_t *)&info.timestamp.tv_sec, timebuf)); /* - report format CPU Busy Busy Free Mem Disk Load Average Util CPU Util (Mbytes) IOPS 1 Min 15 Min X.XXX XXX X.XXX XXXXX.XXX XXXXXX XXXX.XX XXXX.XX */ printf(" CPU"); if (ncpu > 1) printf(" Busy Busy"); printf(" Free Mem Disk Load Average\n"); printf(" Util"); if (ncpu > 1) printf(" CPU Util"); printf(" (Mbytes) IOPS 1 Min 15 Min\n"); } if (opts.context != PM_CONTEXT_ARCHIVE || pauseFlag) __pmtimevalSleep(opts.interval); get_sample(&info); printf("%5.2f", info.cpu_util); if (ncpu > 1) printf(" %3d %5.2f", info.peak_cpu, info.peak_cpu_util); printf(" %9.3f", info.freemem); printf(" %6d", info.dkiops); printf(" %7.2f %7.2f\n", info.load1, info.load15); lines++; } exit(0); }
int main(int argc, char **argv) { //argument variables const char *exe = NULL; int perclimit = 0; int exe_ok = 0; int pid_ok = 0; int limit_ok = 0; pid_t pid = 0; int include_children = 0; //get program name char *p = (char*)memrchr(argv[0], (unsigned int)'/', strlen(argv[0])); program_name = p==NULL ? argv[0] : (p+1); //get current pid cpulimit_pid = getpid(); //get cpu count NCPU = get_ncpu(); //parse arguments int next_option; int option_index = 0; //A string listing valid short options letters const char* short_options = "+p:e:l:vzih"; //An array describing valid long options const struct option long_options[] = { { "pid", required_argument, NULL, 'p' }, { "exe", required_argument, NULL, 'e' }, { "limit", required_argument, NULL, 'l' }, { "verbose", no_argument, NULL, 'v' }, { "lazy", no_argument, NULL, 'z' }, { "include-children", no_argument, NULL, 'i' }, { "help", no_argument, NULL, 'h' }, { 0, 0, 0, 0 } }; do { next_option = getopt_long(argc, argv, short_options,long_options, &option_index); switch(next_option) { case 'p': pid = atoi(optarg); pid_ok = 1; break; case 'e': exe = optarg; exe_ok = 1; break; case 'l': perclimit = atoi(optarg); limit_ok = 1; break; case 'v': verbose = 1; break; case 'z': lazy = 1; break; case 'i': include_children = 1; break; case 'h': print_usage(stdout, 1); break; case '?': print_usage(stderr, 1); break; case -1: break; default: abort(); } } while(next_option != -1); if (pid_ok && (pid <= 1 || pid >= get_pid_max())) { fprintf(stderr,"Error: Invalid value for argument PID\n"); print_usage(stderr, 1); exit(1); } if (pid != 0) { lazy = 1; } if (!limit_ok) { fprintf(stderr,"Error: You must specify a cpu limit percentage\n"); print_usage(stderr, 1); exit(1); } double limit = perclimit / 100.0; if (limit<0 || limit >NCPU) { fprintf(stderr,"Error: limit must be in the range 0-%d00\n", NCPU); print_usage(stderr, 1); exit(1); } int command_mode = optind < argc; if (exe_ok + pid_ok + command_mode == 0) { fprintf(stderr,"Error: You must specify one target process, either by name, pid, or command line\n"); print_usage(stderr, 1); exit(1); } if (exe_ok + pid_ok + command_mode > 1) { fprintf(stderr,"Error: You must specify exactly one target process, either by name, pid, or command line\n"); print_usage(stderr, 1); exit(1); } //all arguments are ok! signal(SIGINT, quit); signal(SIGTERM, quit); //print the number of available cpu if (verbose) printf("%d cpu detected\n", NCPU); if (command_mode) { int i; //executable file const char *cmd = argv[optind]; //command line arguments char **cmd_args = (char**)malloc((argc-optind + 1) * sizeof(char*)); if (cmd_args==NULL) exit(2); for (i=0; i<argc-optind; i++) { cmd_args[i] = argv[i+optind]; } cmd_args[i] = NULL; if (verbose) { printf("Running command: '%s", cmd); for (i=1; i<argc-optind; i++) { printf(" %s", cmd_args[i]); } printf("'\n"); } int child = fork(); if (child < 0) { exit(EXIT_FAILURE); } else if (child == 0) { //target process code int ret = execvp(cmd, cmd_args); //if we are here there was an error, show it perror("Error"); exit(ret); } else { //parent code free(cmd_args); int limiter = fork(); if (limiter < 0) { exit(EXIT_FAILURE); } else if (limiter > 0) { //parent int status_process; int status_limiter; waitpid(child, &status_process, 0); waitpid(limiter, &status_limiter, 0); if (WIFEXITED(status_process)) { if (verbose) printf("Process %d terminated with exit status %d\n", child, (int)WEXITSTATUS(status_process)); exit(WEXITSTATUS(status_process)); } printf("Process %d terminated abnormally\n", child); exit(status_process); } else { //limiter code if (verbose) printf("Limiting process %d\n",child); limit_process(child, limit, include_children); exit(0); } } } while(1) { //look for the target process..or wait for it pid_t ret = 0; if (pid_ok) { //search by pid ret = find_process_by_pid(pid); if (ret == 0) { printf("No process found\n"); } else if (ret < 0) { printf("Process found but you aren't allowed to control it\n"); } } else { //search by file or path name ret = find_process_by_name(exe); if (ret == 0) { printf("No process found\n"); } else if (ret < 0) { printf("Process found but you aren't allowed to control it\n"); } else { pid = ret; } } if (ret > 0) { if (ret == cpulimit_pid) { printf("Target process %d is cpulimit itself! Aborting because it makes no sense\n", ret); exit(1); } printf("Process %d found\n", pid); //control limit_process(pid, limit, include_children); } if (lazy) break; sleep(2); }; exit(0); }
int main() { int i, ncpu; int *child_pid; pthread_t tid, tid_runner; void *tmpresult; long result; pthread_attr_t attr; struct sched_param param; int thread_cpu; ncpu = get_ncpu(); if (ncpu == -1) { printf("Can not get the number of CPUs of your machines.\n"); return PTS_UNRESOLVED; } printf("System has %d processors\n", ncpu); param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 1; if (sched_setscheduler(getpid(), SCHED_FIFO, ¶m) != 0) { if (errno == EPERM) { printf("This process does not have the permission to set its own scheduling policy.\nTry to launch this test as root.\n"); return PTS_UNRESOLVED; } perror("An error occurs when calling sched_setscheduler()"); return PTS_UNRESOLVED; } child_pid = malloc((ncpu-1)*sizeof(int)); for (i=0; i<ncpu-1; i++) { child_pid[i] = fork(); if (child_pid[i] == -1) { perror("An error occurs when calling fork()"); return PTS_UNRESOLVED; } else if (child_pid[i] == 0) { busy_process(i); printf("This code should not be executed.\n"); return PTS_UNRESOLVED; } } pthread_attr_init(&attr); pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); thread_cpu = ncpu -1; if (pthread_create(&tid, &attr, busy_thread, &thread_cpu) != 0) { perror("An error occurs when calling pthread_create()"); return PTS_UNRESOLVED; } if (pthread_create(&tid_runner, &attr, runner, &thread_cpu) != 0) { perror("An error occurs when calling pthread_create()"); return PTS_UNRESOLVED; } if (pthread_join(tid_runner, &tmpresult) != 0) { perror("An error occurs when calling pthread_join()"); return PTS_UNRESOLVED; } for (i=0; i<ncpu-1; i++) waitpid(child_pid[i], NULL, 0); result = (long)tmpresult; if (result) { printf("A thread does not relinquish the processor.\n"); return PTS_FAIL; } printf("Test PASSED\n"); return PTS_PASS; }
int main(){ int child_count, i; struct sched_param param; int *child_pid; float ratio = 0.0; nb_child = get_ncpu(); if(nb_child == -1) { printf("Can not get the number of CPUs of your machine.\n"); return PTS_UNRESOLVED; } child_pid = malloc(nb_child); param.sched_priority = ( sched_get_priority_min(SCHED_RR) + sched_get_priority_max(SCHED_RR) ) / 2; if(sched_setscheduler(getpid(), SCHED_RR, ¶m) == -1){ if(errno == EPERM){ printf("This process does not have the permission to set its own scheduling policy.\nTry to launch this test as root\n"); } else { perror("An error occurs when calling sched_setscheduler()"); } return PTS_UNRESOLVED; } if(signal(SIGTERM, sigterm_handler) == SIG_ERR){ perror("An error occurs when calling signal()"); return PTS_UNRESOLVED; } pipe(the_pipe); for(i=0; i<nb_child; i++) { child_pid[i] = fork(); if(child_pid[i] == -1){ perror("An error occurs when calling fork()"); return PTS_UNRESOLVED; } else if (child_pid[i] == 0){ child_process(i); printf("This code should not be executed.\n"); return PTS_UNRESOLVED; } } param.sched_priority = sched_get_priority_max(SCHED_RR); if(sched_setparam(0, ¶m) != 0) { perror("An error occurs when calling sched_setparam()"); return PTS_UNRESOLVED; } close(STDIN); close(the_pipe[1]); dup2(the_pipe[0],STDIN); close(the_pipe[0]); for(i=0; i<NB_LOOP; i++){ count++; } if(kill(child_pid[nb_child-1], SIGTERM) != 0) { perror("An error occurs when calling kill()"); return PTS_UNRESOLVED; } param.sched_priority = sched_get_priority_min(SCHED_RR); if(sched_setparam(0, ¶m) != 0) { perror("An error occurs when calling sched_setparam()"); return PTS_UNRESOLVED; } while(scanf("*%i*",&child_count) == 0) sched_yield(); for(i=0; i<nb_child-1; i++) { if(kill(child_pid[i], SIGKILL) != 0) { perror("An error occurs when calling kill()"); return PTS_UNRESOLVED; } } if(child_count) ratio = (float)count / (float)child_count; if(child_count == 0 || ratio >= ACCEPTABLE_RATIO) { printf("Test PASSED\n"); return PTS_PASS; } else if(ratio <= (1/ACCEPTABLE_RATIO)) { printf("Higher numerical values for the priority represent the lower priorities.\n"); return PTS_FAIL; } else { printf("The difference between the processes is not representative.\n"); return PTS_UNRESOLVED; } }
T_DECL(thread_request_32848402, "repro for rdar://32848402") { dispatch_queue_attr_t bg_attr, in_attr; bg_attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_BACKGROUND, 0); in_attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_USER_INITIATED, 0); dispatch_queue_t a = dispatch_queue_create_with_target("in", in_attr, NULL); dispatch_queue_t b = dispatch_queue_create_with_target("bg", bg_attr, NULL); end_spin = clock_gettime_nsec_np(CLOCK_MONOTONIC) + 2 * NSEC_PER_SEC; dispatch_async_f(a, (void *)0, spin_and_pause); long n_threads = MIN((long)get_ncpu(), pthread_qos_max_parallelism(QOS_CLASS_BACKGROUND, 0)); for (long i = 1; i < n_threads; i++) { dispatch_async_f(b, (void *)i, spin); } dispatch_async(b, ^{ T_PASS("The NCPU+1-nth block got scheduled"); T_END; }); sleep(10); T_FAIL("The NCPU+1-nth block didn't get scheduled"); }
int main(void) { int *child_pid, oldcount, newcount, shm_id, i, j; struct sched_param param; key_t key; nb_cpu = get_ncpu(); if (nb_cpu == -1) { printf("Can not get the number of CPUs of your machines.\n"); return PTS_UNRESOLVED; } child_pid = malloc(nb_cpu * sizeof(int)); key = ftok("conformance/interfaces/sched_setparam/9-1.c",1234); shm_id = shmget(key, sizeof(int), IPC_CREAT|0600); if (shm_id < 0) { perror("An error occurs when calling shmget()"); return PTS_UNRESOLVED; } shmptr = shmat(shm_id, 0, 0); if (shmptr == (void*)-1) { perror("An error occurs when calling shmat()"); return PTS_UNRESOLVED; } *shmptr = 0; param.sched_priority = sched_get_priority_min(SCHED_FIFO); if (sched_setscheduler(getpid(), SCHED_FIFO, ¶m) != 0) { if (errno == EPERM) { printf("This process does not have the permission to set its own scheduling " "parameter.\nTry to launch this test as root\n"); } else { perror("An error occurs when calling sched_setscheduler()"); } return PTS_UNRESOLVED; } for (i = 0; i < (nb_cpu - 1); i++) { child_pid[i] = fork(); if (child_pid[i] == -1) { perror("An error occurs when calling fork()"); for (j = 0; j < i; j++) { kill(child_pid[j], SIGTERM); } return PTS_UNRESOLVED; } else if (child_pid[i] == 0) { child_process(); printf("This code should not be executed.\n"); return PTS_UNRESOLVED; } } child_pid[i] = fork(); if (child_pid[i] == -1) { perror("An error occurs when calling fork()"); for (j = 0; j < i; j++) { kill(child_pid[j], SIGTERM); } return PTS_UNRESOLVED; } else if (child_pid[i] == 0) { test_process(); printf("This code should not be executed.\n"); return PTS_UNRESOLVED; } sleep(1); param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2; oldcount = *shmptr; if (sched_setparam(child_pid[i], ¶m) != 0) { perror("An error occurs when calling sched_setparam()"); kill_children(child_pid); return PTS_UNRESOLVED; } newcount = *shmptr; if (newcount == oldcount) { printf("The target process does not preempt the calling process\n"); kill_children(child_pid); return PTS_FAIL; } printf("Test PASSED\n"); kill_children(child_pid); return PTS_PASS; }
int main() { int child_count, i; struct sched_param param; int *child_pid; float ratio; /* Only use a single CPU and one child process when set_affinity is availaible.It's because no matter what value of the counter is set to, There is no guarantee that the LOOP of the child can be certainly big enough on any device at any time. */ int rc = set_affinity(0); if (rc) { nb_child = get_ncpu(); if (nb_child == -1) { printf("Can not get the number of" "CPUs of your machine.\n"); return PTS_UNRESOLVED; } } else { nb_child = 1; } child_pid = malloc(nb_child * sizeof(int)); if (child_pid == NULL) { printf("malloc failed\n"); return PTS_UNRESOLVED; } param.sched_priority = (sched_get_priority_min(SCHED_RR) + sched_get_priority_max(SCHED_RR)) / 2; if (sched_setscheduler(getpid(), SCHED_RR, ¶m) == -1) { if (errno == EPERM) { printf("This process does not have the permission to set its own scheduling policy.\nTry to launch this test as root\n"); } else { perror("An error occurs when calling sched_setscheduler()"); } return PTS_UNRESOLVED; } if (signal(SIGTERM, sigterm_handler) == SIG_ERR) { perror("An error occurs when calling signal()"); return PTS_UNRESOLVED; } pipe(the_pipe); for (i=0; i<nb_child; i++) { child_pid[i] = fork(); if (child_pid[i] == -1) { perror("An error occurs when calling fork()"); return PTS_UNRESOLVED; } else if (child_pid[i] == 0) { child_process(i); printf("This code should not be executed.\n"); return PTS_UNRESOLVED; } } param.sched_priority = sched_get_priority_max(SCHED_RR); if (sched_setparam(0, ¶m) != 0) { perror("An error occurs when calling sched_setparam()"); return PTS_UNRESOLVED; } close(STDIN); close(the_pipe[1]); dup2(the_pipe[0],STDIN); close(the_pipe[0]); for (i=0; i<NB_LOOP; i++) { count++; } if (kill(child_pid[nb_child-1], SIGTERM) != 0) { perror("An error occurs when calling kill()"); return PTS_UNRESOLVED; } param.sched_priority = sched_get_priority_min(SCHED_RR); if (sched_setparam(0, ¶m) != 0) { perror("An error occurs when calling sched_setparam()"); return PTS_UNRESOLVED; } while (scanf("*%i*",&child_count) == 0) sched_yield(); for (i = 0; i < (nb_child-1); i++) { if (kill(child_pid[i], SIGKILL) != 0) { perror("An error occurs when calling kill()"); return PTS_UNRESOLVED; } } if (child_count) ratio = (float)count / (float)child_count; if (child_count == 0 || ratio >= ACCEPTABLE_RATIO) { printf("Test PASSED\n"); return PTS_PASS; } else if (ratio <= (1/ACCEPTABLE_RATIO)) { printf("Higher numerical values for the priority represent the lower priorities.\n"); return PTS_FAIL; } else { printf("The difference between the processes is not representative.\n"); return PTS_UNRESOLVED; } }
int main(int argc, char **argv) { //get program name // char *p=(char*)memrchr(argv[0],(unsigned int)'/',strlen(argv[0])); // program_name = p==NULL?argv[0]:(p+1); program_name = argv[0]; int run_in_background = FALSE; //parse arguments int next_option; /* A string listing valid short options letters. */ const char* short_options="p:e:P:l:c:bqkrvzh"; /* An array describing valid long options. */ const struct option long_options[] = { { "pid", required_argument, NULL, 'p' }, { "exe", required_argument, NULL, 'e' }, { "path", required_argument, NULL, 'P' }, { "limit", required_argument, NULL, 'l' }, { "background", no_argument, NULL, 'b' }, { "quiet", no_argument, NULL, 'q' }, { "verbose", no_argument, NULL, 'v' }, { "lazy", no_argument, NULL, 'z' }, { "help", no_argument, NULL, 'h' }, { "cpu", required_argument, NULL, 'c'}, { NULL, 0, NULL, 0 } }; //argument variables const char *exe=NULL; const char *path=NULL; int perclimit=0; int pid_ok = FALSE; int process_ok = FALSE; int limit_ok = FALSE; int last_known_argument = 0; int kill_process = FALSE; // kill process instead of stopping it int restore_process = FALSE; // restore killed process // struct rlimit maxlimit; NCPU = get_ncpu(); opterr = 0; // avoid unwanted error messages for unknown parameters do { next_option = getopt_long (argc, argv, short_options,long_options, NULL); switch(next_option) { case 'b': run_in_background = TRUE; last_known_argument++; break; case 'p': pid=atoi(optarg); if (pid) // valid PID { pid_ok = TRUE; lazy = TRUE; } last_known_argument += 2; break; case 'e': exe=optarg; process_ok = TRUE; last_known_argument += 2; break; case 'P': path=optarg; process_ok = TRUE; last_known_argument += 2; break; case 'l': perclimit=atoi(optarg); limit_ok = TRUE; last_known_argument += 2; break; case 'c': NCPU = atoi(optarg); last_known_argument += 2; break; case 'k': kill_process = TRUE; last_known_argument++; break; case 'r': restore_process = TRUE; last_known_argument++; break; case 'v': verbose = TRUE; last_known_argument++; break; case 'q': quiet = TRUE; last_known_argument++; break; case 'z': lazy = TRUE; last_known_argument++; break; case 'h': print_usage (stdout, 1); last_known_argument++; break; case 'o': last_known_argument++; next_option = -1; break; case '?': print_usage (stderr, 1); last_known_argument++; break; case -1: break; // default: // abort(); } } while(next_option != -1); // try to launch a program passed on the command line // But only if we do not already have a PID to watch if ( (last_known_argument + 1 < argc) && (pid_ok == FALSE) ) { last_known_argument++; // if we stopped on "--" jump to the next parameter if ( (last_known_argument + 1 < argc) && (! strcmp(argv[last_known_argument], "--") ) ) last_known_argument++; pid_t forked_pid; // try to launch remaining arguments if (verbose) { int index = last_known_argument; printf("Launching %s", argv[index]); for (index = last_known_argument + 1; index < argc; index++) printf(" %s", argv[index]); printf(" with limit %d\n", perclimit); } forked_pid = fork(); if (forked_pid == -1) // error { printf("Failed to launch specified process.\n"); exit(1); } else if (forked_pid == 0) // target child { execvp(argv[last_known_argument], &(argv[last_known_argument]) ); exit(2); } else // parent who will now fork the throttler { pid_t limit_pid; // if we are planning to kill a process, give it // a running head start to avoid death at start-up if (kill_process) sleep(5); limit_pid = fork(); if (limit_pid == 0) // child { pid = forked_pid; // the first child lazy = TRUE; pid_ok = TRUE; if (verbose) printf("Throttling process %d\n", (int) pid); } else // parent exit(0); } /* else if (forked_pid == 0) // child { lazy = TRUE; pid_ok = TRUE; pid = getppid(); if (verbose) printf("Throttling process %d\n", (int) pid); } else // parent { execvp(argv[last_known_argument], &(argv[last_known_argument])); // we should never return exit(2); } */ } // end of launching child process if (!process_ok && !pid_ok) { fprintf(stderr,"Error: You must specify a target process\n"); print_usage (stderr, 1); exit(1); } if ((exe!=NULL && path!=NULL) || (pid_ok && (exe!=NULL || path!=NULL))) { fprintf(stderr,"Error: You must specify exactly one target process\n"); print_usage (stderr, 1); exit(1); } if (!limit_ok) { fprintf(stderr,"Error: You must specify a cpu limit\n"); print_usage (stderr, 1); exit(1); } float limit=perclimit/100.0; if ( (limit <= 0.00) || (limit > NCPU) ) { fprintf(stderr,"Error: limit must be in the range of 1 to %d00\n", NCPU); print_usage (stderr, 1); exit(1); } // check to see if we should fork if (run_in_background) { pid_t process_id; process_id = fork(); if (! process_id) exit(0); else { setsid(); process_id = fork(); if (process_id) exit(0); } } //parameters are all ok! signal(SIGINT,quit); signal(SIGTERM,quit); my_pid = getpid(); if (verbose) printf("%d CPUs detected.\n", NCPU); increase_priority(); /* Instead of all this big block of code to detect and change priority settings, let us just use the increase_priority() function. It is a little more simple and takes a more gradual approach, rather than "all or nothing". -- Jesse if (setpriority(PRIO_PROCESS, my_pid,-20)!=0) { //if that failed, check if we have a limit // by how much we can raise the priority #ifdef RLIMIT_NICE //check if non-root can even make changes // (ifdef because it's only available in linux >= 2.6.13) nice_lim=getpriority(PRIO_PROCESS, my_pid); getrlimit(RLIMIT_NICE, &maxlimit); //if we can do better then current if( (20 - (signed)maxlimit.rlim_cur) < nice_lim && setpriority(PRIO_PROCESS, my_pid, 20 - (signed)maxlimit.rlim_cur)==0 //and it actually works ) { //if we can do better, but not by much, warn about it if( (nice_lim - (20 - (signed)maxlimit.rlim_cur)) < 9) { printf("Warning, can only increase priority by %d.\n", nice_lim - (20 - (signed)maxlimit.rlim_cur)); } //our new limit nice_lim = 20 - (signed)maxlimit.rlim_cur; } else // otherwise don't try to change priority. // The below will also run if it's not possible // for non-root to change priority #endif { printf("Warning: cannot renice.\nTo work better you should run this program as root, or adjust RLIMIT_NICE.\nFor example in /etc/security/limits.conf add a line with: * - nice -10\n\n"); nice_lim=INT_MAX; } } else { nice_lim=-20; } */ //time quantum in microseconds. it's splitted in a working period and a sleeping one int period=100000; struct timespec twork,tsleep; //working and sleeping intervals memset(&twork,0,sizeof(struct timespec)); memset(&tsleep,0,sizeof(struct timespec)); wait_for_process: //look for the target process..or wait for it if (exe != NULL) pid=getpidof(exe); else if (path != NULL) pid=getpidof(path); else waitforpid(pid); //process detected...let's play //init compute_cpu_usage internal stuff compute_cpu_usage(0,0,NULL); //main loop counter int i=0; struct timespec startwork,endwork; long workingtime=0; //last working time in microseconds if (verbose) print_caption(); float pcpu_avg=0; //here we should already have high priority, for time precision while(1) { //estimate how much the controlled process is using the cpu in its working interval struct cpu_usage cu; if (compute_cpu_usage(pid,workingtime,&cu)==-1) { if (!quiet) fprintf(stderr,"Process %d dead!\n",pid); if (lazy) exit(2); //wait until our process appears goto wait_for_process; } //cpu actual usage of process (range 0-1) float pcpu=cu.pcpu; //rate at which we are keeping active the process (range 0-1) float workingrate=cu.workingrate; //adjust work and sleep time slices if (pcpu>0) { twork.tv_nsec=min(period*limit*1000/pcpu*workingrate,period*1000); } else if (pcpu==0) { twork.tv_nsec=period*1000; } else if (pcpu==-1) { //not yet a valid idea of cpu usage pcpu=limit; workingrate=limit; twork.tv_nsec=min(period*limit*1000,period*1000); } tsleep.tv_nsec=period*1000-twork.tv_nsec; //update average usage pcpu_avg=(pcpu_avg*i+pcpu)/(i+1); if (verbose && i%10==0 && i>0) { printf("%0.2f%%\t%6ld us\t%6ld us\t%0.2f%%\n",pcpu*100,twork.tv_nsec/1000,tsleep.tv_nsec/1000,workingrate*100); if (i%200 == 0) print_caption(); } // if (limit<1 && limit>0) { // printf("Comparing %f to %f\n", pcpu, limit); if (pcpu < limit) { // printf("Continue\n"); //resume process if (kill(pid,SIGCONT)!=0) { if (!quiet) fprintf(stderr,"Process %d dead!\n",pid); if (lazy) exit(2); //wait until our process appears goto wait_for_process; } } #ifdef __APPLE_ // OS X does not have clock_gettime, use clock_get_time clock_serv_t cclock; mach_timespec_t mts; host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); clock_get_time(cclock, &mts); mach_port_deallocate(mach_task_self(), cclock); startwork.tv_sec = mts.tv_sec; startwork.tv_nsec = mts.tv_nsec; #else clock_gettime(CLOCK_REALTIME,&startwork); #endif nanosleep(&twork,NULL); //now process is working #ifdef __APPLE__ // OS X does not have clock_gettime, use clock_get_time // clock_serv_t cclock; // mach_timespec_t mts; host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); clock_get_time(cclock, &mts); mach_port_deallocate(mach_task_self(), cclock); endwork.tv_sec = mts.tv_sec; endwork.tv_nsec = mts.tv_nsec; #else clock_gettime(CLOCK_REALTIME,&endwork); #endif workingtime=timediff(&endwork,&startwork); // if (limit<1) { // printf("Checking %f vs %f\n", pcpu, limit); if (pcpu > limit) { // When over our limit we may run into // situations where we want to kill // the offending process, then restart it if (kill_process) { kill(pid, SIGKILL); if (!quiet) fprintf(stderr, "Process %d killed.\n", pid); if ( (lazy) && (! restore_process) ) exit(2); // restart killed process if (restore_process) { pid_t new_process; new_process = fork(); if (new_process == -1) { fprintf(stderr, "Failed to restore killed process.\n"); } else if (new_process == 0) { // child which becomes new process if (verbose) printf("Relaunching %s\n", argv[last_known_argument]); execvp(argv[last_known_argument], &(argv[last_known_argument]) ); } else // parent { // we need to track new process pid = new_process; // avoid killing child process sleep(5); } } } // do not kll process, just throttle it else { // printf("Stop\n"); //stop process, it has worked enough if (kill(pid,SIGSTOP)!=0) { if (!quiet) fprintf(stderr,"Process %d dead!\n", pid); if (lazy) exit(2); //wait until our process appears goto wait_for_process; } nanosleep(&tsleep,NULL); //now process is sleeping } // end of throttle process } // end of process using too much CPU i++; } return 0; }