diff options
Diffstat (limited to 'usr/src')
| -rw-r--r-- | usr/src/uts/common/os/clock.c | 5 | ||||
| -rw-r--r-- | usr/src/uts/common/os/kstat_fr.c | 9 | ||||
| -rw-r--r-- | usr/src/uts/common/os/zone.c | 94 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/zone.h | 9 | ||||
| -rw-r--r-- | usr/src/uts/common/syscall/getloadavg.c | 14 | 
5 files changed, 111 insertions, 20 deletions
| diff --git a/usr/src/uts/common/os/clock.c b/usr/src/uts/common/os/clock.c index 70286146d9..3421ae28d1 100644 --- a/usr/src/uts/common/os/clock.c +++ b/usr/src/uts/common/os/clock.c @@ -67,6 +67,7 @@  #include <sys/ddi_periodic.h>  #include <sys/random.h>  #include <sys/modctl.h> +#include <sys/zone.h>  /*   * for NTP support @@ -1149,6 +1150,10 @@ loadavg_update()  	} while ((cpupart = cpupart->cp_next) != cp_list_head); +	/* +	 * Third pass totals up per-zone statistics. +	 */ +	zone_loadavg_update();  }  /* diff --git a/usr/src/uts/common/os/kstat_fr.c b/usr/src/uts/common/os/kstat_fr.c index 31ba702346..3f055e6cde 100644 --- a/usr/src/uts/common/os/kstat_fr.c +++ b/usr/src/uts/common/os/kstat_fr.c @@ -806,7 +806,6 @@ system_misc_kstat_update(kstat_t *ksp, int rw)  {  	int myncpus = ncpus;  	int *loadavgp = &avenrun[0]; -	int loadavg[LOADAVG_NSTATS];  	time_t zone_boot_time;  	clock_t zone_lbolt;  	hrtime_t zone_hrtime; @@ -823,17 +822,11 @@ system_misc_kstat_update(kstat_t *ksp, int rw)  		 */  		mutex_enter(&cpu_lock);  		if (pool_pset_enabled()) { -			psetid_t mypsid = zone_pset_get(curproc->p_zone); -			int error; -  			myncpus = zone_ncpus_get(curproc->p_zone);  			ASSERT(myncpus > 0); -			error = cpupart_get_loadavg(mypsid, &loadavg[0], -			    LOADAVG_NSTATS); -			ASSERT(error == 0); -			loadavgp = &loadavg[0];  		}  		mutex_exit(&cpu_lock); +		loadavgp = &curproc->p_zone->zone_avenrun[0];  	}  	if (INGLOBALZONE(curproc)) { diff --git a/usr/src/uts/common/os/zone.c b/usr/src/uts/common/os/zone.c index 84467a6659..444b455e5e 100644 --- a/usr/src/uts/common/os/zone.c +++ b/usr/src/uts/common/os/zone.c @@ -1841,6 +1841,10 @@ zone_misc_kstat_update(kstat_t *ksp, int rw)  	scalehrtime(&tmp);  	zmp->zm_wtime.value.ui64 = tmp; +	zmp->zm_avenrun1.value.ui32 = zone->zone_avenrun[0]; +	zmp->zm_avenrun5.value.ui32 = zone->zone_avenrun[1]; +	zmp->zm_avenrun15.value.ui32 = zone->zone_avenrun[2]; +  	return (0);  } @@ -1870,6 +1874,10 @@ zone_misc_kstat_create(zone_t *zone)  	kstat_named_init(&zmp->zm_utime, "nsec_user", KSTAT_DATA_UINT64);  	kstat_named_init(&zmp->zm_stime, "nsec_sys", KSTAT_DATA_UINT64);  	kstat_named_init(&zmp->zm_wtime, "nsec_waitrq", KSTAT_DATA_UINT64); +	kstat_named_init(&zmp->zm_avenrun1, "avenrun_1min", KSTAT_DATA_UINT32); +	kstat_named_init(&zmp->zm_avenrun5, "avenrun_5min", KSTAT_DATA_UINT32); +	kstat_named_init(&zmp->zm_avenrun15, "avenrun_15min", +	    KSTAT_DATA_UINT32);  	ksp->ks_update = zone_misc_kstat_update;  	ksp->ks_private = zone; @@ -3050,6 +3058,92 @@ zone_find_by_path(const char *path)  }  /* + * Public interface for updating per-zone load averages.  Called once per + * second. + * + * Based on loadavg_update(), genloadavg() and calcloadavg() from clock.c. + */ +void +zone_loadavg_update() +{ +	zone_t *zp; +	zone_status_t status; +	struct loadavg_s *lavg; +	hrtime_t zone_total; +	int i; +	hrtime_t hr_avg; +	int nrun; +	static int64_t f[3] = { 135, 27, 9 }; +	int64_t q, r; + +	mutex_enter(&zonehash_lock); +	for (zp = list_head(&zone_active); zp != NULL; +	    zp = list_next(&zone_active, zp)) { +		mutex_enter(&zp->zone_lock); + +		/* Skip zones that are on the way down or not yet up */ +		status = zone_status_get(zp); +		if (status < ZONE_IS_READY || status >= ZONE_IS_DOWN) { +			/* For all practical purposes the zone doesn't exist. */ +			mutex_exit(&zp->zone_lock); +			continue; +		} + +		/* +		 * Update the 10 second moving average data in zone_loadavg. +		 */ +		lavg = &zp->zone_loadavg; + +		zone_total = zp->zone_utime + zp->zone_stime + zp->zone_wtime; +		scalehrtime(&zone_total); + +		/* The zone_total should always be increasing. */ +		lavg->lg_loads[lavg->lg_cur] = (zone_total > lavg->lg_total) ? +		    zone_total - lavg->lg_total : 0; +		lavg->lg_cur = (lavg->lg_cur + 1) % S_LOADAVG_SZ; +		/* lg_total holds the prev. 1 sec. total */ +		lavg->lg_total = zone_total; + +		/* +		 * To simplify the calculation, we don't calculate the load avg. +		 * until the zone has been up for at least 10 seconds and our +		 * moving average is thus full. +		 */ +		if ((lavg->lg_len + 1) < S_LOADAVG_SZ) { +			lavg->lg_len++; +			mutex_exit(&zp->zone_lock); +			continue; +		} + +		/* Now calculate the 1min, 5min, 15 min load avg. */ +		hr_avg = 0; +		for (i = 0; i < S_LOADAVG_SZ; i++) +			hr_avg += lavg->lg_loads[i]; +		hr_avg = hr_avg / S_LOADAVG_SZ; +		nrun = hr_avg / (NANOSEC / LGRP_LOADAVG_IN_THREAD_MAX); + +		/* Compute load avg. See comment in calcloadavg() */ +		for (i = 0; i < 3; i++) { +			q = (zp->zone_hp_avenrun[i] >> 16) << 7; +			r = (zp->zone_hp_avenrun[i] & 0xffff) << 7; +			zp->zone_hp_avenrun[i] += +			    ((nrun - q) * f[i] - ((r * f[i]) >> 16)) >> 4; + +			/* avenrun[] can only hold 31 bits of load avg. */ +			if (zp->zone_hp_avenrun[i] < +			    ((uint64_t)1<<(31+16-FSHIFT))) +				zp->zone_avenrun[i] = (int32_t) +				    (zp->zone_hp_avenrun[i] >> (16 - FSHIFT)); +			else +				zp->zone_avenrun[i] = 0x7fffffff; +		} + +		mutex_exit(&zp->zone_lock); +	} +	mutex_exit(&zonehash_lock); +} + +/*   * Get the number of cpus visible to this zone.  The system-wide global   * 'ncpus' is returned if pools are disabled, the caller is in the   * global zone, or a NULL zone argument is passed in. diff --git a/usr/src/uts/common/sys/zone.h b/usr/src/uts/common/sys/zone.h index 18c2a9ef4b..6d6d324843 100644 --- a/usr/src/uts/common/sys/zone.h +++ b/usr/src/uts/common/sys/zone.h @@ -321,6 +321,7 @@ typedef struct zone_net_data {   * libraries which may be defining ther own versions.   */  #include <sys/list.h> +#include <sys/cpuvar.h>  #define	GLOBAL_ZONEUNIQID	0	/* uniqid of the global zone */ @@ -383,6 +384,9 @@ typedef struct {  	kstat_named_t	zm_utime;  	kstat_named_t	zm_stime;  	kstat_named_t	zm_wtime; +	kstat_named_t	zm_avenrun1; +	kstat_named_t	zm_avenrun5; +	kstat_named_t	zm_avenrun15;  } zone_misc_kstat_t;  typedef struct zone { @@ -565,6 +569,10 @@ typedef struct zone {  	uint64_t	zone_utime;		/* total user time */  	uint64_t	zone_wtime;		/* total time waiting in runq */ +	struct loadavg_s zone_loadavg;		/* loadavg for this zone */ +	uint64_t	zone_hp_avenrun[3];	/* high-precision avenrun */ +	int		zone_avenrun[3];	/* FSCALED avg. run queue len */ +  	/*  	 * DTrace-private per-zone state  	 */ @@ -604,6 +612,7 @@ extern zoneid_t getzoneid(void);  extern zone_t *zone_find_by_id_nolock(zoneid_t);  extern int zone_datalink_walk(zoneid_t, int (*)(datalink_id_t, void *), void *);  extern int zone_check_datalink(zoneid_t *, datalink_id_t); +extern void zone_loadavg_update();  /*   * Zone-specific data (ZSD) APIs diff --git a/usr/src/uts/common/syscall/getloadavg.c b/usr/src/uts/common/syscall/getloadavg.c index c669f9b8ba..0f44064e90 100644 --- a/usr/src/uts/common/syscall/getloadavg.c +++ b/usr/src/uts/common/syscall/getloadavg.c @@ -22,10 +22,9 @@  /*   * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.   * Use is subject to license terms. + * Copyright 2011 Joyent, Inc.  All rights reserved.   */ -#pragma ident	"%Z%%M%	%I%	%E% SMI" -  #include <sys/types.h>  #include <sys/systm.h>  #include <sys/errno.h> @@ -41,7 +40,6 @@ int  getloadavg(int *buf, int nelem)  {  	int *loadbuf = &avenrun[0]; -	int loadavg[LOADAVG_NSTATS];  	int error;  	if (nelem < 0) @@ -50,15 +48,7 @@ getloadavg(int *buf, int nelem)  		nelem = LOADAVG_NSTATS;  	if (!INGLOBALZONE(curproc)) { -		mutex_enter(&cpu_lock); -		if (pool_pset_enabled()) { -			psetid_t psetid = zone_pset_get(curproc->p_zone); - -			error = cpupart_get_loadavg(psetid, &loadavg[0], nelem); -			ASSERT(error == 0);	/* pset isn't going anywhere */ -			loadbuf = &loadavg[0]; -		} -		mutex_exit(&cpu_lock); +		loadbuf = &curproc->p_zone->zone_avenrun[0];  	}  	error = copyout(loadbuf, buf, nelem * sizeof (avenrun[0])); | 
