1#define TARGET_OS_EMBEDDED 1
2#include <stdio.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <time.h>
6#include <pthread.h>
7#include <libgen.h>
8#include <sys/types.h>
9#include <sys/sysctl.h>
10
11#import <Foundation/Foundation.h>
12
13#include <mach/message.h>
14#include <libproc_internal.h>
15
16#define MAX_THREADS 100
17
18char *pname;
19
20int pid;
21
22int exit_after = -1;
23
24int percentage = 95, interval = 600;
25
26int wakemon_rate = 150;
27
28int limit = 0; // Worker thread should apply per-thread limit to self?
29int limit_period = 5000;
30
31void usage(void) {
32	printf("usage: monitor_stress [ -c nthreads ] [ -w nthreads ] \n");
33	printf("\t-c: number of CPU usage monitor stress threads to use (default: 2\n");
34	printf("\t-w: number of wakeups monitor stress threads to use (default: 0\n");
35	printf("\t-e: exit after this many seconds (default: run forever)\n");
36	printf("\t-p: act on this pid (default: self)\n");
37}
38
39void *perthr_limit_thread(void *arg)
40{
41	int percent = 90, refill_period = 30; // time unit is milliseconds
42	int err;
43	int cpupercent;
44
45top:
46	cpupercent = percent | (refill_period << 8);
47    
48    	if ((err = sysctlbyname("kern.setthread_cpupercent", 0, 0,
49    		&cpupercent, sizeof (int))) != 0) {
50		printf("kern.setthread_cpupercent: error %d\n", err);
51		exit(1);
52	}
53	goto top;
54}
55
56void *cpumon_stress_thread(void *arg)
57{
58top:
59	if (proc_set_cpumon_params(pid, percentage, interval) != 0) {
60		perror("proc_set_cpumon_params");
61		exit(1);
62	}
63	if (proc_disable_cpumon(pid) != 0) {
64		perror("proc_disable_cpumon");
65		exit(1);
66	}
67	goto top;
68}
69
70void *wakemon_stress_thread(void *arg)
71{
72top:
73	if (proc_set_wakemon_params(pid, wakemon_rate, 0) != 0) {
74		perror("proc_set_wakemon_params");
75		exit(1);
76	}
77	if (proc_disable_wakemon(pid) != 0) {
78		perror("proc_disable_wakemon");
79		exit(1);
80	}
81	goto top;
82}
83
84void *exit_thread(void *arg) 
85{
86	sleep(exit_after);
87	printf("...exiting.\n");
88	exit(0);
89
90	return (NULL);
91}
92
93int main(int argc, char *argv[])
94{
95	int ch;
96	int i = 0;
97	int cpumon_threads = 2;
98	int wakemon_threads = 0;
99    
100	pthread_t thr_id;
101	
102	pname = basename(argv[0]);
103	pid = getpid();
104    
105	while ((ch = getopt(argc, argv, "c:w:e:p:h?")) != -1) {
106		switch (ch) {
107		case 'c':
108			cpumon_threads = atoi(optarg);
109			break;
110		case 'w':
111			wakemon_threads = atoi(optarg);
112			break;
113		case 'e':
114			exit_after = atoi(optarg);
115			break;
116		case 'p':
117			pid = atoi(optarg);
118			break;
119		case 'h':
120		default:
121			usage();
122			exit(1);
123
124		}
125	}
126	argc -= optind;
127	argv += optind;
128
129	if (argc != 0) {
130		usage();
131		exit(1);
132	}
133
134	if ((cpumon_threads <= 0) || (cpumon_threads > MAX_THREADS) ||
135	    (wakemon_threads < 0) || (wakemon_threads > MAX_THREADS)) {
136		printf("%s: %d/%d threads too many (max is %d)\n", pname,
137			cpumon_threads, wakemon_threads, MAX_THREADS);
138		exit(1);
139	}
140
141	printf("%s: creating %d CPU usage monitor stress threads (1 will be main thread), ", pname, cpumon_threads);
142	if (wakemon_threads > 0) {
143		printf( "%d wakeups monitor stress threads, ", wakemon_threads);
144	}
145	printf("and 1 per-thread CPU limit stress thread.\n");
146
147	if (pthread_create(&thr_id, NULL, perthr_limit_thread, NULL) != 0) {
148     		perror("pthread_create");
149     		exit(1);
150	}
151
152	for (i = 0; i < wakemon_threads; i++) {
153		if (pthread_create(&thr_id, NULL, wakemon_stress_thread, NULL) != 0) {
154	     		perror("pthread_create");
155	     		exit(1);
156		}
157	}
158
159	// main thread will be used as stress thread too, so start count at 1
160	for (i = 1; i < cpumon_threads; i++) {
161		if (pthread_create(&thr_id, NULL, cpumon_stress_thread, NULL) != 0) {
162	     		perror("pthread_create");
163	     		exit(1);
164		}
165	}
166
167	if (exit_after >= 0) {
168		printf("%s: will exit after %d seconds\n", pname, exit_after);
169		if (pthread_create(&thr_id, NULL, exit_thread, NULL) != 0) {
170			perror("pthread_create");
171			exit(1);
172		}
173	}
174
175	cpumon_stress_thread(NULL);
176
177	return (0);
178}
179