1
0
Files
irix-657m-src/irix/cmd/lboot/tune.c
2022-09-29 17:59:04 +03:00

521 lines
12 KiB
C

#ident "$Revision: 1.17 $"
/* Config for Tunable Parameters */
#include "lboot.h"
#include "boothdr.h"
#include "tune.h"
#include "errno.h"
#include <sys/types.h>
#include <stdio.h>
#include <sys/conf.h>
extern struct kernel kernel;
extern struct driver *driver;
extern char *slash_mtune;
extern char *stune_file;
char *tune_tag[MAXTAGS]; /* tag(s) on tune variables to pick */
int tune_num; /* next free tune entry */
char mtune_file[LSIZE];
char linebuf[LSIZE];
struct tune *tune_info = NULL;
struct tunemodule *group_info = NULL;
int group_num;
static int getline(FILE *fp, int *);
static char *parse_mtune(char *mname, int *groups);
static char *parse_stune(struct stune *sp);
void
gen_tune(struct driver *dp, char *alternate_file)
{
FILE *mtune;
char *p;
char *msg;
int groups = 0, linenum = 0;
struct tunemodule *gp;
if (alternate_file)
strcpy( mtune_file, alternate_file );
else {
strcpy( mtune_file, slash_mtune );
strcat( mtune_file, "/" );
strcat( mtune_file, dp->mname );
}
p=strrchr(mtune_file,'/');
if ( (p=strchr(p,'.')) != NULL )
*p = '\0';
if ((mtune = fopen(mtune_file,"r")) == NULL)
return;
while (getline(mtune, &linenum) != 0) {
if ((msg = parse_mtune(dp->mname, &groups)) != NULL)
error(ER55, mtune_file, linenum, msg);
}
if (groups == 0) {
/* generate tunemodule structure */
gp = (struct tunemodule *)mymalloc(sizeof(struct tunemodule));
gp->t_mname = mymalloc( strlen( dp->mname) + 1);
strcpy(gp->t_mname, dp->mname);
gp->t_gname = NULL;
gp->t_flags = N_STATIC;
gp->t_sanity = NULL;
gp->t_next = group_info;
group_info = gp;
group_num++;
}
}
/*
* Read a line. Skip lines beginning with '*' or '#', and blank lines.
* Return 0 if EOF. Return 1 otherwise.
*/
static int
getline(FILE *fp, int *ln)
{
int linenum = *ln;
for (;;) {
if (fgets(linebuf, LSIZE, fp) == NULL) {
linebuf[0] = '\0';
return(0);
}
linenum++;
if (*linebuf != '*' && *linebuf != '#' && *linebuf != '\n') {
*ln = linenum;
return(1);
}
}
}
static char *
chkstrtoull(char *str, long long *val, char *desc)
{
char *chkp;
unsigned long long v;
static char ebuf[80];
errno = 0;
v = strtoull(str, &chkp, 0);
if (errno == ERANGE) {
sprintf(ebuf, "number out of range for %s value:%s", desc, str);
return ebuf;
}
if (str == chkp) {
sprintf(ebuf, "invalid number for %s value:%s", desc, str);
return ebuf;
}
*val = (long long)v;
return NULL;
}
static char *
chkstrtoul(char *str, long long *val, char *desc)
{
char *chkp;
unsigned long v;
static char ebuf[80];
errno = 0;
v = strtoul(str, &chkp, 0);
if (errno == ERANGE) {
sprintf(ebuf, "number out of range for %s value:%s", desc, str);
return ebuf;
}
if (str == chkp) {
sprintf(ebuf, "invalid number for %s value:%s", desc, str);
return ebuf;
}
*val = (long long)v;
return NULL;
}
/*
* parse a tune file
* there are 2 main formats - a grtoup identifier and the tune variables
* themselves
* name[,tag] default [min [max [size]]]
*/
static char *
parse_mtune(char *mname, int *groups)
{
register int argc;
char *argv[256], **argvp;
struct tune *tp;
struct tunemodule *gp;
static char ebuf[80], *errstr;
argc = parse(argv,sizeof(argv)/sizeof(argv[0]),linebuf);
if (argc > sizeof(argv)/sizeof(argv[0]))
return("line too long");
if (argc < 2)
return("not enough fields in line!");
if (*argv[1] != ':') {
/*
* tunable parameter
* If the tunable has a 'tag' then check that
* If they haven't provided ANY tag value (via -O) we
* ignore ALL tagged values.
* We set argvp to point to the value for 'default'
* We also adjust argc to reflect # of args AFTER name/tag
*/
if (*argv[1] == ',') {
int i;
if (argc <= 2)
return("Not enough args for tagged variable");
for (i = 0; i < tune_num; i++)
if (strcmp(argv[2], tune_tag[i]) == 0)
break; /* match */
if (i >= tune_num)
/* no match */
return NULL;
argvp = &argv[3];
argc -= 3;
} else {
argvp = &argv[1];
argc--;
}
if (argc < 1)
return("no default value");
if (tunefind(argv[0])) {
sprintf(ebuf, "duplicate tune variable:%s", argv[0]);
return ebuf;
}
tp = (struct tune *)mymalloc(sizeof(struct tune));
tp->tname = mymalloc( strlen(argv[0]) + 1);
strcpy(tp->tname, argv[0]);
tp->tmin = 0;
tp->tmax = 0;
tp->type = TUNE_TYPE_32;
if ((argc > 3) && ((strcmp(argvp[3], "LL") == 0) ||
(strcmp(argvp[3], "ll") == 0))) {
tp->type = TUNE_TYPE_64;
if ((errstr = chkstrtoull(argvp[0], &tp->def,
"default")) != NULL)
return errstr;
if (argc > 1) {
if ((errstr = chkstrtoull(argvp[1], &tp->tmin,
"minimum")) != NULL)
return errstr;
}
if (argc > 2) {
/* don't check for valid 'max' - some folks
* like to put words in as comments ...
* should actually change tmax to be __uint64_t...
*/
tp->tmax = (long long)strtoull(argvp[2], 0, 0);
}
} else {
if ((errstr = chkstrtoul(argvp[0], &tp->def, "default")) != NULL)
return errstr;
if (argc > 1) {
if ((errstr = chkstrtoul(argvp[1], &tp->tmin,
"minimum")) != NULL)
return errstr;
}
if (argc > 2) {
/* don't check for valid 'max' - some folks
* like to put words in as comments ...
*/
tp->tmax = (long long)strtoul(argvp[2], 0, 0);
}
}
tp->svalue = tp->def;
tp->conf = 0;
if (!*groups) {
tp->group = group_num;
}
else {
tp->group = group_num - 1;
}
tp->next = tune_info;
tune_info = tp;
} else {
/* group name */
gp = (struct tunemodule *)mymalloc(sizeof(struct tunemodule));
gp->t_mname = mymalloc( strlen(mname)+ 1);
strcpy(gp->t_mname, mname);
gp->t_gname = mymalloc( strlen(argv[0]) + 1);
strcpy(gp->t_gname, argv[0]);
if ((argc > 2) && (EQUAL("run", argv[2])))
gp->t_flags = N_RUN;
else
gp->t_flags = N_STATIC;
gp->t_sanity = NULL;
gp->t_next = group_info;
group_info = gp;
(*groups)++;
group_num++;
}
return(NULL);
}
/*
* rdstune - System tunable parameter file
*/
void
rdstune(void)
{
struct stune stune;
register struct tune *tune;
FILE *stunep;
char *msg, ebuf[128];
int linenum = 0;
if ((stunep = fopen(stune_file, "r")) == NULL)
return;
while (getline(stunep, &linenum) != 0) {
if ((msg = parse_stune(&stune)) != NULL) {
error(ER110, stune_file, linenum, msg);
continue;
}
if (stune.s_name[0] == '\0')
continue;
/* find tunable in Parameter table */
tune = tunefind(stune.s_name);
if (tune == NULL) {
sprintf(ebuf, "unknown tunable parameter '%s' - Ignoring",
stune.s_name);
error(ER110, stune_file, linenum, ebuf);
continue;
}
/* check if already specified */
if (tune->conf) {
sprintf(ebuf, "tunable parameter '%s' respecified - ignoring 2nd definition",
stune.s_name);
error(ER110, stune_file, linenum, ebuf);
continue;
}
/* make sure types match */
if (stune.s_type != tune->type) {
sprintf(ebuf, " Ignoring '%s' because the type doesn't match\n\tCheck for missing \" LL\" or incorrect \" LL\" at end of line",
stune.s_name);
error(ER110, stune_file, linenum, ebuf);
continue;
}
/* check whether parameter is within min and max */
if (tune->tmax != 0) {
if (stune.s_value < tune->tmin ||
stune.s_value > tune->tmax) {
sprintf(ebuf, "the value of parameter '%s', %lld, must be within (%lld, %lld) - Ignoring",
stune.s_name, stune.s_value,
tune->tmin, tune->tmax);
error(ER110, stune_file, linenum, ebuf);
continue;
}
} else if (tune->tmin != 0) {
if (stune.s_value < tune->tmin) {
sprintf(ebuf, "the value of parameter '%s', %lld, must be greater than %lld - Ignoring",
stune.s_name, stune.s_value,tune->tmin);
error(ER110, stune_file, linenum, ebuf);
continue;
}
}
/* store value in Parameter table */
tune->svalue = stune.s_value;
/* indicate tunable parameter specified */
tune->conf = 1;
}
}
/* This routine is used to search the Parameter table
* for the keyword that was specified in the configuration. If the
* keyword cannot be found in this table, a NULL is returned.
* If the keyword is found, a pointer to that entry is returned.
*/
struct tune *
tunefind(char *keyword)
{
struct tune *tune;
for (tune = tune_info; tune != NULL; tune = tune->next) {
if (EQUAL(keyword, tune->tname))
return(tune);
}
return(NULL);
}
struct tunemodule *
gfind(char *keyword)
{
register struct tunemodule *tune;
for (tune = group_info; tune != NULL; tune = tune->t_next) {
if (EQUAL(keyword, tune->t_mname))
return(tune);
}
return(NULL);
}
/*
* stune file:
* name[,tag] = value [ll]
*/
static char *
parse_stune(struct stune *sp)
{
register int argc;
char *argv[256], **argvp, *errstr;
sp->s_name[0] = '\0';
argc = parse(argv,sizeof(argv)/sizeof(argv[0]),linebuf);
if (argc > sizeof(argv)/sizeof(argv[0]))
return("line too long");
/*
* check for tag - re-position argvp and argc to point to '='
*/
if (argc>1 && *argv[1] == ',') {
int i;
if (argc <= 2)
return("syntax error<name[,tag] = value [ll]>");
for (i = 0; i < tune_num; i++)
if (strcmp(argv[2], tune_tag[i]) == 0)
break; /* match */
if (i >= tune_num)
/* no match */
return NULL;
argvp = &argv[3];
argc -= 3;
} else {
argvp = &argv[1];
argc--;
}
if (argc < 2 || *argvp[0] != '=')
return("syntax error<name[,tag] = value [ll]>");
strcpy(sp->s_name, argv[0]);
sp->s_type = TUNE_TYPE_32;
if ((argc == 3) && ((strcmp(argvp[2], "LL") == 0) ||
(strcmp(argvp[2], "ll") == 0))) {
sp->s_type = TUNE_TYPE_64;
if ((errstr = chkstrtoull(argvp[1], &sp->s_value, "value")) != NULL)
return errstr;
} else
if ((errstr = chkstrtoul(argvp[1], &sp->s_value, "value")) != NULL)
return errstr;
return(NULL);
}
/*
* print out tunable Parameter table
*/
void
print_tune(FILE *f)
{
register struct tune *tune;
register struct tunemodule *gp;
int tuneentries = 0;
for (gp = group_info; gp != NULL; gp = gp->t_next) {
if (gp->t_sanity)
fprintf(f, "extern %s();\n", gp->t_sanity);
}
fprintf( f, "\nstruct tunetable tunetable[] = {\n");
for (gp = group_info; gp != NULL; gp = gp->t_next) {
fprintf(f, "\t{ ");
if (gp->t_gname)
fprintf(f, "\"%s\",", gp->t_gname);
else
fprintf(f, "\"%s\",", gp->t_mname);
if (gp->t_flags & N_RUN)
fprintf(f, "N_RUN,");
else if (gp->t_flags & N_STATIC)
fprintf(f, "N_STATIC,");
if (gp->t_sanity)
fprintf(f, "%s},\n", gp->t_sanity);
else
fprintf(f, "0},\n");
tuneentries++;
}
fprintf( f, " {0, 0, 0},\n};\n" );
fprintf(f, "\n/* defines for each tunable parameter */\n");
for (tune = tune_info; tune != NULL; tune = tune->next) {
if (tune->type == TUNE_TYPE_64)
fprintf(f, "long long\t%s = \t0x%llxll;\n",
tune->tname, tune->svalue);
else {
int val = (int)tune->svalue; /* avoid overflow */
fprintf(f, "int\t%s = \t0x%x;\n",
tune->tname, val);
}
}
fprintf(f, "int\ttuneentries = \t%d;\n\n", tuneentries+1);
/* Generate the tunename table. It is used to match up the name
* of a tuneable with its address and tunetable group index.
*/
fprintf( f, "\nstruct tunename tunename[] = {\n");
tuneentries = 0;
for (tune = tune_info; tune != NULL; tune = tune->next) {
fprintf(f, "\t{\"%s\", (int *)&%s, sizeof(%s), %d},\n",
tune->tname, tune->tname, tune->tname,
group_num - tune->group - 1);
tuneentries++;
}
fprintf( f, " {0, 0, 0, 0},\n};\n" );
fprintf(f, "int\ttunename_cnt = \t%d;\n\n", tuneentries+1);
}
/*
* find_kernel_sanity
*
* Called for each global procedure to detect if it
* is a tune sanity procedure, and if so, register it.
* XXX no real reason this can't be used for any sanity....
*/
/* ARGSUSED */
void
find_kernel_sanity(char *procname, void *arg0, void *arg1, void *arg2)
{
struct tunemodule *tmpgp;
char mgname[80];
int got_sanity;
struct tunemodule *gp = (struct tunemodule*)arg1;
/* build up tune_sanity functions */
tmpgp = gp;
got_sanity = 0;
while ((!got_sanity) && tmpgp) {
strcpy(mgname, "_");
if (tmpgp->t_gname)
strcat(mgname, tmpgp->t_gname);
else
strcat(mgname, tmpgp->t_mname);
if (function(mgname, "_sanity", procname)) {
tmpgp->t_sanity =
strcpy(mymalloc(strlen(procname)+1),procname);
got_sanity++;
}
tmpgp = tmpgp->t_next;
}
}