X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/8ad349bb6ed4a0be06e34c92be0d98b92e078db4..39236c6e673c41db228275375ab7fdb0f837b292:/osfmk/kern/sched_average.c diff --git a/osfmk/kern/sched_average.c b/osfmk/kern/sched_average.c index bfa1d2ef0..b3edb3d9c 100644 --- a/osfmk/kern/sched_average.c +++ b/osfmk/kern/sched_average.c @@ -1,31 +1,29 @@ /* - * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2007 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. The rights granted to you under the - * License may not be used to create, or enable the creation or - * redistribution of, unlawful or unlicensed copies of an Apple operating - * system, or to circumvent, violate, or enable the circumvention or - * violation of, any terms of an Apple operating system software license - * agreement. - * - * Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and * limitations under the License. - * - * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ @@ -70,10 +68,14 @@ #include #include #include +#if CONFIG_TELEMETRY +#include +#endif uint32_t avenrun[3] = {0, 0, 0}; uint32_t mach_factor[3] = {0, 0, 0}; +#if defined(CONFIG_SCHED_TRADITIONAL) /* * Values are scaled by LOAD_SCALE, defined in processor_info.h */ @@ -89,104 +91,147 @@ static uint32_t fract[3] = { #undef base #undef frac +#endif /* CONFIG_SCHED_TRADITIONAL */ + static unsigned int sched_nrun; typedef void (*sched_avg_comp_t)( void *param); -#define SCHED_AVG_SECS(n) ((n) << SCHED_TICK_SHIFT) - static struct sched_average { sched_avg_comp_t comp; - void *param; - int period; - int tick; + void *param; + int period; /* in seconds */ + uint64_t deadline; } sched_average[] = { - { compute_averunnable, &sched_nrun, SCHED_AVG_SECS(5), 0 }, - { compute_stack_target, NULL, SCHED_AVG_SECS(5), 1 }, + { compute_averunnable, &sched_nrun, 5, 0 }, + { compute_stack_target, NULL, 5, 1 }, + { compute_memory_pressure, NULL, 1, 0 }, + { compute_zone_gc_throttle, NULL, 60, 0 }, + { compute_pageout_gc_throttle, NULL, 1, 0 }, + { compute_pmap_gc_throttle, NULL, 60, 0 }, +#if CONFIG_TELEMETRY + { compute_telemetry, NULL, 1, 0 }, +#endif { NULL, NULL, 0, 0 } }; typedef struct sched_average *sched_average_t; +/* The "stdelta" parameter represents the number of scheduler maintenance + * "ticks" that have elapsed since the last invocation, subject to + * integer division imprecision. + */ + void -compute_averages(void) +compute_averages(uint64_t stdelta) { - register processor_set_t pset = &default_pset; - register int ncpus; - register int nthreads, nshared; - sched_average_t avg; - register uint32_t factor_now = 0; - register uint32_t average_now = 0; - register uint32_t load_now = 0; - - if ((ncpus = pset->processor_count) > 0) { - /* - * Retrieve counts, ignoring - * the current thread. - */ - nthreads = pset->run_count - 1; - nshared = pset->share_count; - - /* - * Load average and mach factor calculations for - * those which ask about these things. - */ - average_now = nthreads * LOAD_SCALE; - - if (nthreads > ncpus) - factor_now = (ncpus * LOAD_SCALE) / (nthreads + 1); + int ncpus, nthreads, nshared, nbackground, nshared_non_bg; + uint32_t factor_now, average_now, load_now = 0, background_load_now = 0, combined_fgbg_load_now = 0; + sched_average_t avg; + uint64_t abstime, index; + + /* + * Retrieve counts, ignoring + * the current thread. + */ + ncpus = processor_avail_count; + nthreads = sched_run_count - 1; + nshared = sched_share_count; + nbackground = sched_background_count; + + /* + * Load average and mach factor calculations for + * those which ask about these things. + */ + average_now = nthreads * LOAD_SCALE; + + if (nthreads > ncpus) + factor_now = (ncpus * LOAD_SCALE) / (nthreads + 1); + else + factor_now = (ncpus - nthreads) * LOAD_SCALE; + + /* For those statistics that formerly relied on being recomputed + * on timer ticks, advance by the approximate number of corresponding + * elapsed intervals, thus compensating for potential idle intervals. + */ + for (index = 0; index < stdelta; index++) { + sched_mach_factor = ((sched_mach_factor << 2) + factor_now) / 5; + sched_load_average = ((sched_load_average << 2) + average_now) / 5; + } + /* + * Compute the timeshare priority conversion factor based on loading. + * Because our counters may be incremented and accessed + * concurrently with respect to each other, we may have + * windows where the invariant nthreads >= nshared >= nbackground + * is broken, so truncate values in these cases. + */ + + if (nshared > nthreads) + nshared = nthreads; + + if (nbackground > nshared) + nbackground = nshared; + + nshared_non_bg = nshared - nbackground; + + if (nshared_non_bg > ncpus) { + if (ncpus > 1) + load_now = nshared_non_bg / ncpus; else - factor_now = (ncpus - nthreads) * LOAD_SCALE; - - pset->mach_factor = ((pset->mach_factor << 2) + factor_now) / 5; - pset->load_average = ((pset->load_average << 2) + average_now) / 5; - - /* - * Compute the timeshare priority - * conversion factor based on loading. - */ - if (nshared > nthreads) - nshared = nthreads; - - if (nshared > ncpus) { - if (ncpus > 1) - load_now = nshared / ncpus; - else - load_now = nshared; - - if (load_now > NRQS - 1) - load_now = NRQS - 1; - } + load_now = nshared_non_bg; + + if (load_now > NRQS - 1) + load_now = NRQS - 1; + } + + if (nbackground > ncpus) { + if (ncpus > 1) + background_load_now = nbackground / ncpus; + else + background_load_now = nbackground; - /* - * The conversion factor consists of - * two components: a fixed value based - * on the absolute time unit, and a - * dynamic portion based on loading. - * - * Zero loading results in a out of range - * shift count. Accumulated usage is ignored - * during conversion and new usage deltas - * are discarded. - */ - pset->pri_shift = sched_pri_shift - sched_load_shifts[load_now]; + if (background_load_now > NRQS - 1) + background_load_now = NRQS - 1; } - else { - pset->mach_factor = pset->load_average = 0; - pset->pri_shift = INT8_MAX; - nthreads = pset->run_count; + + if (nshared > ncpus) { + if (ncpus > 1) + combined_fgbg_load_now = nshared / ncpus; + else + combined_fgbg_load_now = nshared; + + if (combined_fgbg_load_now > NRQS - 1) + combined_fgbg_load_now = NRQS - 1; } /* * Sample total running threads. */ sched_nrun = nthreads; + +#if defined(CONFIG_SCHED_TRADITIONAL) + + /* + * The conversion factor consists of + * two components: a fixed value based + * on the absolute time unit, and a + * dynamic portion based on loading. + * + * Zero loading results in a out of range + * shift count. Accumulated usage is ignored + * during conversion and new usage deltas + * are discarded. + */ + sched_pri_shift = sched_fixed_shift - sched_load_shifts[load_now]; + sched_background_pri_shift = sched_fixed_shift - sched_load_shifts[background_load_now]; + sched_combined_fgbg_pri_shift = sched_fixed_shift - sched_load_shifts[combined_fgbg_load_now]; /* * Compute old-style Mach load averages. */ - { + + for (index = 0; index < stdelta; index++) { register int i; for (i = 0; i < 3; i++) { @@ -197,14 +242,24 @@ compute_averages(void) (average_now * (LOAD_SCALE - fract[i]))) / LOAD_SCALE; } } +#endif /* CONFIG_SCHED_TRADITIONAL */ /* * Compute averages in other components. */ + abstime = mach_absolute_time(); for (avg = sched_average; avg->comp != NULL; ++avg) { - if (++avg->tick >= avg->period) { - (*avg->comp)(avg->param); - avg->tick = 0; + if (abstime >= avg->deadline) { + uint64_t period_abs = (avg->period * sched_one_second_interval); + uint64_t ninvokes = 1; + + ninvokes += (abstime - avg->deadline) / period_abs; + ninvokes = MIN(ninvokes, SCHED_TICK_MAX_DELTA); + + for (index = 0; index < ninvokes; index++) { + (*avg->comp)(avg->param); + } + avg->deadline = abstime + period_abs; } } }