• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************/
2 /*									      */
3 /* Copyright (c) International Business Machines  Corp., 2001		      */
4 /*									      */
5 /* This program is free software;  you can redistribute it and/or modify      */
6 /* it under the terms of the GNU General Public License as published by       */
7 /* the Free Software Foundation; either version 2 of the License, or          */
8 /* (at your option) any later version.					      */
9 /*									      */
10 /* This program is distributed in the hope that it will be useful,	      */
11 /* but WITHOUT ANY WARRANTY;  without even the implied warranty of	      */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See	              */
13 /* the GNU General Public License for more details.			      */
14 /*									      */
15 /* You should have received a copy of the GNU General Public License	      */
16 /* along with this program;  if not, write to the Free Software		      */
17 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA    */
18 /*									      */
19 /******************************************************************************/
20 
21 /******************************************************************************/
22 /*			                                                      */
23 /* History:	Feb - 21 - 2002 Created - Manoj Iyer, IBM Austin TX.          */
24 /*				          email: manjo@austin.ibm.com.        */
25 /*			                                                      */
26 /* 		Feb - 25 - 2002 Modified - Manoj Iyer, IBM Austin TX.         */
27 /*		                - Added structure thread_sched_t.             */
28 /*				- Added logic to specify scheduling policy.   */
29 /*			                                                      */
30 /*		Feb - 25 - 2002 Modified - Manoj Iyer, IBM Austin TX.         */
31 /*				- Added header file string.h.	              */
32 /*				- Removed dead variable ppid from thread_func.*/
33 /*				- Fixed date from 2001 to 2002 in History.    */
34 /*			                                                      */
35 /* File:	trace_sched.c						      */
36 /*			                                                      */
37 /* Description:	This utility spawns N tasks, each task sets its priority by   */
38 /*		making a system call to the scheduler. The thread function    */
39 /*		reads the priority that tbe schedular sets for this task and  */
40 /*		also reads from /proc the processor this task last executed on*/
41 /*		the information that is gathered by the thread function may   */
42 /*		be in real-time. Its only an approximation.                   */
43 /*			                                                      */
44 /******************************************************************************/
45 
46 #include <fcntl.h>
47 #include <limits.h>
48 #include <pthread.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <sched.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <sys/wait.h>
55 #include <sys/time.h>
56 #include <unistd.h>
57 #include <string.h>
58 
noprintf(char * string,...)59 void noprintf(char *string, ...)
60 {
61 }
62 
63 #ifdef DEBUG			/* compile with this flag for debug, use dprt in code */
64 #define dprt    printf
65 #else
66 #define dprt    noprintf
67 #endif
68 
69 #ifndef PID_MAX
70 #define PID_MAX 0x8000
71 #endif
72 
73 #define MAXT 100
74 
75 #ifdef PTHREAD_THREADS_MAX
76 #define PIDS PTHREAD_THREADS_MAX	/* maximum thread allowed.                     */
77 #elif defined(PID_MAX_DEFAULT)
78 #define PIDS PID_MAX_DEFAULT	/* maximum pids allowed.                       */
79 #else
80 #define PIDS PID_MAX		/* alternative way maximum pids may be defined */
81 #endif
82 
83 #define UP   1			/* assume UP if no SMP value is specified.     */
84 
85 #define OPT_MISSING(prog, opt)   do{\
86                                fprintf(stderr, "%s: option -%c ", prog, opt); \
87                                fprintf(stderr, "requires an argument\n"); \
88                                usage(prog); \
89                                    } while (0)
90 
91 #define SAFE_FREE(p) { if (p) { free(p); (p)=NULL; } }
92 
93 typedef struct {		/* contains priority and CPU info of the task.        */
94 	int exp_prio;		/* priority that we wish to set.                      */
95 	int act_prio;		/* priority set by the scheduler.                     */
96 	int proc_num;		/* last processor on which this task executed.        */
97 	int procs_id;		/* pid of this task.                                  */
98 	int s_policy;		/* scheduling policy for the task.                    */
99 } thread_sched_t;
100 
101 int verbose = 0;		/* set verbose printing, makes output look ugly!      */
102 
103 /******************************************************************************/
104 /*                                                                            */
105 /* Function:    usage                                                         */
106 /*                                                                            */
107 /* Description: Print the usage message.                                      */
108 /*                                                                            */
109 /* Return:      exits with -1                                                 */
110 /*                                                                            */
111 /******************************************************************************/
usage(char * progname)112 void usage(char *progname)
113 {				/* name of this program                                 */
114 	fprintf(stderr,
115 		"Usage: %s -c NCPU -h -p [fifo:rr:other] -t THREADS -v\n"
116 		"\t -c Number of CUPS in the machine. User MUST provide\n"
117 		"\t -h Help!\n"
118 		"\t -p Scheduling policy, choice: fifo, rr, other. Default: fifo\n"
119 		"\t -t Number of threads to create.                Default: %d\n"
120 		"\t -v Verbose out put, print ugly!.               Default: OFF\n",
121 		progname, MAXT);
122 	exit(-1);
123 }
124 
125 /******************************************************************************/
126 /*                                                                            */
127 /* Function:    get_proc_num                                                  */
128 /*                                                                            */
129 /* Description: Function reads the proc filesystem file /proc/<PID>/stat      */
130 /*		gets the CPU number this process last executed on and returns */
131 /*		Some hard assumptions were made regarding buffer sizes.       */
132 /*                                                                            */
133 /* Return:      exits with -1 - on error                                      */
134 /*              CPU number - on success				              */
135 /*                                                                            */
136 /******************************************************************************/
get_proc_num(void)137 static int get_proc_num(void)
138 {
139 	int fd = -1;		/* file descriptor of the /proc/<pid>/stat file.      */
140 	int fsize = -1;		/* size of the /proc/<pid>/stat file.                 */
141 	char filename[256];	/* buffer to hold the string /proc/<pid>/stat.        */
142 	char fbuff[512];	/* contains the contents of the stat file.            */
143 
144 	/* get the name of the stat file for this process */
145 	sprintf(filename, "/proc/%d/stat", getpid());
146 
147 	/* open the stat file and read the contents to a buffer */
148 	if ((fd = open(filename, O_RDONLY)) == -1) {
149 		perror("get_proc_num(): open()");
150 		return -1;
151 	}
152 
153 	usleep(6);
154 	sched_yield();
155 
156 	if ((fsize = read(fd, fbuff, 512)) == -1) {
157 		perror("main(): read()");
158 		return -1;
159 	}
160 
161 	close(fd);
162 	/* return the processor number last executed on. */
163 	return atoi(&fbuff[fsize - 2]);
164 }
165 
166 /******************************************************************************/
167 /*                                                                            */
168 /* Function:    thread_func                                                   */
169 /*                                                                            */
170 /* Description: This function is executed in the context of the new task that */
171 /*		pthread_createi() will spawn. The (thread) task will get the  */
172 /*		minimum and maximum static priority for this system, set the  */
173 /*		priority of the current task to a random priority value if    */
174 /*		the policy set if SCHED_FIFO or SCHED_RR. The priority if this*/
175 /*		task that was assigned by the scheduler is got from making the*/
176 /*		system call to sched_getscheduler(). The CPU number on which  */
177 /*		the task was last seen is also recorded. All the above data is*/
178 /*		returned to the calling routine in a structure thread_sched_t.*/
179 /*                                                                            */
180 /* Input:       thread_sched_t 						      */
181 /*		    s_policy - scheduling policy for the task.                */
182 /*                                                                            */
183 /* Return:      thread_sched_t - on success.				      */
184 /*		    exp_prio - random priority value to set.                  */
185 /*		    act_prio - priority set by the scheduler.                 */
186 /*		    proc_num - CPU number on which this task last executed.   */
187 /*		    procs_id -  pid of this task.                             */
188 /*                                                                            */
189 /*		-1 	       - on error.                                    */
190 /*                                                                            */
191 /******************************************************************************/
thread_func(void * args)192 void *thread_func(void *args)
193 {				/* arguments to the thread function           */
194 	static int max_priority;	/* max possible priority for a process.       */
195 	static int min_priority;	/* min possible priority for a process.       */
196 	static int set_priority;	/* set the priority of the proc by this value. */
197 	static int get_priority;	/* get the priority that is set for this proc. */
198 	static int procnum;	/* processor number last executed on.         */
199 	static int sched_policy;	/* scheduling policy as set by user/default   */
200 	struct sched_param ssp;	/* set schedule priority.                     */
201 	struct sched_param gsp;	/* gsp schedule priority.                     */
202 	struct timeval tptr;	/* tptr.tv_usec will be used to seed srand.   */
203 	thread_sched_t *locargptr =	/* local ptr to the arguments.                */
204 	    (thread_sched_t *) args;
205 
206 	/* Get the system max and min static priority for a process. */
207 	if (((max_priority = sched_get_priority_max(SCHED_FIFO)) == -1) ||
208 	    ((min_priority = sched_get_priority_min(SCHED_FIFO)) == -1)) {
209 		fprintf(stderr, "failed to get static priority range\n");
210 		dprt("pid[%d]: exiting with -1\n", getpid());
211 		pthread_exit((void *)-1);
212 	}
213 
214 	if ((sched_policy = locargptr->s_policy) == SCHED_OTHER)
215 		ssp.sched_priority = 0;
216 	else {
217 		/* Set a random value between max_priority and min_priority */
218 		gettimeofday(&tptr, NULL);
219 		srand((unsigned int)tptr.tv_usec);
220 		set_priority = (min_priority + (int)((float)max_priority
221 						     * rand() / (RAND_MAX +
222 								 1.0)));
223 		ssp.sched_priority = set_priority;
224 	}
225 
226 	/* give other threads a chance */
227 	usleep(8);
228 
229 	/* set a random priority value and check if this value was honoured. */
230 	if ((sched_setscheduler(getpid(), sched_policy, &ssp)) == -1) {
231 		perror("main(): sched_setscheduler()");
232 		dprt("pid[%d]: exiting with -1\n", getpid());
233 		pthread_exit((void *)-1);
234 	}
235 
236 	/* processor number this process last executed on */
237 	if ((procnum = get_proc_num()) == -1) {
238 		fprintf(stderr, "main(): get_proc_num() failed\n");
239 		dprt("pid[%d]: exiting with -1\n", getpid());
240 		pthread_exit((void *)-1);
241 	}
242 
243 	if ((get_priority = sched_getparam(getpid(), &gsp)) == -1) {
244 		perror("main(): sched_setscheduler()");
245 		dprt("pid[%d]: exiting with -1\n", getpid());
246 		pthread_exit((void *)-1);
247 	}
248 
249 	/* processor number this process last executed on */
250 	if ((procnum = get_proc_num()) == -1) {
251 		fprintf(stderr, "main(): get_proc_num() failed\n");
252 		dprt("pid[%d]: exiting with -1\n", getpid());
253 		pthread_exit((void *)-1);
254 	}
255 
256 	if (verbose) {
257 		fprintf(stdout,
258 			"PID of this task         = %d\n"
259 			"Max priority             = %d\n"
260 			"Min priority             = %d\n"
261 			"Expected priority        = %d\n"
262 			"Actual assigned priority = %d\n"
263 			"Processor last execed on = %d\n\n", getpid(),
264 			max_priority, min_priority, set_priority,
265 			gsp.sched_priority, procnum);
266 	}
267 
268 	locargptr->exp_prio = set_priority;
269 	locargptr->act_prio = gsp.sched_priority;
270 	locargptr->proc_num = procnum;
271 	locargptr->procs_id = getpid();
272 
273 	dprt("pid[%d]: exiting with %ld\n", getpid(), locargptr);
274 	pthread_exit((void *)locargptr);
275 }
276 
277 /******************************************************************************/
278 /*                                                                            */
279 /* Function:    main						              */
280 /*                                                                            */
281 /* Description: Entry point of the program, parse options, check for their    */
282 /*		validity, spawn N tasks, wait for them to return, in the end  */
283 /*		print all the data that the thiread function collected.       */
284 /*                                                                            */
285 /* Return:      exits with -1 - on error.                                     */
286 /*		exits with  0 - on success.				      */
287 /*                                                                            */
288 /******************************************************************************/
main(int argc,char ** argv)289 int main(int argc,		/* number of input parameters.                        */
290 	 char **argv)
291 {				/* pointer to the command line arguments.       */
292 	int c;			/* command line options.                      */
293 	int proc_ndx;		/* number of time to repete the loop.         */
294 	int pid_ndx;		/* number of time to repete the loop.         */
295 	int num_cpus = UP;	/* assume machine is an UP machine.           */
296 	int num_thrd = MAXT;	/* number of threads to create.               */
297 	int thrd_ndx;		/* index into the array of threads.           */
298 	int exp_prio[PIDS];	/* desired priority, random value.            */
299 	int act_prio[PIDS];	/* priority actually set.                     */
300 	int gen_pid[PIDS];	/* pid of the processes on this processor.    */
301 	int proc_id[PIDS];	/* id of the processor last execed on.        */
302 	int spcy = SCHED_FIFO;	/* scheduling policy for the tasks.           */
303 	pthread_t thid[PIDS];	/* pids of process or threads spawned         */
304 	thread_sched_t *chld_args;	/* arguments to funcs execed by child process. */
305 	thread_sched_t *status;	/* exit status for light weight process.      */
306 	extern char *optarg;	/* arguments passed to each option.           */
307 	thread_sched_t **args_table;	/* pointer table of arguments address         */
308 	thread_sched_t **status_table;	/*pointer table of status address          */
309 
310 	if (getuid() != 0) {
311 		fprintf(stderr,
312 			"ERROR: Only root user can run this program.\n");
313 		usage(argv[0]);
314 	}
315 
316 	if (argc < 2) {
317 		fprintf(stderr,
318 			"ERROR: Enter a value for the number of CPUS\n");
319 		usage(argv[0]);
320 	}
321 
322 	while ((c = getopt(argc, argv, "c:hp:t:v")) != -1) {
323 		switch (c) {
324 		case 'c':	/* number of processors. no default. */
325 			if ((num_cpus = atoi(optarg)) == 0)
326 				OPT_MISSING(argv[0], optopt);
327 			else if (num_cpus < 0) {
328 				fprintf(stdout,
329 					"WARNING: Bad argument -p %d. Using default\n",
330 					num_cpus);
331 				num_cpus = UP;
332 			}
333 			/* MAXT threads per cpu. */
334 			num_thrd = num_thrd * num_cpus;
335 			break;
336 		case 'h':	/* usage message */
337 			usage(argv[0]);
338 			break;
339 		case 'p':	/* schedular policy. default SCHED_FIFO */
340 			if (strncmp(optarg, "fifo", 4) == 0)
341 				spcy = SCHED_FIFO;
342 			else if (strncmp(optarg, "rr", 2) == 0)
343 				spcy = SCHED_RR;
344 			else if (strncmp(optarg, "other", 5) == 0)
345 				spcy = SCHED_OTHER;
346 			else {
347 				fprintf(stderr,
348 					"ERROR: Unrecognized scheduler policy, "
349 					"using default\n");
350 				usage(argv[0]);
351 			}
352 			break;
353 		case 't':	/* input how many threads to create */
354 			if ((num_thrd = atoi(optarg)) == 0)
355 				OPT_MISSING(argv[0], optopt);
356 			else if (num_thrd < 0) {
357 				fprintf(stderr,
358 					"WARNING: Bad argument -t %d. Using default\n",
359 					num_thrd);
360 				num_thrd = MAXT;
361 			} else if (num_thrd > PIDS) {
362 				fprintf(stderr,
363 					"WARNING: -t %d exceeds maximum number of allowed pids"
364 					" %d\n Setting number of threads to %d\n",
365 					num_thrd, PIDS, PIDS - 1000);
366 				num_thrd = (PIDS - 1000);
367 			}
368 			break;
369 		case 'v':	/* verbose out put, make output look ugly! */
370 			verbose = 1;
371 			break;
372 		default:
373 			usage(argv[0]);
374 			break;
375 		}
376 	}
377 
378 	/* create num_thrd number of threads. */
379 	args_table = malloc(num_thrd * sizeof(thread_sched_t *));
380 	if (!args_table) {
381 		perror("main(): malloc failed");
382 		exit(-1);
383 	}
384 	for (thrd_ndx = 0; thrd_ndx < num_thrd; thrd_ndx++) {
385 		args_table[thrd_ndx] = malloc(sizeof(thread_sched_t));
386 		if (!args_table[thrd_ndx]) {
387 			perror("main(): malloc failed");
388 			exit(-1);
389 		}
390 		chld_args = args_table[thrd_ndx];
391 		chld_args->s_policy = spcy;
392 		if (pthread_create(&thid[thrd_ndx], NULL, thread_func,
393 				   chld_args)) {
394 			fprintf(stderr, "ERROR: creating task number: %d\n",
395 				thrd_ndx);
396 			perror("main(): pthread_create()");
397 			exit(-1);
398 		}
399 		if (verbose)
400 			fprintf(stdout, "Created thread[%d]\n", thrd_ndx);
401 		usleep(9);
402 		sched_yield();
403 	}
404 
405 	/* wait for the children to terminate */
406 	status_table = malloc(num_thrd * sizeof(thread_sched_t *));
407 	if (!status_table) {
408 		perror("main(): malloc failed");
409 		exit(-1);
410 	}
411 	for (thrd_ndx = 0; thrd_ndx < num_thrd; thrd_ndx++) {
412 		status_table[thrd_ndx] = malloc(sizeof(thread_sched_t));
413 		if (!status_table[thrd_ndx]) {
414 			perror("main(): malloc failed");
415 			exit(-1);
416 		}
417 		status = status_table[thrd_ndx];
418 		if (pthread_join(thid[thrd_ndx], (void **)&status)) {
419 			perror("main(): pthread_join()");
420 			exit(-1);
421 		} else {
422 			if (status == (thread_sched_t *) - 1) {
423 				fprintf(stderr,
424 					"thread [%d] - process exited with exit code -1\n",
425 					thrd_ndx);
426 				exit(-1);
427 			} else {
428 				exp_prio[thrd_ndx] = status->exp_prio;
429 				act_prio[thrd_ndx] = status->act_prio;
430 				proc_id[thrd_ndx] = status->proc_num;
431 				gen_pid[thrd_ndx] = status->procs_id;
432 			}
433 		}
434 		SAFE_FREE(args_table[thrd_ndx]);
435 		SAFE_FREE(status_table[thrd_ndx]);
436 		usleep(10);
437 	}
438 
439 	if (verbose) {
440 		fprintf(stdout,
441 			"Number of tasks spawned: %d\n"
442 			"Number of CPUs:          %d\n"
443 			"Scheduling policy:       %d\n", num_thrd, num_cpus,
444 			spcy);
445 	}
446 
447 	SAFE_FREE(args_table);
448 	SAFE_FREE(status_table);
449 
450 	for (proc_ndx = 0; proc_ndx < num_cpus; proc_ndx++) {
451 		fprintf(stdout, "For processor number = %d\n", proc_ndx);
452 		fprintf(stdout, "%s\n", "===========================");
453 		for (pid_ndx = 0; pid_ndx < num_thrd; pid_ndx++) {
454 			if (proc_id[pid_ndx] == proc_ndx)
455 				fprintf(stdout,
456 					"pid of task = %d priority requested = %d"
457 					" priority assigned by scheduler = %d\n",
458 					gen_pid[pid_ndx], exp_prio[pid_ndx],
459 					act_prio[pid_ndx]);
460 		}
461 	}
462 	exit(0);
463 }
464