1
0
Files
irix-657m-src/eoe/lib/libnanothread/test/mp_sugnumthd.c
2022-09-29 17:59:04 +03:00

269 lines
7.8 KiB
C

#define _KMEMUSER 1
#ifndef _SGI_MP_SOURCE
#define _SGI_MP_SOURCE
#endif
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <ulocks.h>
#include <task.h>
#include <signal.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/timers.h> /* needs _KMEMUSER */
#include <sys/utsname.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/schedctl.h>
#include <sys/param.h>
#include <sys/prctl.h> /* for PRDA */
#include <sys/procfs.h> /* for reading from /proc */
#include <sys/sysmp.h> /* for sysmp() call */
#include "mp.h"
#define RATE 3 /* minimum of 3 seconds between checking load */
extern int suggestednthreads;
struct timers_t { /* keep track of running vs wait time */
unsigned wall; /* wall clock time in HZ ticks */
unsigned run; /* this cpu run time in HZ ticks */
unsigned idle; /* all cpus idle time in HZ ticks */
};
static struct status_t { /* bounds and current number of processors */
int32 min;
int32 max;
int32 now;
} status;
static struct timers_t t_now; /* current times of interest */
static struct timers_t t_last; /* previous, to calculate deltas */
static int verbose = FALSE; /* TRUE to print informational messages */
static int frozen = FALSE; /* TRUE if mp_numthreads or mp_set_numthreads */
static int clk_tck; /* set in init routine, from limits.h */
static int fd; /* for /proc of parent */
static int sugnumthd_pid = 0; /* pid of mp_sugnumthd_thread */
static void get_timers(struct timers_t *timers)
{
struct prpsinfo prpsinfo; /* filled in from /proc ioctl */
struct timeval tv; /* for time of day */
time_t cpu_time[6]; /* for cpu run, idle, wait etc. */
int rc;
BSD_getime(&tv); /* like gettimeofday but faster */
if (fd) {
rc = ioctl(fd,PIOCPSINFO,&prpsinfo);
if (rc<0) {
perror("mp_sugnumthd: ioctl of /proc failed");
exit(1);
}
}
rc = sysmp(MP_SAGET, MPSA_SINFO, &cpu_time, sizeof(cpu_time));
if (rc < 0) {
perror("mp_sugnumthd: sysmp MPSA_SINFO failed");
exit(1);
}
timers->idle = cpu_time[0]+cpu_time[3];
timers->run = prpsinfo.pr_time.tv_sec*100+prpsinfo.pr_time.tv_nsec/10000000;
timers->wall = tv.tv_sec*100+tv.tv_usec/10000;
}
/*
* This routine wakes up every few seconds and checks to see what
* sort of load the master process has, as well as if ther are any
* idle processors in the system.
*/
static void mp_sugnumthd_examine(void)
{
unsigned wall;
unsigned run;
unsigned idle;
unsigned frac_run;
unsigned frac_idle;
int adjust = 0;
if (frozen) /* till we add our syssgi() call... */
return;
get_timers(&t_now); /* pick up current wall, run and idle times */
wall = t_now.wall - t_last.wall; /* compute deltas */
run = t_now.run - t_last.run;
idle = t_now.idle - t_last.idle;
t_last = t_now; /* copy whole structure */
frac_run = 100*run/wall; /* percent of time running vs wall time */
frac_idle = 100*idle/wall; /* total idle cpus (100 = one idle cpu) */
if (frac_run < 90) { /* less than ideal headway? */
adjust = -1;
} else { /* go for it... */
if (frac_idle > 100)
adjust = 1+frac_idle/200; /* rather aggressive */
}
adjust += status.now; /* desired adjustment */
if (adjust > status.max)
adjust = status.max; /* clip to max if needed */
if (adjust < status.min)
adjust = status.min; /* clip to min if needed */
if (adjust != status.now) {
suggestednthreads = adjust; /* inform the rest of the library */
if (verbose) /* anything interesting happen? */
printf("wall %3d run %3d idle %3d frac_run %3d frac_idle %3d now %3d was %3d\n",
wall, run, idle, frac_run, frac_idle, adjust, status.now);
status.now = adjust;
}
PRDA->t_sys.t_hint = SGS_FREE; /* we don't want to join the gang */
}
/*
* This is the thread to handle dynamic parallel jobs
* We set ourselves up to read the master thread state
* Then we sleep, with periodic wakeup every few seconds to
* see if the system has become more or less busy.
*/
static void mp_sugnumthd_thread(uint_ptr spare)
{
char path[20]; /* /proc file name for parent */
int ppid; /* parent pid */
int nap;
int rc;
if (verbose)
printf("mp_sugnumthd_thread => enter\n");
PRDA->t_sys.t_hint = SGS_FREE; /* we don't want to join the gang */
ppid = getppid(); /* get main thread pid */
sprintf(path,"/proc/pinfo/%05d",ppid);
fd = open(path,O_RDONLY); /* open parent's /proc/pinfo file */
if (fd<0) {
perror("mp_sugnumthd: open of /proc failed");
exit(1); /* application keeps going... */
}
rc =sysmp(MP_SASZ, MPSA_SINFO);
if (rc < 0) {
perror("mp_sugnumthd: sysmp MP_SASZ failed");
exit(1); /* application keeps going... */
}
get_timers(&t_last); /* prime the timers */
sugnumthd_pid = getpid(); /* so we can be killed at exit */
while (1) { /* forever (exit with other sprocs) */
nap = clk_tck*RATE+(t_last.run+t_last.idle)%200;
while (nap = sginap(nap)) ; /* wait for entire interval */
mp_sugnumthd_examine(); /* check system load */
}
}
/*
* Called from mp.c after forking the computation sproc's
*
* 1. Checks to see of sugnumthd facility is wanted, returns if not.
* 2. Checks to see if verbose messages are desired.
* 3. Makes a static copy of min, max and current number of compute threads
* for later use (we make sure we stay within these bounds at all times)
* 4. Creates an extra sproc so we can set an alarm clock & block on it
*/
void __mp_sugnumthd_exit()
{
if (sugnumthd_pid)
kill(sugnumthd_pid,SIGTERM); /* kill the sproc'd thread */
sugnumthd_pid = 0;
}
/*
* If we are already frozen, just return.
* If user hasn't requested our service via MP_SUGNUMTHD or MPC_SUGNUMTHD, just return
* Check for user specified min & max number of processors
* Use sproc() call to make a child thread
*/
void __mp_sugnumthd_init(int32 min, int32 max,int32 now)
{
char *charP; /* for environment string */
int n; /* for environment integer */
if (frozen) { /* might already be frozen... */
if (verbose)
printf("__mp_sugnumthd_init => already frozen\n");
return;
}
if ( getenv("MP_SUGNUMTHD_VERBOSE") || getenv("MPC_SUGNUMTHD_VERBOSE") )
verbose = TRUE;
clk_tck = CLK_TCK; /* needed by sginap, from limits.h */
if ( ( (charP = getenv("MP_SUGNUMTHD_MIN")) != NULL) ||
( (charP = getenv("MPC_SUGNUMTHD_MIN")) != NULL) )
{
n = atoi(charP);
if ( (n>=min) && (n<=max) )
min = n; /* honor user's min request if ok */
}
if ( ( (charP = getenv("MP_SUGNUMTHD_MAX")) != NULL) ||
( (charP = getenv("MPC_SUGNUMTHD_MAX")) != NULL) )
{
n = atoi(charP);
if ( (n>=min) && (n<=max) )
max = n; /* honor user's min request if ok */
}
status.min = min; /* keep local copies */
status.max = max;
status.now = now;
if (verbose)
printf("Creating mp_sugnumthd_thread\n");
if (sproc((void(*)())mp_sugnumthd_thread, PR_SALL, 0) == -1) {
perror("sproc for mp_sugnumthd_thread");
exit(-1);
}
}
/*
* Called from mp.c whenever the number of threads is frozen
*
* 1. If verbose is set and we haven't warned the user before, print a
* warning message to stderr.
* 2. If our child sproc is running, terminate it via a signal.
*/
void __mp_sugnumthd_freeze(char *why)
{
if (frozen) /* ignore after first time */
return;
frozen = TRUE; /* in case init called later */
if ( !getenv("MP_SUGNUMTHD") && !getenv("MPC_SUGNUMTHD") )
return;
if ( getenv("MP_SUGNUMTHD_VERBOSE") || getenv("MPC_SUGNUMTHD_VERBOSE") )
verbose = TRUE;
if (verbose)
fprintf(stderr,"mp_sugnumthd warning: variable threads disabled due to %s call\n",why);
/* remember the child pid from the sproc and do a kill here... */
}