📄 cpustat.c
字号:
# ifndef lintstatic char *sccsid = "@(#)cpustat.c 4.5 (ULTRIX) 12/20/90";# endif not lint/************************************************************************ * * * Copyright (c) 1988, 1990 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************/#include <curses.h>#include <signal.h>#include <nlist.h>#include <utmp.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/smp_lock.h>#include <sys/time.h>#include <sys/param.h>#include <sys/proc.h>#include <sys/cpudata.h>#ifdef mips#include <sys/fixpoint.h>#endif mips#ifdef vax#include <machine/vectors.h>#endif /* vax *//************************************************************************** * A program to display per cpu information * * * to be compiled with curses library * cc -o cpustat cpustat.c -lcurses -ltermcap * * * This program is designed to display different sets of information * about each cpu. In the default mode, the intent is to display as * much as possible on a full screen. But the user can select specific * flags for specific displays ('s' for statistics and 'c' for cpu * states). If the program is to be modified to display new sets of * information, the following need to be done: * 1. If a new data structure is to be accessed in the kernel, * update the namelist structure and modify the update_info() * routine to extract the new information. * 2. Add a new flag to the command line and modify the get_opts() * routine to set the corresponding flag on. * 3. display() is the central routine controlling the display. * Wherever a test is done for the current optional flags * (sflg or cflg), add the test for the new flag. If the new * flag is set, call the corresponding routine to display the * header or the updated information. * 4. Add a new switch condition for the new flag (i.e. a one * letter command is to be added to the commands available from * the full screen.). Do things similar to what is currently * being done for 'c' or 's' commands. * 5. Write two new routines to set up the header for the new set * of information (similar to setup_state()) and display the * new information (similar to upd_statistics_scrn()). * 6. Write a new routine to print the new information on the * screen (similar to pr_state()). * 7. Special things may have to be done depending on the format * in which the new information is to be displayed (like * format_state()). * 8. Update the help messages help_stats[], help_state[] and * help_info[]. * 9. Update the string *cmd for the new command. * 10. Update the man page. * **************************************************************************//************************************************************************** * Modification History: * * 20 dec 90 - dlh * corrected output of pid field * changed display of vp state * * 14 Nov 90 - paradis * Add support for displaying vector-processor statistics * (only on vector-capable VAX architectures) * * 08 Dec 89 - jaw * add error check for select call for interrupted system call. * 09 Jun 89 - gmm * Fixes to print load average correctly on mips. * 15 Jun 88 - George Mathew * Changes to conform to the new way cpudata allocated * 01 Jun 88 - George Mathew * Fixed some display alignment problems * 22 Feb 88 - George Mathew * Created this progam. * ***************************************************************************/struct nlist namelist[] = {#define C_HZ 0 { "_hz" },#define C_CPUDATA 1 { "_cpudata" },#define C_AVENRUN 2 { "_avenrun" },#ifdef vax#define C_VPTOTAL 3 { "_vptotal" },#define C_VPMASK 4 { "_vpmask" },#endif /* vax */ { "" }};#define HOSTLEN 255char hname[HOSTLEN];#define DEF_INTERVAL 10 /* default interval between displays *//* #define MAXCPU 32 max. no of cpus/slots (now defined in cpudata.h) *//* X-Y positions on the window */#define XZERO 0#define YZERO 0#define YTWO 2#define YTHREE 3int activecpu; /* mask of active cpus */int fflg,cflg,sflg,errflg; /* command line options */int vflg = 0; /* vector option */int vptotal = 0; /* # vector processors */unsigned vpmask = 0; /* mask of installed VPs */int kmem; /* file descriptor for kmem file */int deflt = 1; /* default flag */int interval,iter;char *kernfile = "/vmunix";char *kmemfile = "/dev/kmem";int total_cpus,cpudata_size;struct cpudata *pcpudata, *cpudata_p1, *cpudata_p0;#ifdef vaxstruct vpdata *vpdata_p1, *vpdata_p0;#endif /* vax */char *state_hdr = "cpu state ipi-mask proc pid";char *statistics_hdr = "cpu us%% ni%% sy%% id%% csw sys trap intr ipi ttyin ttyout";#ifdef vaxchar *vp_hdr = "cpu vp state vp owner chp cxsw exp cxsw succ req failed req"; #endif /* vax */char printbuf[100]; /* buffer to hold the format string for printing*/char *st_format = " %s %s %c ";#ifdef vaxdouble loadav[3];#endif vax#ifdef mipsfix loadav[3];#endiflong cur_time;int users; char *help_0 = "cpustat HELP screen";char *help_stats[] = { "When in full screen mode, to change the display type:", " s : Display cpu statistics only", " c : Display cpu states only",#ifdef vax " v : Display vector processor states only",#endif /* vax */ " d : Display default mode (stats) and states if less than 8 cpus", " q : Quit this program", " h : Display this help screen", " Any other character refreshes the screen", 0 };char *help_state[] = { "The options for cpustat are:", " -f : display cpu statistics and state on full screen", " -s : display only cpu statistics information", " -c : display only cpu state information",#ifdef vax " -v : display only vector processor state information",#endif /* vax */ " -h : display this help information", " interval: interval in seconds before refreshing display", " count: count of intervals before exiting the program", "If no option is used, all information will be displayed line by line", 0 };char *help_info[] = { "The Statistics fields are:", " us%% : %% time spent in user mode", " ni%% : %% time spent in nice mode", " sy%% : %% time spent in system mode", " id%% : %% time spent idle by the cpu", " csw : number of context switches", " sys: number of system calls", " trap: number of traps", " intr: number of device interrupts", " ipi: number of inter processor interrupts", " ttyin: number of input tty characters", " ttyout: number of output tty characters", "The Cpu States fields are:", " cpuid: Unique identifier of the cpu", " state: Cpu state: B - Boot cpu, R - running, T - TB needs invalidation,", " P - paniced, D - disable soft errors, S - cpu stopped", " ipi-mask: Inter processor interrupt mask: P - panic, R - console print", " S - schedule, T - TB invalidation, H - stop cpu", " proc: if the cpu has an associated process (Y/N)", " pid: process id of the running process", 0 };char *help_1 = "To get out of the help screen, type any character";#ifdef vaxchar *cmd = "Commands: <c,d,v,h,q,s>"; /* commands available from within * the full display screen */#elsechar *cmd = "Commands: <c,d,h,q,s>"; /* commands available from within * the full display screen */#endif /* vax */struct stats { /* structure to internally hold all statistics */ float st_usr; float st_nice; float st_sys; float st_idle; int st_csw; int st_calls; int st_trap; int st_intr; int st_ipi; int st_ttyin; int st_ttyout;} stats;struct cpu_states { /* structure to internally hold all states */ char cps_state[15]; char cps_ipi[15]; char cps_proc; short cps_pid;} cpu_states;char scale_data();int done();extern int errno;main(argc,argv)int argc;char *argv[];{ register int i; struct cpudata *pcpu; if(--argc > 0) { if (argv[1][0] == '-') { if(get_opts(argv[1])) { usage(); exit(1); } argc--; argv++; } if(argc--) interval = atoi(argv[1]); if(argc) iter = atoi((++argv)[1]); } nlist(kernfile,namelist); if(namelist[C_AVENRUN].n_type == 0) { printf("Namelist could not be found for %s\n",kernfile); exit(1); } if ( (kmem = open(kmemfile,0)) == 0 ) { printf("Cannot open %s\n",kmemfile); exit(1); }#ifdef vax if(namelist[C_VPMASK].n_value != 0) { lseek(kmem, (long)namelist[C_VPMASK].n_value, 0); read(kmem, &vpmask, sizeof(vpmask)); } else { vpmask = 0; } if(namelist[C_VPTOTAL].n_value != 0) { lseek(kmem, (long)namelist[C_VPTOTAL].n_value, 0); read(kmem, &vptotal, sizeof(vptotal)); } else { vptotal = 0; }#endif /* vax */ for(i=0; i<MAXCPU; i++) { lseek(kmem, (long)namelist[C_CPUDATA].n_value + 4*i, 0); read(kmem, &pcpu, sizeof (pcpu)); if (pcpu) { activecpu = activecpu | (1<<i); total_cpus++; } } if( (cpudata_p0 = (struct cpudata *)calloc(total_cpus,sizeof(struct cpudata)) ) == NULL) { printf("No memory to allocate cpudata structures\n"); exit(1); } if( (cpudata_p1 = (struct cpudata *)calloc(total_cpus,sizeof(struct cpudata)) ) == NULL) { printf("No memory to allocate cpudata structures\n"); exit(1); }#ifdef vax if(vptotal > 0) { if( (vpdata_p0 = (struct vpdata *)calloc(total_cpus, sizeof(struct vpdata)) ) == NULL) { printf("No memory to allocate vpdata structures\n"); exit(1); } if( (vpdata_p1 = (struct vpdata *)calloc(total_cpus, sizeof(struct vpdata)) ) == NULL) { printf("No memory to allocate vpdata structures\n"); exit(1); } }#endif /* vax */ signal(SIGINT,done); signal(SIGQUIT,done); display(); /* NO RETURN */}get_opts(ptr)char *ptr;{ char c; int errflg = 0; while (c = *ptr++) { switch(c) { case 'f': fflg++; break; case 'c': cflg++; deflt = 0; break; case 's': sflg++; deflt = 0; break;#ifdef vax case'v': vflg++; deflt = 0; break;#endif /* vax */ case 'h': print_help(); exit(0); case '-': break; default: errflg++; } } if(errflg) return(1); else return(0);}/* This is the routine which controls all the display. It loops for ever * updating the display at requested intervals. */display(){ struct timeval tintv; int mask,tin; char c; int hdr = 0; if(interval == 0) tintv.tv_sec = DEF_INTERVAL; else tintv.tv_sec = interval; tintv.tv_usec = 0; if(fflg) { /* if full screen option, set up the headers */ gethostname(hname,HOSTLEN); init_screen(); if(sflg || cflg || vflg) { if(sflg) setup_statistics(); if(cflg) setup_state(); if(vflg && vptotal) setup_vecstate(); } else { /* if only -f option used, try to display all info */ setup_statistics(); if( total_cpus <=8 ) setup_state(); if( vptotal && (total_cpus <= 6 )) setup_vecstate(); } } for(;;) { update_info(); /* pick up the latest data from /dev/kmem */ if(fflg) { standout(); /* start highligting display */#ifdef vax mvprintw(YZERO,25,"%4.2f %4.2f %4.2f",loadav[0],loadav[1],loadav[2]);#endif vax#ifdef mips mvprintw(YZERO,25,"%4.2f %4.2f %4.2f",FIX_TO_DBL(loadav[0]),FIX_TO_DBL(loadav[1]),FIX_TO_DBL(loadav[2]));#endif mips mvprintw(YZERO,45,ctime(&cur_time)); move (YZERO,70); if(users != -1) { if(users == 1) addstr("1 user"); else printw("%d users",users); } standend(); /* end highlighting display */ if(sflg || cflg || vflg ) { if(sflg) upd_statistics_scrn(); if(cflg) upd_state_scrn(); if(vflg) upd_vec_scrn(); } else { upd_statistics_scrn(); if( total_cpus <=8 ) upd_state_scrn(); if( total_cpus <= 6 ) upd_vec_scrn(); } mvprintw(LINES-1,XZERO,cmd); refresh(); /* put the stuff up on the screen */ } else { if(sflg || cflg || vflg) { if (cflg) { if( (hdr == 0) || (sflg) ) { printf(statistics_hdr); printf("\n"); } pr_statistics(); } if(sflg) { if( (hdr == 0) || (cflg) ) printf("\n"); printf("%s\n",state_hdr); pr_state(); }#ifdef vax if((vflg != 0) && (vptotal != 0)) { if( (hdr == 0) || (vflg) ) { printf("\n"); printf("%s\n", vp_hdr); } pr_vecstate(); }#endif /* vax */ if(hdr == 0) hdr = 19/total_cpus; /* to print header*/ else hdr--; } else { printf(statistics_hdr); printf("\n"); pr_statistics(); printf("%s\n",state_hdr); pr_state();#ifdef vax if(vptotal > 0) { printf("%s\n", vp_hdr); pr_vecstate(); }#endif /* vax */ } printf("\n"); } if(--iter == 0) done(); if(fflg) { /* wait for any user input for full screen option */ tin = 1; /* mask for stdin for select() */ /* pick up the user typed character within the desired * time interval */ errno = 0; mask = select(2, &tin, (int *)0, (int *)0, &tintv); if( !errno && mask && tin) { int saved; c = getchar(); switch(c) { case 'q': done(); case 'h': display_help(); saved = tintv.tv_sec; /* display the help message for a max. * of 10 mins. before going back to the * original display */ tintv.tv_sec = 10 * 60; /* max. 10 mins */ tin = 1; errno = 0; mask = select(2,&tin,(int *)0, (int *)0,&tintv); if(!errno && mask && tin) c = getchar(); tintv.tv_sec = saved; /* setup the screen as was before * putting up the help screen */ setup_init(); if(sflg || cflg || vflg) { if(sflg) setup_statistics(); if(cflg) setup_state(); if(vflg && vptotal) setup_vecstate(); } else { setup_statistics(); if( total_cpus <=8 ) setup_state(); if(vptotal&&(total_cpus <= 6)) setup_vecstate(); } break; case 'c': if(sflg || vflg || (!cflg) ) { deflt = 0; cflg = 1; sflg = 0; vflg = 0; setup_init(); setup_state(); } break;#ifdef vax case 'v': if(sflg || cflg || (!vflg) ) { deflt = 0; vflg = 1; cflg = 0; sflg = 0; setup_init(); if(vptotal) setup_vecstate(); } break;#endif /* vax */ case 's': if(cflg || vflg || (!sflg) ) { deflt = 0; sflg = 1; cflg = 0; vflg = 0; setup_statistics(); } break; case 'd': /* display the default option * ie. only f flag */ if(!deflt) { deflt = 1; vflg = cflg = sflg = 0; setup_statistics(); if(total_cpus <= 8) setup_state(); if(vptotal&&(total_cpus <= 6)) setup_vecstate(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -