Home | History | Annotate | Download | only in vmstat
      1 /*
      2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 /*
      7  * Copyright (c) 1980 Regents of the University of California.
      8  * All rights reserved.  The Berkeley software License Agreement
      9  * specifies the terms and conditions for redistribution.
     10  */
     11 
     12 /* from UCB 5.4 5/17/86 */
     13 /* from SunOS 4.1, SID 1.31 */
     14 
     15 #include <stdio.h>
     16 #include <stdlib.h>
     17 #include <stdarg.h>
     18 #include <ctype.h>
     19 #include <unistd.h>
     20 #include <memory.h>
     21 #include <string.h>
     22 #include <fcntl.h>
     23 #include <errno.h>
     24 #include <signal.h>
     25 #include <values.h>
     26 #include <poll.h>
     27 #include <locale.h>
     28 
     29 #include "statcommon.h"
     30 
     31 char *cmdname = "vmstat";
     32 int caught_cont = 0;
     33 
     34 static uint_t timestamp_fmt = NODATE;
     35 
     36 static	int	hz;
     37 static	int	pagesize;
     38 static	double	etime;
     39 static	int	lines = 1;
     40 static	int	swflag = 0, cflag = 0, pflag = 0;
     41 static	int	suppress_state;
     42 static	long	iter = 0;
     43 static	hrtime_t period_n = 0;
     44 static  struct	snapshot *ss;
     45 
     46 struct iodev_filter df;
     47 
     48 #define	pgtok(a) ((a) * (pagesize >> 10))
     49 #define	denom(x) ((x) ? (x) : 1)
     50 #define	REPRINT	19
     51 
     52 static	void	dovmstats(struct snapshot *old, struct snapshot *new);
     53 static	void	printhdr(int);
     54 static	void	dosum(struct sys_snapshot *ss);
     55 static	void	dointr(struct snapshot *ss);
     56 static	void	docachestats(kstat_ctl_t *kc, hrtime_t interval, int forever);
     57 static	void	usage(void);
     58 
     59 int
     60 main(int argc, char **argv)
     61 {
     62 	struct snapshot *old = NULL;
     63 	enum snapshot_types types = SNAP_SYSTEM;
     64 	int summary = 0;
     65 	int intr = 0;
     66 	kstat_ctl_t *kc;
     67 	int forever = 0;
     68 	hrtime_t start_n;
     69 	int c;
     70 
     71 	(void) setlocale(LC_ALL, "");
     72 #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
     73 #define	TEXT_DOMAIN "SYS_TEST"		/* Use this only if it weren't */
     74 #endif
     75 	(void) textdomain(TEXT_DOMAIN);
     76 
     77 	pagesize = sysconf(_SC_PAGESIZE);
     78 	hz = sysconf(_SC_CLK_TCK);
     79 
     80 	while ((c = getopt(argc, argv, "cipqsST:")) != EOF)
     81 		switch (c) {
     82 		case 'S':
     83 			swflag = !swflag;
     84 			break;
     85 		case 's':
     86 			summary = 1;
     87 			break;
     88 		case 'i':
     89 			intr = 1;
     90 			break;
     91 		case 'c':
     92 			cflag++;
     93 			break;
     94 		case 'q':
     95 			suppress_state = 1;
     96 			break;
     97 		case 'p':
     98 			pflag++;	/* detailed paging info */
     99 			break;
    100 		case 'T':
    101 			if (optarg) {
    102 				if (*optarg == 'u')
    103 					timestamp_fmt = UDATE;
    104 				else if (*optarg == 'd')
    105 					timestamp_fmt = DDATE;
    106 				else
    107 					usage();
    108 			} else {
    109 				usage();
    110 			}
    111 			break;
    112 		default:
    113 			usage();
    114 		}
    115 
    116 	argc -= optind;
    117 	argv += optind;
    118 
    119 	/* consistency with iostat */
    120 	types |= SNAP_CPUS;
    121 
    122 	if (intr)
    123 		types |= SNAP_INTERRUPTS;
    124 	if (cflag)
    125 		types |= SNAP_FLUSHES;
    126 	if (!intr)
    127 		types |= SNAP_IODEVS;
    128 
    129 	/* max to fit in less than 80 characters */
    130 	df.if_max_iodevs = 4;
    131 	df.if_allowed_types = IODEV_DISK;
    132 	df.if_nr_names = 0;
    133 	df.if_names = safe_alloc(df.if_max_iodevs * sizeof (char *));
    134 	(void) memset(df.if_names, 0, df.if_max_iodevs * sizeof (char *));
    135 
    136 	while (argc > 0 && !isdigit(argv[0][0]) &&
    137 	    df.if_nr_names < df.if_max_iodevs) {
    138 		df.if_names[df.if_nr_names] = *argv;
    139 		df.if_nr_names++;
    140 		argc--, argv++;
    141 	}
    142 
    143 	kc = open_kstat();
    144 
    145 	start_n = gethrtime();
    146 
    147 	ss = acquire_snapshot(kc, types, &df);
    148 
    149 	/* time, in seconds, since boot */
    150 	etime = ss->s_sys.ss_ticks / hz;
    151 
    152 	if (intr) {
    153 		dointr(ss);
    154 		free_snapshot(ss);
    155 		exit(0);
    156 	}
    157 	if (summary) {
    158 		dosum(&ss->s_sys);
    159 		free_snapshot(ss);
    160 		exit(0);
    161 	}
    162 
    163 	if (argc > 0) {
    164 		long interval;
    165 		char *endptr;
    166 
    167 		errno = 0;
    168 		interval = strtol(argv[0], &endptr, 10);
    169 
    170 		if (errno > 0 || *endptr != '\0' || interval <= 0 ||
    171 		    interval > MAXINT)
    172 			usage();
    173 		period_n = (hrtime_t)interval * NANOSEC;
    174 		if (period_n <= 0)
    175 			usage();
    176 		iter = MAXLONG;
    177 		if (argc > 1) {
    178 			iter = strtol(argv[1], NULL, 10);
    179 			if (errno > 0 || *endptr != '\0' || iter <= 0)
    180 				usage();
    181 		} else
    182 			forever = 1;
    183 		if (argc > 2)
    184 			usage();
    185 	}
    186 
    187 	if (cflag) {
    188 		free_snapshot(ss);
    189 		docachestats(kc, period_n, forever);
    190 		exit(0);
    191 	}
    192 
    193 	(void) sigset(SIGCONT, printhdr);
    194 
    195 	dovmstats(old, ss);
    196 	while (forever || --iter > 0) {
    197 		/* (void) poll(NULL, 0, poll_interval); */
    198 
    199 		/* Have a kip */
    200 		sleep_until(&start_n, period_n, forever, &caught_cont);
    201 
    202 		free_snapshot(old);
    203 		old = ss;
    204 		ss = acquire_snapshot(kc, types, &df);
    205 
    206 		if (!suppress_state)
    207 			snapshot_report_changes(old, ss);
    208 
    209 		/* if config changed, show stats from boot */
    210 		if (snapshot_has_changed(old, ss)) {
    211 			free_snapshot(old);
    212 			old = NULL;
    213 		}
    214 
    215 		dovmstats(old, ss);
    216 	}
    217 
    218 	free_snapshot(old);
    219 	free_snapshot(ss);
    220 	free(df.if_names);
    221 	(void) kstat_close(kc);
    222 	return (0);
    223 }
    224 
    225 #define	DELTA(v) (new->v - (old ? old->v : 0))
    226 #define	ADJ(n)	((adj <= 0) ? n : (adj >= n) ? 1 : n - adj)
    227 #define	adjprintf(fmt, n, val)	adj -= (n + 1) - printf(fmt, ADJ(n), val)
    228 
    229 static int adj;	/* number of excess columns */
    230 
    231 /*ARGSUSED*/
    232 static void
    233 show_disk(void *v1, void *v2, void *d)
    234 {
    235 	struct iodev_snapshot *old = (struct iodev_snapshot *)v1;
    236 	struct iodev_snapshot *new = (struct iodev_snapshot *)v2;
    237 	hrtime_t oldtime = new->is_crtime;
    238 	double hr_etime;
    239 	double reads, writes;
    240 
    241 	if (new == NULL)
    242 		return;
    243 
    244 	if (old)
    245 		oldtime = old->is_stats.wlastupdate;
    246 	hr_etime = new->is_stats.wlastupdate - oldtime;
    247 	if (hr_etime == 0.0)
    248 		hr_etime = NANOSEC;
    249 	reads = new->is_stats.reads - (old ? old->is_stats.reads : 0);
    250 	writes = new->is_stats.writes - (old ? old->is_stats.writes : 0);
    251 	adjprintf(" %*.0f", 2, (reads + writes) / hr_etime * NANOSEC);
    252 }
    253 
    254 static void
    255 dovmstats(struct snapshot *old, struct snapshot *new)
    256 {
    257 	kstat_t *oldsys = NULL;
    258 	kstat_t *newsys = &new->s_sys.ss_agg_sys;
    259 	kstat_t *oldvm = NULL;
    260 	kstat_t *newvm = &new->s_sys.ss_agg_vm;
    261 	double percent_factor;
    262 	ulong_t updates;
    263 	int count;
    264 
    265 	adj = 0;
    266 
    267 	if (old) {
    268 		oldsys = &old->s_sys.ss_agg_sys;
    269 		oldvm = &old->s_sys.ss_agg_vm;
    270 	}
    271 
    272 	etime = cpu_ticks_delta(oldsys, newsys);
    273 
    274 	percent_factor = 100.0 / denom(etime);
    275 	/*
    276 	 * If any time has passed, convert etime to seconds per CPU
    277 	 */
    278 	etime = etime >= 1.0 ? (etime / nr_active_cpus(new)) / hz : 1.0;
    279 	updates = denom(DELTA(s_sys.ss_sysinfo.updates));
    280 
    281 	if (timestamp_fmt != NODATE) {
    282 		print_timestamp(timestamp_fmt);
    283 		lines--;
    284 	}
    285 
    286 	if (--lines <= 0)
    287 		printhdr(0);
    288 
    289 	adj = 0;
    290 
    291 	if (pflag) {
    292 		adjprintf(" %*u", 6,
    293 		    pgtok((int)(DELTA(s_sys.ss_vminfo.swap_avail) / updates)));
    294 		adjprintf(" %*u", 5,
    295 		    pgtok((int)(DELTA(s_sys.ss_vminfo.freemem) / updates)));
    296 		adjprintf(" %*.0f", 3, kstat_delta(oldvm, newvm, "pgrec")
    297 		    / etime);
    298 		adjprintf(" %*.0f", 3, (kstat_delta(oldvm, newvm, "hat_fault") +
    299 		    kstat_delta(oldvm, newvm, "as_fault")) / etime);
    300 		adjprintf(" %*.0f", 3, pgtok(kstat_delta(oldvm, newvm, "dfree"))
    301 		    / etime);
    302 		adjprintf(" %*ld", 3, pgtok(new->s_sys.ss_deficit));
    303 		adjprintf(" %*.0f", 3, kstat_delta(oldvm, newvm, "scan")
    304 		    / etime);
    305 		adjprintf(" %*.0f", 4,
    306 		    pgtok(kstat_delta(oldvm, newvm, "execpgin")) / etime);
    307 		adjprintf(" %*.0f", 4,
    308 		    pgtok(kstat_delta(oldvm, newvm, "execpgout")) / etime);
    309 		adjprintf(" %*.0f", 4,
    310 		    pgtok(kstat_delta(oldvm, newvm, "execfree")) / etime);
    311 		adjprintf(" %*.0f", 4,
    312 		    pgtok(kstat_delta(oldvm, newvm, "anonpgin")) / etime);
    313 		adjprintf(" %*.0f", 4,
    314 		    pgtok(kstat_delta(oldvm, newvm, "anonpgout")) / etime);
    315 		adjprintf(" %*.0f", 4,
    316 		    pgtok(kstat_delta(oldvm, newvm, "anonfree")) / etime);
    317 		adjprintf(" %*.0f", 4,
    318 		    pgtok(kstat_delta(oldvm, newvm, "fspgin")) / etime);
    319 		adjprintf(" %*.0f", 4,
    320 		    pgtok(kstat_delta(oldvm, newvm, "fspgout")) / etime);
    321 		adjprintf(" %*.0f\n", 4,
    322 		    pgtok(kstat_delta(oldvm, newvm, "fsfree")) / etime);
    323 		(void) fflush(stdout);
    324 		return;
    325 	}
    326 
    327 	adjprintf(" %*lu", 1, DELTA(s_sys.ss_sysinfo.runque) / updates);
    328 	adjprintf(" %*lu", 1, DELTA(s_sys.ss_sysinfo.waiting) / updates);
    329 	adjprintf(" %*lu", 1, DELTA(s_sys.ss_sysinfo.swpque) / updates);
    330 	adjprintf(" %*u", 6, pgtok((int)(DELTA(s_sys.ss_vminfo.swap_avail)
    331 	    / updates)));
    332 	adjprintf(" %*u", 5, pgtok((int)(DELTA(s_sys.ss_vminfo.freemem)
    333 	    / updates)));
    334 	adjprintf(" %*.0f", 3, swflag?
    335 	    kstat_delta(oldvm, newvm, "swapin") / etime :
    336 	    kstat_delta(oldvm, newvm, "pgrec") / etime);
    337 	adjprintf(" %*.0f", 3, swflag?
    338 	    kstat_delta(oldvm, newvm, "swapout") / etime :
    339 	    (kstat_delta(oldvm, newvm, "hat_fault")
    340 	    + kstat_delta(oldvm, newvm, "as_fault"))
    341 	    / etime);
    342 	adjprintf(" %*.0f", 2, pgtok(kstat_delta(oldvm, newvm, "pgpgin"))
    343 	    / etime);
    344 	adjprintf(" %*.0f", 2, pgtok(kstat_delta(oldvm, newvm, "pgpgout"))
    345 	    / etime);
    346 	adjprintf(" %*.0f", 2, pgtok(kstat_delta(oldvm, newvm, "dfree"))
    347 	    / etime);
    348 	adjprintf(" %*ld", 2, pgtok(new->s_sys.ss_deficit));
    349 	adjprintf(" %*.0f", 2, kstat_delta(oldvm, newvm, "scan") / etime);
    350 
    351 	(void) snapshot_walk(SNAP_IODEVS, old, new, show_disk, NULL);
    352 
    353 	count = df.if_max_iodevs - new->s_nr_iodevs;
    354 	while (count-- > 0)
    355 		adjprintf(" %*d", 2, 0);
    356 
    357 	adjprintf(" %*.0f", 4, kstat_delta(oldsys, newsys, "intr") / etime);
    358 	adjprintf(" %*.0f", 4, kstat_delta(oldsys, newsys, "syscall") / etime);
    359 	adjprintf(" %*.0f", 4, kstat_delta(oldsys, newsys, "pswitch") / etime);
    360 	adjprintf(" %*.0f", 2,
    361 	    kstat_delta(oldsys, newsys, "cpu_ticks_user") * percent_factor);
    362 	adjprintf(" %*.0f", 2, kstat_delta(oldsys, newsys, "cpu_ticks_kernel")
    363 	    * percent_factor);
    364 	adjprintf(" %*.0f\n", 2, (kstat_delta(oldsys, newsys, "cpu_ticks_idle")
    365 	    + kstat_delta(oldsys, newsys, "cpu_ticks_wait"))
    366 	    * percent_factor);
    367 	(void) fflush(stdout);
    368 }
    369 
    370 /*ARGSUSED*/
    371 static void
    372 print_disk(void *v, void *v2, void *d)
    373 {
    374 	struct iodev_snapshot *iodev = (struct iodev_snapshot *)v2;
    375 
    376 	if (iodev == NULL)
    377 		return;
    378 
    379 	(void) printf("%c%c ", iodev->is_name[0], iodev->is_name[2]);
    380 }
    381 
    382 /* ARGSUSED */
    383 static void
    384 printhdr(int sig)
    385 {
    386 	int i = df.if_max_iodevs - ss->s_nr_iodevs;
    387 
    388 	if (sig == SIGCONT)
    389 		caught_cont = 1;
    390 
    391 	if (pflag) {
    392 		(void) printf("     memory           page          ");
    393 		(void) printf("executable      anonymous      filesystem \n");
    394 		(void) printf("   swap  free  re  mf  fr  de  sr  ");
    395 		(void) printf("epi  epo  epf  api  apo  apf  fpi  fpo  fpf\n");
    396 		lines = REPRINT;
    397 		return;
    398 	}
    399 
    400 	(void) printf(" kthr      memory            page            ");
    401 	(void) printf("disk          faults      cpu\n");
    402 
    403 	if (swflag)
    404 		(void) printf(" r b w   swap  free  si  so pi po fr de sr ");
    405 	else
    406 		(void) printf(" r b w   swap  free  re  mf pi po fr de sr ");
    407 
    408 	(void) snapshot_walk(SNAP_IODEVS, NULL, ss, print_disk, NULL);
    409 
    410 	while (i-- > 0)
    411 		(void) printf("-- ");
    412 
    413 	(void) printf("  in   sy   cs us sy id\n");
    414 	lines = REPRINT;
    415 }
    416 
    417 static void
    418 sum_out(char const *pretty, kstat_t *ks, char *name)
    419 {
    420 	kstat_named_t *ksn = kstat_data_lookup(ks, name);
    421 	if (ksn == NULL) {
    422 		fail(0, "kstat_data_lookup('%s', '%s') failed",
    423 		    ks->ks_name, name);
    424 	}
    425 
    426 	(void) printf("%9llu %s\n", ksn->value.ui64, pretty);
    427 }
    428 
    429 static void
    430 dosum(struct sys_snapshot *ss)
    431 {
    432 	uint64_t total_faults;
    433 	kstat_named_t *ksn;
    434 	long double nchtotal;
    435 	uint64_t nchhits;
    436 
    437 	sum_out("swap ins", &ss->ss_agg_vm, "swapin");
    438 	sum_out("swap outs", &ss->ss_agg_vm, "swapout");
    439 	sum_out("pages swapped in", &ss->ss_agg_vm, "pgswapin");
    440 	sum_out("pages swapped out", &ss->ss_agg_vm, "pgswapout");
    441 
    442 	ksn = kstat_data_lookup(&ss->ss_agg_vm, "hat_fault");
    443 	if (ksn == NULL) {
    444 		fail(0, "kstat_data_lookup('%s', 'hat_fault') failed",
    445 		    ss->ss_agg_vm.ks_name);
    446 	}
    447 	total_faults = ksn->value.ui64;
    448 	ksn = kstat_data_lookup(&ss->ss_agg_vm, "as_fault");
    449 	if (ksn == NULL) {
    450 		fail(0, "kstat_data_lookup('%s', 'as_fault') failed",
    451 		    ss->ss_agg_vm.ks_name);
    452 	}
    453 	total_faults += ksn->value.ui64;
    454 
    455 	(void) printf("%9llu total address trans. faults taken\n",
    456 	    total_faults);
    457 
    458 	sum_out("page ins", &ss->ss_agg_vm, "pgin");
    459 	sum_out("page outs", &ss->ss_agg_vm, "pgout");
    460 	sum_out("pages paged in", &ss->ss_agg_vm, "pgpgin");
    461 	sum_out("pages paged out", &ss->ss_agg_vm, "pgpgout");
    462 	sum_out("total reclaims", &ss->ss_agg_vm, "pgrec");
    463 	sum_out("reclaims from free list", &ss->ss_agg_vm, "pgfrec");
    464 	sum_out("micro (hat) faults", &ss->ss_agg_vm, "hat_fault");
    465 	sum_out("minor (as) faults", &ss->ss_agg_vm, "as_fault");
    466 	sum_out("major faults", &ss->ss_agg_vm, "maj_fault");
    467 	sum_out("copy-on-write faults", &ss->ss_agg_vm, "cow_fault");
    468 	sum_out("zero fill page faults", &ss->ss_agg_vm, "zfod");
    469 	sum_out("pages examined by the clock daemon", &ss->ss_agg_vm, "scan");
    470 	sum_out("revolutions of the clock hand", &ss->ss_agg_vm, "rev");
    471 	sum_out("pages freed by the clock daemon", &ss->ss_agg_vm, "dfree");
    472 	sum_out("forks", &ss->ss_agg_sys, "sysfork");
    473 	sum_out("vforks", &ss->ss_agg_sys, "sysvfork");
    474 	sum_out("execs", &ss->ss_agg_sys, "sysexec");
    475 	sum_out("cpu context switches", &ss->ss_agg_sys, "pswitch");
    476 	sum_out("device interrupts", &ss->ss_agg_sys, "intr");
    477 	sum_out("traps", &ss->ss_agg_sys, "trap");
    478 	sum_out("system calls", &ss->ss_agg_sys, "syscall");
    479 
    480 	nchtotal = (long double) ss->ss_nc.ncs_hits.value.ui64 +
    481 	    (long double) ss->ss_nc.ncs_misses.value.ui64;
    482 	nchhits = ss->ss_nc.ncs_hits.value.ui64;
    483 	(void) printf("%9.0Lf total name lookups (cache hits %.0Lf%%)\n",
    484 	    nchtotal, nchhits / denom(nchtotal) * 100);
    485 
    486 	sum_out("user   cpu", &ss->ss_agg_sys, "cpu_ticks_user");
    487 	sum_out("system cpu", &ss->ss_agg_sys, "cpu_ticks_kernel");
    488 	sum_out("idle   cpu", &ss->ss_agg_sys, "cpu_ticks_idle");
    489 	sum_out("wait   cpu", &ss->ss_agg_sys, "cpu_ticks_wait");
    490 }
    491 
    492 static void
    493 dointr(struct snapshot *ss)
    494 {
    495 	size_t i;
    496 	ulong_t total = 0;
    497 
    498 	(void) printf("interrupt         total     rate\n");
    499 	(void) printf("--------------------------------\n");
    500 
    501 	for (i = 0; i < ss->s_nr_intrs; i++) {
    502 		(void) printf("%-12.8s %10lu %8.0f\n",
    503 		    ss->s_intrs[i].is_name, ss->s_intrs[i].is_total,
    504 		    ss->s_intrs[i].is_total / etime);
    505 		total += ss->s_intrs[i].is_total;
    506 	}
    507 
    508 	(void) printf("--------------------------------\n");
    509 	(void) printf("Total        %10lu %8.0f\n", total, total / etime);
    510 }
    511 
    512 static void
    513 docachestats(kstat_ctl_t *kc, hrtime_t interval, int forever)
    514 {
    515 	struct snapshot *old;
    516 	struct snapshot *new;
    517 	int i;
    518 	hrtime_t start;
    519 
    520 	start = gethrtime();
    521 	old = acquire_snapshot(kc, SNAP_FLUSHES, NULL);
    522 
    523 	if (iter == 0) {
    524 		(void) printf("flush statistics: (totals)\n");
    525 		(void) printf("%8s%8s%8s%8s%8s%8s\n",
    526 		    "usr", "ctx", "rgn", "seg", "pag", "par");
    527 		(void) printf(" %7d %7d %7d %7d %7d %7d\n",
    528 		    old->s_flushes.f_usr, old->s_flushes.f_ctx,
    529 		    old->s_flushes.f_region, old->s_flushes.f_segment,
    530 		    old->s_flushes.f_page, old->s_flushes.f_partial);
    531 		return;
    532 	}
    533 
    534 	(void) printf("flush statistics: (interval based)\n");
    535 	for (i = 0; i < iter; i++) {
    536 		if (i % REPRINT == 0)
    537 			(void) printf("%8s%8s%8s%8s%8s%8s\n",
    538 			    "usr", "ctx", "rgn", "seg", "pag", "par");
    539 
    540 		/* Have a kip */
    541 		sleep_until(&start, interval, forever, &caught_cont);
    542 
    543 		new = acquire_snapshot(kc, SNAP_FLUSHES, NULL);
    544 
    545 		(void) printf(" %7d %7d %7d %7d %7d %7d\n",
    546 		    new->s_flushes.f_usr - old->s_flushes.f_usr,
    547 		    new->s_flushes.f_ctx - old->s_flushes.f_ctx,
    548 		    new->s_flushes.f_region - old->s_flushes.f_region,
    549 		    new->s_flushes.f_segment - old->s_flushes.f_segment,
    550 		    new->s_flushes.f_page - old->s_flushes.f_page,
    551 		    new->s_flushes.f_partial- old->s_flushes.f_partial);
    552 		(void) fflush(stdout);
    553 		free_snapshot(old);
    554 		old = new;
    555 	}
    556 }
    557 
    558 static void
    559 usage(void)
    560 {
    561 	(void) fprintf(stderr,
    562 	    "Usage: vmstat [-cipqsS] [-T d|u] [disk ...] "
    563 	    "[interval [count]]\n");
    564 	exit(1);
    565 }
    566