sched_ule.c revision 113371
1230130Smav/*-
2230130Smav * Copyright (c) 2002-2003, Jeffrey Roberson <jeff@freebsd.org>
3230130Smav * All rights reserved.
4230130Smav *
5230130Smav * Redistribution and use in source and binary forms, with or without
6230130Smav * modification, are permitted provided that the following conditions
7230130Smav * are met:
8230130Smav * 1. Redistributions of source code must retain the above copyright
9230130Smav *    notice unmodified, this list of conditions, and the following
10230130Smav *    disclaimer.
11230130Smav * 2. Redistributions in binary form must reproduce the above copyright
12230130Smav *    notice, this list of conditions and the following disclaimer in the
13230130Smav *    documentation and/or other materials provided with the distribution.
14230130Smav *
15230130Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16230130Smav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17230130Smav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18230130Smav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19230130Smav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20230130Smav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21230130Smav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22230130Smav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23230130Smav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24230130Smav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25230130Smav *
26230130Smav * $FreeBSD: head/sys/kern/sched_ule.c 113371 2003-04-11 18:40:34Z jeff $
27230130Smav */
28230130Smav
29230130Smav#include <sys/param.h>
30230130Smav#include <sys/systm.h>
31230130Smav#include <sys/kernel.h>
32230130Smav#include <sys/ktr.h>
33230130Smav#include <sys/lock.h>
34230130Smav#include <sys/mutex.h>
35230130Smav#include <sys/proc.h>
36230130Smav#include <sys/resource.h>
37230130Smav#include <sys/sched.h>
38230130Smav#include <sys/smp.h>
39230130Smav#include <sys/sx.h>
40230130Smav#include <sys/sysctl.h>
41230130Smav#include <sys/sysproto.h>
42230130Smav#include <sys/vmmeter.h>
43230130Smav#ifdef DDB
44230130Smav#include <ddb/ddb.h>
45230130Smav#endif
46230130Smav#ifdef KTRACE
47230130Smav#include <sys/uio.h>
48230130Smav#include <sys/ktrace.h>
49230130Smav#endif
50230130Smav
51230130Smav#include <machine/cpu.h>
52230130Smav
53230130Smav#define KTR_ULE         KTR_NFS
54230130Smav
55230130Smav/* decay 95% of `p_pctcpu' in 60 seconds; see CCPU_SHIFT before changing */
56230130Smav/* XXX This is bogus compatability crap for ps */
57230130Smavstatic fixpt_t  ccpu = 0.95122942450071400909 * FSCALE; /* exp(-1/20) */
58230130SmavSYSCTL_INT(_kern, OID_AUTO, ccpu, CTLFLAG_RD, &ccpu, 0, "");
59230130Smav
60230130Smavstatic void sched_setup(void *dummy);
61230130SmavSYSINIT(sched_setup, SI_SUB_RUN_QUEUE, SI_ORDER_FIRST, sched_setup, NULL)
62230130Smav
63230130Smavstatic SYSCTL_NODE(_kern, OID_AUTO, sched, CTLFLAG_RW, 0, "SCHED");
64230130Smav
65230130Smavstatic int sched_strict;
66230130SmavSYSCTL_INT(_kern_sched, OID_AUTO, strict, CTLFLAG_RD, &sched_strict, 0, "");
67230130Smav
68230130Smavstatic int slice_min = 1;
69230130SmavSYSCTL_INT(_kern_sched, OID_AUTO, slice_min, CTLFLAG_RW, &slice_min, 0, "");
70230130Smav
71230130Smavstatic int slice_max = 2;
72230130SmavSYSCTL_INT(_kern_sched, OID_AUTO, slice_max, CTLFLAG_RW, &slice_max, 0, "");
73230130Smav
74264832Smariusint realstathz;
75230130Smavint tickincr = 1;
76230130Smav
77230130Smav/*
78230130Smav * These datastructures are allocated within their parent datastructure but
79230130Smav * are scheduler specific.
80230130Smav */
81230130Smav
82230130Smavstruct ke_sched {
83230130Smav	int		ske_slice;
84230130Smav	struct runq	*ske_runq;
85230130Smav	/* The following variables are only used for pctcpu calculation */
86230130Smav	int		ske_ltick;	/* Last tick that we were running on */
87230130Smav	int		ske_ftick;	/* First tick that we were running on */
88230130Smav	int		ske_ticks;	/* Tick count */
89230130Smav	/* CPU that we have affinity for. */
90281544Srpaulo	u_char		ske_cpu;
91230130Smav};
92230130Smav#define	ke_slice	ke_sched->ske_slice
93230130Smav#define	ke_runq		ke_sched->ske_runq
94230130Smav#define	ke_ltick	ke_sched->ske_ltick
95230130Smav#define	ke_ftick	ke_sched->ske_ftick
96230571Smav#define	ke_ticks	ke_sched->ske_ticks
97230571Smav#define	ke_cpu		ke_sched->ske_cpu
98230130Smav
99230130Smavstruct kg_sched {
100230130Smav	int	skg_slptime;		/* Number of ticks we vol. slept */
101230130Smav	int	skg_runtime;		/* Number of ticks we were running */
102230130Smav};
103230130Smav#define	kg_slptime	kg_sched->skg_slptime
104230130Smav#define	kg_runtime	kg_sched->skg_runtime
105230130Smav
106230130Smavstruct td_sched {
107230130Smav	int	std_slptime;
108230130Smav};
109230130Smav#define	td_slptime	td_sched->std_slptime
110230130Smav
111230130Smavstruct td_sched td_sched;
112230130Smavstruct ke_sched ke_sched;
113230130Smavstruct kg_sched kg_sched;
114230130Smav
115230130Smavstruct ke_sched *kse0_sched = &ke_sched;
116230130Smavstruct kg_sched *ksegrp0_sched = &kg_sched;
117230130Smavstruct p_sched *proc0_sched = NULL;
118230130Smavstruct td_sched *thread0_sched = &td_sched;
119230130Smav
120230130Smav/*
121230130Smav * This priority range has 20 priorities on either end that are reachable
122230130Smav * only through nice values.
123230130Smav *
124230130Smav * PRI_RANGE:	Total priority range for timeshare threads.
125230130Smav * PRI_NRESV:	Reserved priorities for nice.
126230130Smav * PRI_BASE:	The start of the dynamic range.
127230130Smav * DYN_RANGE:	Number of priorities that are available int the dynamic
128230130Smav *		priority range.
129230571Smav */
130230571Smav#define	SCHED_PRI_RANGE		(PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE + 1)
131230571Smav#define	SCHED_PRI_NRESV		PRIO_TOTAL
132230571Smav#define	SCHED_PRI_NHALF		(PRIO_TOTAL / 2)
133230130Smav#define	SCHED_PRI_NTHRESH	(SCHED_PRI_NHALF - 1)
134230571Smav#define	SCHED_PRI_BASE		((SCHED_PRI_NRESV / 2) + PRI_MIN_TIMESHARE)
135230130Smav#define	SCHED_DYN_RANGE		(SCHED_PRI_RANGE - SCHED_PRI_NRESV)
136230130Smav#define	SCHED_PRI_INTERACT(score)					\
137230130Smav    ((score) * SCHED_DYN_RANGE / SCHED_INTERACT_RANGE)
138230130Smav
139230130Smav/*
140230130Smav * These determine the interactivity of a process.
141230130Smav *
142230130Smav * SLP_RUN_MAX:	Maximum amount of sleep time + run time we'll accumulate
143230130Smav *		before throttling back.
144230130Smav * SLP_RUN_THROTTLE:	Divisor for reducing slp/run time.
145230130Smav * INTERACT_RANGE:	Range of interactivity values.  Smaller is better.
146230130Smav * INTERACT_HALF:	Convenience define, half of the interactivity range.
147230130Smav * INTERACT_THRESH:	Threshhold for placement on the current runq.
148230130Smav */
149230130Smav#define	SCHED_SLP_RUN_MAX	((hz / 10) << 10)
150230130Smav#define	SCHED_SLP_RUN_THROTTLE	(10)
151230130Smav#define	SCHED_INTERACT_RANGE	(100)
152230130Smav#define	SCHED_INTERACT_HALF	(SCHED_INTERACT_RANGE / 2)
153230130Smav#define	SCHED_INTERACT_THRESH	(10)
154230130Smav
155230130Smav/*
156230130Smav * These parameters and macros determine the size of the time slice that is
157230130Smav * granted to each thread.
158230130Smav *
159230571Smav * SLICE_MIN:	Minimum time slice granted, in units of ticks.
160230571Smav * SLICE_MAX:	Maximum time slice granted.
161230571Smav * SLICE_RANGE:	Range of available time slices scaled by hz.
162230571Smav * SLICE_SCALE:	The number slices granted per val in the range of [0, max].
163230130Smav * SLICE_NICE:  Determine the amount of slice granted to a scaled nice.
164230130Smav */
165230130Smav#define	SCHED_SLICE_MIN			(slice_min)
166230130Smav#define	SCHED_SLICE_MAX			(slice_max)
167230130Smav#define	SCHED_SLICE_RANGE		(SCHED_SLICE_MAX - SCHED_SLICE_MIN + 1)
168230130Smav#define	SCHED_SLICE_SCALE(val, max)	(((val) * SCHED_SLICE_RANGE) / (max))
169230130Smav#define	SCHED_SLICE_NICE(nice)						\
170230130Smav    (SCHED_SLICE_MAX - SCHED_SLICE_SCALE((nice), SCHED_PRI_NTHRESH))
171230130Smav
172230130Smav/*
173230130Smav * This macro determines whether or not the kse belongs on the current or
174230130Smav * next run queue.
175230130Smav *
176230130Smav * XXX nice value should effect how interactive a kg is.
177230130Smav */
178230571Smav#define	SCHED_INTERACTIVE(kg)						\
179230571Smav    (sched_interact_score(kg) < SCHED_INTERACT_THRESH)
180230571Smav#define	SCHED_CURR(kg, ke)	SCHED_INTERACTIVE(kg)
181230571Smav#if 0
182230571Smav    (ke->ke_thread->td_priority < PRI_MIN_TIMESHARE || SCHED_INTERACTIVE(kg))
183230571Smav#endif
184230571Smav
185230571Smav/*
186230571Smav * Cpu percentage computation macros and defines.
187230571Smav *
188230571Smav * SCHED_CPU_TIME:	Number of seconds to average the cpu usage across.
189230571Smav * SCHED_CPU_TICKS:	Number of hz ticks to average the cpu usage across.
190230130Smav */
191230130Smav
192230130Smav#define	SCHED_CPU_TIME	10
193230571Smav#define	SCHED_CPU_TICKS	(hz * SCHED_CPU_TIME)
194230571Smav
195230571Smav/*
196230130Smav * kseq - per processor runqs and statistics.
197230571Smav */
198230130Smav
199230571Smav#define	KSEQ_NCLASS	(PRI_IDLE + 1)	/* Number of run classes. */
200230130Smav
201230130Smavstruct kseq {
202230130Smav	struct runq	ksq_idle;		/* Queue of IDLE threads. */
203230130Smav	struct runq	ksq_timeshare[2];	/* Run queues for !IDLE. */
204230130Smav	struct runq	*ksq_next;		/* Next timeshare queue. */
205230130Smav	struct runq	*ksq_curr;		/* Current queue. */
206230130Smav	int		ksq_loads[KSEQ_NCLASS];	/* Load for each class */
207230130Smav	int		ksq_load;		/* Aggregate load. */
208230130Smav	short		ksq_nice[PRIO_TOTAL + 1]; /* KSEs in each nice bin. */
209230571Smav	short		ksq_nicemin;		/* Least nice. */
210230571Smav#ifdef SMP
211230571Smav	unsigned int	ksq_rslices;	/* Slices on run queue */
212230571Smav#endif
213230571Smav};
214230571Smav
215230571Smav/*
216230571Smav * One kse queue per processor.
217230571Smav */
218230571Smav#ifdef SMP
219230571Smavstruct kseq	kseq_cpu[MAXCPU];
220230571Smav#define	KSEQ_SELF()	(&kseq_cpu[PCPU_GET(cpuid)])
221230571Smav#define	KSEQ_CPU(x)	(&kseq_cpu[(x)])
222230571Smav#else
223230571Smavstruct kseq	kseq_cpu;
224230571Smav#define	KSEQ_SELF()	(&kseq_cpu)
225230571Smav#define	KSEQ_CPU(x)	(&kseq_cpu)
226230571Smav#endif
227230571Smav
228230571Smavstatic void sched_slice(struct kse *ke);
229230571Smavstatic void sched_priority(struct ksegrp *kg);
230230571Smavstatic int sched_interact_score(struct ksegrp *kg);
231230130Smavvoid sched_pctcpu_update(struct kse *ke);
232230130Smavint sched_pickcpu(void);
233230130Smav
234230130Smav/* Operations on per processor queues */
235230130Smavstatic struct kse * kseq_choose(struct kseq *kseq);
236230130Smavstatic void kseq_setup(struct kseq *kseq);
237230130Smavstatic void kseq_add(struct kseq *kseq, struct kse *ke);
238230130Smavstatic void kseq_rem(struct kseq *kseq, struct kse *ke);
239230130Smavstatic void kseq_nice_add(struct kseq *kseq, int nice);
240230130Smavstatic void kseq_nice_rem(struct kseq *kseq, int nice);
241230130Smavvoid kseq_print(struct kseq *kseq);
242230130Smav#ifdef SMP
243230130Smavstruct kseq * kseq_load_highest(void);
244230130Smav#endif
245230130Smav
246230130Smavvoid
247230130Smavkseq_print(struct kseq *kseq)
248230130Smav{
249230130Smav	int i;
250230130Smav
251230130Smav	if (kseq == NULL)
252230130Smav		kseq = KSEQ_SELF();
253230130Smav
254230130Smav	printf("kseq:\n");
255230130Smav	printf("\tload:           %d\n", kseq->ksq_load);
256230130Smav	printf("\tload ITHD:      %d\n", kseq->ksq_loads[PRI_ITHD]);
257230130Smav	printf("\tload REALTIME:  %d\n", kseq->ksq_loads[PRI_REALTIME]);
258230130Smav	printf("\tload TIMESHARE: %d\n", kseq->ksq_loads[PRI_TIMESHARE]);
259230130Smav	printf("\tload IDLE:      %d\n", kseq->ksq_loads[PRI_IDLE]);
260230130Smav	printf("\tnicemin:\t%d\n", kseq->ksq_nicemin);
261230130Smav	printf("\tnice counts:\n");
262230130Smav	for (i = 0; i < PRIO_TOTAL + 1; i++)
263230130Smav		if (kseq->ksq_nice[i])
264230130Smav			printf("\t\t%d = %d\n",
265230130Smav			    i - SCHED_PRI_NHALF, kseq->ksq_nice[i]);
266230130Smav}
267230130Smav
268230130Smavstatic void
269230130Smavkseq_add(struct kseq *kseq, struct kse *ke)
270230130Smav{
271230130Smav	kseq->ksq_loads[ke->ke_ksegrp->kg_pri_class]++;
272230130Smav	kseq->ksq_load++;
273230130Smav	if (ke->ke_ksegrp->kg_pri_class == PRI_TIMESHARE)
274230130Smav	CTR6(KTR_ULE, "Add kse %p to %p (slice: %d, pri: %d, nice: %d(%d))",
275230130Smav	    ke, ke->ke_runq, ke->ke_slice, ke->ke_thread->td_priority,
276230130Smav	    ke->ke_ksegrp->kg_nice, kseq->ksq_nicemin);
277230130Smav	if (ke->ke_ksegrp->kg_pri_class == PRI_TIMESHARE)
278230130Smav		kseq_nice_add(kseq, ke->ke_ksegrp->kg_nice);
279230130Smav#ifdef SMP
280230130Smav	kseq->ksq_rslices += ke->ke_slice;
281230130Smav#endif
282230130Smav}
283230130Smav
284230130Smavstatic void
285230130Smavkseq_rem(struct kseq *kseq, struct kse *ke)
286230130Smav{
287230130Smav	kseq->ksq_loads[ke->ke_ksegrp->kg_pri_class]--;
288230130Smav	kseq->ksq_load--;
289230130Smav	ke->ke_runq = NULL;
290230130Smav	if (ke->ke_ksegrp->kg_pri_class == PRI_TIMESHARE)
291230130Smav		kseq_nice_rem(kseq, ke->ke_ksegrp->kg_nice);
292230130Smav#ifdef SMP
293230130Smav	kseq->ksq_rslices -= ke->ke_slice;
294230130Smav#endif
295230130Smav}
296230130Smav
297230130Smavstatic void
298230130Smavkseq_nice_add(struct kseq *kseq, int nice)
299230130Smav{
300230130Smav	/* Normalize to zero. */
301230130Smav	kseq->ksq_nice[nice + SCHED_PRI_NHALF]++;
302230130Smav	if (nice < kseq->ksq_nicemin || kseq->ksq_loads[PRI_TIMESHARE] == 0)
303230130Smav		kseq->ksq_nicemin = nice;
304230571Smav}
305230571Smav
306230130Smavstatic void
307230130Smavkseq_nice_rem(struct kseq *kseq, int nice)
308230130Smav{
309230130Smav	int n;
310230130Smav
311243794Seadler	/* Normalize to zero. */
312243793Seadler	n = nice + SCHED_PRI_NHALF;
313243794Seadler	kseq->ksq_nice[n]--;
314243794Seadler	KASSERT(kseq->ksq_nice[n] >= 0, ("Negative nice count."));
315230130Smav
316230130Smav	/*
317230130Smav	 * If this wasn't the smallest nice value or there are more in
318230130Smav	 * this bucket we can just return.  Otherwise we have to recalculate
319230130Smav	 * the smallest nice.
320230130Smav	 */
321230130Smav	if (nice != kseq->ksq_nicemin ||
322258170Smav	    kseq->ksq_nice[n] != 0 ||
323281544Srpaulo	    kseq->ksq_loads[PRI_TIMESHARE] == 0)
324230130Smav		return;
325230130Smav
326230130Smav	for (; n < SCHED_PRI_NRESV + 1; n++)
327230130Smav		if (kseq->ksq_nice[n]) {
328230571Smav			kseq->ksq_nicemin = n - SCHED_PRI_NHALF;
329230571Smav			return;
330230331Smav		}
331230571Smav}
332230571Smav
333230571Smav#ifdef SMP
334230571Smavstruct kseq *
335230331Smavkseq_load_highest(void)
336230571Smav{
337230571Smav	struct kseq *kseq;
338230571Smav	int load;
339230571Smav	int cpu;
340230574Smav	int i;
341230571Smav
342230571Smav	cpu = 0;
343230331Smav	load = 0;
344230331Smav
345230130Smav	for (i = 0; i < mp_maxid; i++) {
346230130Smav		if (CPU_ABSENT(i))
347230130Smav			continue;
348230130Smav		kseq = KSEQ_CPU(i);
349230130Smav		if (kseq->ksq_load > load) {
350230130Smav			load = kseq->ksq_load;
351230130Smav			cpu = i;
352230130Smav		}
353230130Smav	}
354230130Smav	if (load > 1)
355230130Smav		return (KSEQ_CPU(cpu));
356230130Smav
357230130Smav	return (NULL);
358230130Smav}
359230130Smav#endif
360230130Smav
361230130Smavstruct kse *
362230130Smavkseq_choose(struct kseq *kseq)
363230130Smav{
364230130Smav	struct kse *ke;
365230130Smav	struct runq *swap;
366230130Smav
367230130Smav	swap = NULL;
368230130Smav
369230130Smav	for (;;) {
370230130Smav		ke = runq_choose(kseq->ksq_curr);
371230130Smav		if (ke == NULL) {
372230130Smav			/*
373230130Smav			 * We already swaped once and didn't get anywhere.
374230130Smav			 */
375230130Smav			if (swap)
376230130Smav				break;
377230130Smav			swap = kseq->ksq_curr;
378230130Smav			kseq->ksq_curr = kseq->ksq_next;
379230130Smav			kseq->ksq_next = swap;
380230331Smav			continue;
381230130Smav		}
382230130Smav		/*
383230130Smav		 * If we encounter a slice of 0 the kse is in a
384230331Smav		 * TIMESHARE kse group and its nice was too far out
385264832Smarius		 * of the range that receives slices.
386230331Smav		 */
387230331Smav		if (ke->ke_slice == 0) {
388230331Smav			runq_remove(ke->ke_runq, ke);
389230331Smav			sched_slice(ke);
390230331Smav			ke->ke_runq = kseq->ksq_next;
391230331Smav			runq_add(ke->ke_runq, ke);
392230331Smav			continue;
393264832Smarius		}
394230331Smav		return (ke);
395230331Smav	}
396230331Smav
397230331Smav	return (runq_choose(&kseq->ksq_idle));
398230331Smav}
399230331Smav
400230331Smavstatic void
401230331Smavkseq_setup(struct kseq *kseq)
402230130Smav{
403230130Smav	runq_init(&kseq->ksq_timeshare[0]);
404230130Smav	runq_init(&kseq->ksq_timeshare[1]);
405230130Smav	runq_init(&kseq->ksq_idle);
406230130Smav
407230130Smav	kseq->ksq_curr = &kseq->ksq_timeshare[0];
408230130Smav	kseq->ksq_next = &kseq->ksq_timeshare[1];
409230130Smav
410230130Smav	kseq->ksq_loads[PRI_ITHD] = 0;
411230130Smav	kseq->ksq_loads[PRI_REALTIME] = 0;
412230130Smav	kseq->ksq_loads[PRI_TIMESHARE] = 0;
413230130Smav	kseq->ksq_loads[PRI_IDLE] = 0;
414230130Smav#ifdef SMP
415230130Smav	kseq->ksq_rslices = 0;
416230130Smav#endif
417230130Smav}
418230130Smav
419230130Smavstatic void
420230130Smavsched_setup(void *dummy)
421230130Smav{
422230130Smav	int i;
423230130Smav
424230130Smav	slice_min = (hz/100);
425230130Smav	slice_max = (hz/10);
426230130Smav
427230130Smav	mtx_lock_spin(&sched_lock);
428230130Smav	/* init kseqs */
429230130Smav	for (i = 0; i < MAXCPU; i++)
430230130Smav		kseq_setup(KSEQ_CPU(i));
431242352Smav
432230130Smav	kseq_add(KSEQ_SELF(), &kse0);
433230130Smav	mtx_unlock_spin(&sched_lock);
434230130Smav}
435230130Smav
436230130Smav/*
437230130Smav * Scale the scheduling priority according to the "interactivity" of this
438230130Smav * process.
439230130Smav */
440230130Smavstatic void
441230130Smavsched_priority(struct ksegrp *kg)
442230130Smav{
443230130Smav	int pri;
444230130Smav
445230130Smav	if (kg->kg_pri_class != PRI_TIMESHARE)
446230130Smav		return;
447230130Smav
448230130Smav	pri = SCHED_PRI_INTERACT(sched_interact_score(kg));
449230130Smav	pri += SCHED_PRI_BASE;
450230130Smav	pri += kg->kg_nice;
451230130Smav
452230130Smav	if (pri > PRI_MAX_TIMESHARE)
453230130Smav		pri = PRI_MAX_TIMESHARE;
454230130Smav	else if (pri < PRI_MIN_TIMESHARE)
455230130Smav		pri = PRI_MIN_TIMESHARE;
456230130Smav
457230130Smav	kg->kg_user_pri = pri;
458230130Smav
459230130Smav	return;
460230130Smav}
461230130Smav
462230130Smav/*
463230130Smav * Calculate a time slice based on the properties of the kseg and the runq
464230130Smav * that we're on.  This is only for PRI_TIMESHARE ksegrps.
465247910Sglebius */
466247910Sglebiusstatic void
467230130Smavsched_slice(struct kse *ke)
468247910Sglebius{
469247910Sglebius	struct kseq *kseq;
470247910Sglebius	struct ksegrp *kg;
471230130Smav
472230130Smav	kg = ke->ke_ksegrp;
473230130Smav	kseq = KSEQ_CPU(ke->ke_cpu);
474230130Smav
475230130Smav	/*
476230130Smav	 * Rationale:
477230130Smav	 * KSEs in interactive ksegs get the minimum slice so that we
478230130Smav	 * quickly notice if it abuses its advantage.
479230130Smav	 *
480230130Smav	 * KSEs in non-interactive ksegs are assigned a slice that is
481230130Smav	 * based on the ksegs nice value relative to the least nice kseg
482230130Smav	 * on the run queue for this cpu.
483230130Smav	 *
484230130Smav	 * If the KSE is less nice than all others it gets the maximum
485230130Smav	 * slice and other KSEs will adjust their slice relative to
486230130Smav	 * this when they first expire.
487230130Smav	 *
488230130Smav	 * There is 20 point window that starts relative to the least
489230130Smav	 * nice kse on the run queue.  Slice size is determined by
490230130Smav	 * the kse distance from the last nice ksegrp.
491230130Smav	 *
492230130Smav	 * If you are outside of the window you will get no slice and
493230130Smav	 * you will be reevaluated each time you are selected on the
494230130Smav	 * run queue.
495230130Smav	 *
496230130Smav	 */
497230130Smav
498230130Smav	if (!SCHED_INTERACTIVE(kg)) {
499230130Smav		int nice;
500230130Smav
501230130Smav		nice = kg->kg_nice + (0 - kseq->ksq_nicemin);
502230130Smav		if (kseq->ksq_loads[PRI_TIMESHARE] == 0 ||
503230130Smav		    kg->kg_nice < kseq->ksq_nicemin)
504230130Smav			ke->ke_slice = SCHED_SLICE_MAX;
505230130Smav		else if (nice <= SCHED_PRI_NTHRESH)
506230130Smav			ke->ke_slice = SCHED_SLICE_NICE(nice);
507230130Smav		else
508230130Smav			ke->ke_slice = 0;
509230130Smav	} else
510230130Smav		ke->ke_slice = SCHED_SLICE_MIN;
511230130Smav
512230130Smav	CTR6(KTR_ULE,
513230130Smav	    "Sliced %p(%d) (nice: %d, nicemin: %d, load: %d, interactive: %d)",
514230130Smav	    ke, ke->ke_slice, kg->kg_nice, kseq->ksq_nicemin,
515230130Smav	    kseq->ksq_loads[PRI_TIMESHARE], SCHED_INTERACTIVE(kg));
516230130Smav
517230130Smav	/*
518230130Smav	 * Check to see if we need to scale back the slp and run time
519242352Smav	 * in the kg.  This will cause us to forget old interactivity
520242352Smav	 * while maintaining the current ratio.
521242352Smav	 */
522242352Smav	CTR4(KTR_ULE, "Slp vs Run %p (Slp %d, Run %d, Score %d)",
523230130Smav	    ke, kg->kg_slptime >> 10, kg->kg_runtime >> 10,
524230130Smav	    sched_interact_score(kg));
525230130Smav
526230130Smav	if ((kg->kg_runtime + kg->kg_slptime) >  SCHED_SLP_RUN_MAX) {
527230130Smav		kg->kg_runtime /= SCHED_SLP_RUN_THROTTLE;
528230130Smav		kg->kg_slptime /= SCHED_SLP_RUN_THROTTLE;
529230130Smav	}
530230130Smav	CTR4(KTR_ULE, "Slp vs Run(2) %p (Slp %d, Run %d, Score %d)",
531230130Smav	    ke, kg->kg_slptime >> 10, kg->kg_runtime >> 10,
532230130Smav	    sched_interact_score(kg));
533230130Smav
534230130Smav	return;
535230130Smav}
536230130Smav
537230130Smavstatic int
538230130Smavsched_interact_score(struct ksegrp *kg)
539230130Smav{
540230130Smav	int big;
541230130Smav	int small;
542230130Smav	int base;
543230130Smav
544230130Smav	if (kg->kg_runtime > kg->kg_slptime) {
545230130Smav		big = kg->kg_runtime;
546230130Smav		small = kg->kg_slptime;
547230130Smav		base = SCHED_INTERACT_HALF;
548230130Smav	} else {
549230130Smav		big = kg->kg_slptime;
550230130Smav		small = kg->kg_runtime;
551230130Smav		base = 0;
552230130Smav	}
553230130Smav
554230130Smav	big /= SCHED_INTERACT_HALF;
555230130Smav	if (big != 0)
556230130Smav		small /= big;
557230130Smav	else
558230130Smav		small = 0;
559230130Smav
560230130Smav	small += base;
561230130Smav	/* XXX Factor in nice */
562230130Smav	return (small);
563230130Smav}
564230130Smav
565230130Smav/*
566230130Smav * This is only somewhat accurate since given many processes of the same
567230130Smav * priority they will switch when their slices run out, which will be
568230130Smav * at most SCHED_SLICE_MAX.
569230130Smav */
570230130Smavint
571230130Smavsched_rr_interval(void)
572230326Smav{
573230130Smav	return (SCHED_SLICE_MAX);
574230130Smav}
575230130Smav
576230130Smavvoid
577230130Smavsched_pctcpu_update(struct kse *ke)
578230326Smav{
579230130Smav	/*
580230130Smav	 * Adjust counters and watermark for pctcpu calc.
581230130Smav	 *
582230130Smav	 * Shift the tick count out so that the divide doesn't round away
583230130Smav	 * our results.
584230130Smav	 */
585230130Smav	ke->ke_ticks <<= 10;
586230130Smav	ke->ke_ticks = (ke->ke_ticks / (ke->ke_ltick - ke->ke_ftick)) *
587230130Smav		    SCHED_CPU_TICKS;
588230130Smav	ke->ke_ticks >>= 10;
589230130Smav	ke->ke_ltick = ticks;
590230130Smav	ke->ke_ftick = ke->ke_ltick - SCHED_CPU_TICKS;
591230130Smav}
592230130Smav
593230130Smav#ifdef SMP
594230130Smav/* XXX Should be changed to kseq_load_lowest() */
595230130Smavint
596230130Smavsched_pickcpu(void)
597230130Smav{
598230130Smav	struct kseq *kseq;
599230130Smav	int load;
600230130Smav	int cpu;
601230130Smav	int i;
602230130Smav
603230130Smav	if (!smp_started)
604230130Smav		return (0);
605230130Smav
606230130Smav	load = 0;
607230130Smav	cpu = 0;
608230130Smav
609230130Smav	for (i = 0; i < mp_maxid; i++) {
610230130Smav		if (CPU_ABSENT(i))
611230130Smav			continue;
612230130Smav		kseq = KSEQ_CPU(i);
613230130Smav		if (kseq->ksq_load < load) {
614230130Smav			cpu = i;
615230130Smav			load = kseq->ksq_load;
616230130Smav		}
617230130Smav	}
618230130Smav
619230130Smav	CTR1(KTR_RUNQ, "sched_pickcpu: %d", cpu);
620230130Smav	return (cpu);
621230130Smav}
622230130Smav#else
623230130Smavint
624230130Smavsched_pickcpu(void)
625230130Smav{
626230130Smav	return (0);
627230130Smav}
628230130Smav#endif
629231024Smav
630230130Smavvoid
631230130Smavsched_prio(struct thread *td, u_char prio)
632230130Smav{
633230130Smav	struct kse *ke;
634230130Smav	struct runq *rq;
635230130Smav
636230130Smav	mtx_assert(&sched_lock, MA_OWNED);
637230130Smav	ke = td->td_kse;
638230130Smav	td->td_priority = prio;
639230130Smav
640230130Smav	if (TD_ON_RUNQ(td)) {
641230130Smav		rq = ke->ke_runq;
642230130Smav
643230130Smav		runq_remove(rq, ke);
644230130Smav		runq_add(rq, ke);
645230130Smav	}
646230130Smav}
647230130Smav
648230130Smavvoid
649230130Smavsched_switchout(struct thread *td)
650230130Smav{
651230130Smav	struct kse *ke;
652230130Smav
653230130Smav	mtx_assert(&sched_lock, MA_OWNED);
654230130Smav
655230130Smav	ke = td->td_kse;
656230130Smav
657230130Smav	td->td_last_kse = ke;
658230130Smav        td->td_lastcpu = td->td_oncpu;
659230130Smav	td->td_oncpu = NOCPU;
660230130Smav        td->td_flags &= ~TDF_NEEDRESCHED;
661230130Smav
662230130Smav	if (TD_IS_RUNNING(td)) {
663230130Smav		runq_add(ke->ke_runq, ke);
664230130Smav		/* setrunqueue(td); */
665230130Smav		return;
666230130Smav	}
667230130Smav	if (ke->ke_runq)
668230130Smav		kseq_rem(KSEQ_CPU(ke->ke_cpu), ke);
669230130Smav	/*
670230130Smav	 * We will not be on the run queue. So we must be
671230130Smav	 * sleeping or similar.
672230130Smav	 */
673230130Smav	if (td->td_proc->p_flag & P_THREADED)
674230130Smav		kse_reassign(ke);
675230130Smav}
676230130Smav
677230130Smavvoid
678230130Smavsched_switchin(struct thread *td)
679230130Smav{
680230130Smav	/* struct kse *ke = td->td_kse; */
681230130Smav	mtx_assert(&sched_lock, MA_OWNED);
682230130Smav
683230130Smav	td->td_oncpu = PCPU_GET(cpuid);
684230130Smav
685230130Smav	if (td->td_ksegrp->kg_pri_class == PRI_TIMESHARE &&
686230130Smav	    td->td_priority != td->td_ksegrp->kg_user_pri)
687230130Smav		curthread->td_flags |= TDF_NEEDRESCHED;
688230130Smav}
689230130Smav
690230130Smavvoid
691230130Smavsched_nice(struct ksegrp *kg, int nice)
692230130Smav{
693230130Smav	struct kse *ke;
694230130Smav	struct thread *td;
695230130Smav	struct kseq *kseq;
696230130Smav
697230130Smav	/*
698230130Smav	 * We need to adjust the nice counts for running KSEs.
699230130Smav	 */
700230130Smav	if (kg->kg_pri_class == PRI_TIMESHARE)
701230130Smav		FOREACH_KSE_IN_GROUP(kg, ke) {
702230130Smav			if (ke->ke_state != KES_ONRUNQ &&
703230130Smav			    ke->ke_state != KES_THREAD)
704230130Smav				continue;
705230130Smav			kseq = KSEQ_CPU(ke->ke_cpu);
706230130Smav			kseq_nice_rem(kseq, kg->kg_nice);
707230130Smav			kseq_nice_add(kseq, nice);
708230130Smav		}
709230130Smav	kg->kg_nice = nice;
710230130Smav	sched_priority(kg);
711230130Smav	FOREACH_THREAD_IN_GROUP(kg, td)
712230130Smav		td->td_flags |= TDF_NEEDRESCHED;
713230130Smav}
714230130Smav
715230130Smavvoid
716230130Smavsched_sleep(struct thread *td, u_char prio)
717264832Smarius{
718230130Smav	mtx_assert(&sched_lock, MA_OWNED);
719230130Smav
720230130Smav	td->td_slptime = ticks;
721230130Smav	td->td_priority = prio;
722230130Smav
723230130Smav	CTR2(KTR_ULE, "sleep kse %p (tick: %d)",
724230130Smav	    td->td_kse, td->td_slptime);
725230130Smav}
726230130Smav
727230130Smavvoid
728264832Smariussched_wakeup(struct thread *td)
729{
730	mtx_assert(&sched_lock, MA_OWNED);
731
732	/*
733	 * Let the kseg know how long we slept for.  This is because process
734	 * interactivity behavior is modeled in the kseg.
735	 */
736	if (td->td_slptime) {
737		struct ksegrp *kg;
738		int hzticks;
739
740		kg = td->td_ksegrp;
741		hzticks = ticks - td->td_slptime;
742		kg->kg_slptime += hzticks << 10;
743		sched_priority(kg);
744		CTR2(KTR_ULE, "wakeup kse %p (%d ticks)",
745		    td->td_kse, hzticks);
746		td->td_slptime = 0;
747	}
748	setrunqueue(td);
749        if (td->td_priority < curthread->td_priority)
750                curthread->td_flags |= TDF_NEEDRESCHED;
751}
752
753/*
754 * Penalize the parent for creating a new child and initialize the child's
755 * priority.
756 */
757void
758sched_fork(struct proc *p, struct proc *p1)
759{
760
761	mtx_assert(&sched_lock, MA_OWNED);
762
763	sched_fork_ksegrp(FIRST_KSEGRP_IN_PROC(p), FIRST_KSEGRP_IN_PROC(p1));
764	sched_fork_kse(FIRST_KSE_IN_PROC(p), FIRST_KSE_IN_PROC(p1));
765	sched_fork_thread(FIRST_THREAD_IN_PROC(p), FIRST_THREAD_IN_PROC(p1));
766}
767
768void
769sched_fork_kse(struct kse *ke, struct kse *child)
770{
771	child->ke_slice = ke->ke_slice;
772	child->ke_cpu = ke->ke_cpu; /* sched_pickcpu(); */
773	child->ke_runq = NULL;
774
775	/*
776	 * Claim that we've been running for one second for statistical
777	 * purposes.
778	 */
779	child->ke_ticks = 0;
780	child->ke_ltick = ticks;
781	child->ke_ftick = ticks - hz;
782}
783
784void
785sched_fork_ksegrp(struct ksegrp *kg, struct ksegrp *child)
786{
787	/* XXX Need something better here */
788	if (kg->kg_slptime > kg->kg_runtime) {
789		child->kg_slptime = SCHED_DYN_RANGE;
790		child->kg_runtime = kg->kg_slptime / SCHED_DYN_RANGE;
791	} else {
792		child->kg_runtime = SCHED_DYN_RANGE;
793		child->kg_slptime = kg->kg_runtime / SCHED_DYN_RANGE;
794	}
795
796	child->kg_user_pri = kg->kg_user_pri;
797	child->kg_nice = kg->kg_nice;
798}
799
800void
801sched_fork_thread(struct thread *td, struct thread *child)
802{
803}
804
805void
806sched_class(struct ksegrp *kg, int class)
807{
808	struct kseq *kseq;
809	struct kse *ke;
810
811	if (kg->kg_pri_class == class)
812		return;
813
814	FOREACH_KSE_IN_GROUP(kg, ke) {
815		if (ke->ke_state != KES_ONRUNQ &&
816		    ke->ke_state != KES_THREAD)
817			continue;
818		kseq = KSEQ_CPU(ke->ke_cpu);
819
820		kseq->ksq_loads[kg->kg_pri_class]--;
821		kseq->ksq_loads[class]++;
822
823		if (kg->kg_pri_class == PRI_TIMESHARE)
824			kseq_nice_rem(kseq, kg->kg_nice);
825		else if (class == PRI_TIMESHARE)
826			kseq_nice_add(kseq, kg->kg_nice);
827	}
828
829	kg->kg_pri_class = class;
830}
831
832/*
833 * Return some of the child's priority and interactivity to the parent.
834 */
835void
836sched_exit(struct proc *p, struct proc *child)
837{
838	struct ksegrp *kg;
839	struct kse *ke;
840
841	/* XXX Need something better here */
842	mtx_assert(&sched_lock, MA_OWNED);
843	kg = FIRST_KSEGRP_IN_PROC(child);
844	ke = FIRST_KSE_IN_KSEGRP(kg);
845	kseq_rem(KSEQ_CPU(ke->ke_cpu), ke);
846}
847
848void
849sched_clock(struct kse *ke)
850{
851	struct kseq *kseq;
852	struct ksegrp *kg;
853	struct thread *td;
854#if 0
855	struct kse *nke;
856#endif
857
858	/*
859	 * sched_setup() apparently happens prior to stathz being set.  We
860	 * need to resolve the timers earlier in the boot so we can avoid
861	 * calculating this here.
862	 */
863	if (realstathz == 0) {
864		realstathz = stathz ? stathz : hz;
865		tickincr = hz / realstathz;
866		/*
867		 * XXX This does not work for values of stathz that are much
868		 * larger than hz.
869		 */
870		if (tickincr == 0)
871			tickincr = 1;
872	}
873
874	td = ke->ke_thread;
875	kg = ke->ke_ksegrp;
876
877	mtx_assert(&sched_lock, MA_OWNED);
878	KASSERT((td != NULL), ("schedclock: null thread pointer"));
879
880	/* Adjust ticks for pctcpu */
881	ke->ke_ticks++;
882	ke->ke_ltick = ticks;
883
884	/* Go up to one second beyond our max and then trim back down */
885	if (ke->ke_ftick + SCHED_CPU_TICKS + hz < ke->ke_ltick)
886		sched_pctcpu_update(ke);
887
888	if (td->td_kse->ke_flags & KEF_IDLEKSE)
889		return;
890
891	CTR4(KTR_ULE, "Tick kse %p (slice: %d, slptime: %d, runtime: %d)",
892	    ke, ke->ke_slice, kg->kg_slptime >> 10, kg->kg_runtime >> 10);
893
894	/*
895	 * We only do slicing code for TIMESHARE ksegrps.
896	 */
897	if (kg->kg_pri_class != PRI_TIMESHARE)
898		return;
899	/*
900	 * Check for a higher priority task on the run queue.  This can happen
901	 * on SMP if another processor woke up a process on our runq.
902	 */
903	kseq = KSEQ_SELF();
904#if 0
905	if (kseq->ksq_load > 1 && (nke = kseq_choose(kseq)) != NULL) {
906		if (sched_strict &&
907		    nke->ke_thread->td_priority < td->td_priority)
908			td->td_flags |= TDF_NEEDRESCHED;
909		else if (nke->ke_thread->td_priority <
910		    td->td_priority SCHED_PRIO_SLOP)
911
912		if (nke->ke_thread->td_priority < td->td_priority)
913			td->td_flags |= TDF_NEEDRESCHED;
914	}
915#endif
916	/*
917	 * We used a tick charge it to the ksegrp so that we can compute our
918	 * interactivity.
919	 */
920	kg->kg_runtime += tickincr << 10;
921
922	/*
923	 * We used up one time slice.
924	 */
925	ke->ke_slice--;
926#ifdef SMP
927	kseq->ksq_rslices--;
928#endif
929
930	if (ke->ke_slice > 0)
931		return;
932	/*
933	 * We're out of time, recompute priorities and requeue.
934	 */
935	kseq_rem(kseq, ke);
936	sched_priority(kg);
937	sched_slice(ke);
938	if (SCHED_CURR(kg, ke))
939		ke->ke_runq = kseq->ksq_curr;
940	else
941		ke->ke_runq = kseq->ksq_next;
942	kseq_add(kseq, ke);
943	td->td_flags |= TDF_NEEDRESCHED;
944}
945
946int
947sched_runnable(void)
948{
949	struct kseq *kseq;
950
951	kseq = KSEQ_SELF();
952
953	if (kseq->ksq_load)
954		return (1);
955#ifdef SMP
956	/*
957	 * For SMP we may steal other processor's KSEs.  Just search until we
958	 * verify that at least on other cpu has a runnable task.
959	 */
960	if (smp_started) {
961		int i;
962
963		for (i = 0; i < mp_maxid; i++) {
964			if (CPU_ABSENT(i))
965				continue;
966			kseq = KSEQ_CPU(i);
967			if (kseq->ksq_load)
968				return (1);
969		}
970	}
971#endif
972	return (0);
973}
974
975void
976sched_userret(struct thread *td)
977{
978	struct ksegrp *kg;
979
980	kg = td->td_ksegrp;
981
982	if (td->td_priority != kg->kg_user_pri) {
983		mtx_lock_spin(&sched_lock);
984		td->td_priority = kg->kg_user_pri;
985		mtx_unlock_spin(&sched_lock);
986	}
987}
988
989struct kse *
990sched_choose(void)
991{
992	struct kseq *kseq;
993	struct kse *ke;
994
995#ifdef SMP
996retry:
997#endif
998	kseq = KSEQ_SELF();
999	ke = kseq_choose(kseq);
1000	if (ke) {
1001		runq_remove(ke->ke_runq, ke);
1002		ke->ke_state = KES_THREAD;
1003
1004		if (ke->ke_ksegrp->kg_pri_class == PRI_TIMESHARE) {
1005			CTR4(KTR_ULE, "Run kse %p from %p (slice: %d, pri: %d)",
1006			    ke, ke->ke_runq, ke->ke_slice,
1007			    ke->ke_thread->td_priority);
1008		}
1009		return (ke);
1010	}
1011
1012#ifdef SMP
1013	if (smp_started) {
1014		/*
1015		 * Find the cpu with the highest load and steal one proc.
1016		 */
1017		if ((kseq = kseq_load_highest()) == NULL)
1018			return (NULL);
1019
1020		/*
1021		 * Remove this kse from this kseq and runq and then requeue
1022		 * on the current processor.  Then we will dequeue it
1023		 * normally above.
1024		 */
1025		ke = kseq_choose(kseq);
1026		runq_remove(ke->ke_runq, ke);
1027		ke->ke_state = KES_THREAD;
1028		kseq_rem(kseq, ke);
1029
1030		ke->ke_cpu = PCPU_GET(cpuid);
1031		sched_add(ke);
1032		goto retry;
1033	}
1034#endif
1035
1036	return (NULL);
1037}
1038
1039void
1040sched_add(struct kse *ke)
1041{
1042	struct kseq *kseq;
1043	struct ksegrp *kg;
1044
1045	mtx_assert(&sched_lock, MA_OWNED);
1046	KASSERT((ke->ke_thread != NULL), ("sched_add: No thread on KSE"));
1047	KASSERT((ke->ke_thread->td_kse != NULL),
1048	    ("sched_add: No KSE on thread"));
1049	KASSERT(ke->ke_state != KES_ONRUNQ,
1050	    ("sched_add: kse %p (%s) already in run queue", ke,
1051	    ke->ke_proc->p_comm));
1052	KASSERT(ke->ke_proc->p_sflag & PS_INMEM,
1053	    ("sched_add: process swapped out"));
1054
1055	kg = ke->ke_ksegrp;
1056
1057	if (ke->ke_runq)
1058		Debugger("hrm?");
1059
1060	switch (kg->kg_pri_class) {
1061	case PRI_ITHD:
1062	case PRI_REALTIME:
1063		kseq = KSEQ_SELF();
1064		if (ke->ke_runq == NULL)
1065			kseq_add(kseq, ke);
1066		ke->ke_runq = kseq->ksq_curr;
1067		ke->ke_slice = SCHED_SLICE_MAX;
1068		break;
1069	case PRI_TIMESHARE:
1070		kseq = KSEQ_CPU(ke->ke_cpu);
1071		if (ke->ke_runq == NULL) {
1072			if (SCHED_CURR(kg, ke))
1073				ke->ke_runq = kseq->ksq_curr;
1074			else
1075				ke->ke_runq = kseq->ksq_next;
1076			kseq_add(kseq, ke);
1077		}
1078		break;
1079	case PRI_IDLE:
1080		kseq = KSEQ_CPU(ke->ke_cpu);
1081
1082		if (ke->ke_runq == NULL)
1083			kseq_add(kseq, ke);
1084		/*
1085		 * This is for priority prop.
1086		 */
1087		if (ke->ke_thread->td_priority < PRI_MAX_TIMESHARE)
1088			ke->ke_runq = kseq->ksq_curr;
1089		else
1090			ke->ke_runq = &kseq->ksq_idle;
1091		ke->ke_slice = SCHED_SLICE_MIN;
1092		break;
1093	default:
1094		panic("Unknown pri class.\n");
1095		break;
1096	}
1097
1098	ke->ke_ksegrp->kg_runq_kses++;
1099	ke->ke_state = KES_ONRUNQ;
1100
1101	runq_add(ke->ke_runq, ke);
1102}
1103
1104void
1105sched_rem(struct kse *ke)
1106{
1107	struct kseq *kseq;
1108
1109	mtx_assert(&sched_lock, MA_OWNED);
1110	/* KASSERT((ke->ke_state == KES_ONRUNQ), ("KSE not on run queue")); */
1111	panic("WTF\n");
1112
1113	ke->ke_state = KES_THREAD;
1114	ke->ke_ksegrp->kg_runq_kses--;
1115	kseq = KSEQ_CPU(ke->ke_cpu);
1116	runq_remove(ke->ke_runq, ke);
1117	kseq_rem(kseq, ke);
1118}
1119
1120fixpt_t
1121sched_pctcpu(struct kse *ke)
1122{
1123	fixpt_t pctcpu;
1124
1125	pctcpu = 0;
1126
1127	if (ke->ke_ticks) {
1128		int rtick;
1129
1130		/* Update to account for time potentially spent sleeping */
1131		ke->ke_ltick = ticks;
1132		sched_pctcpu_update(ke);
1133
1134		/* How many rtick per second ? */
1135		rtick = ke->ke_ticks / SCHED_CPU_TIME;
1136		pctcpu = (FSCALE * ((FSCALE * rtick)/realstathz)) >> FSHIFT;
1137	}
1138
1139	ke->ke_proc->p_swtime = ke->ke_ltick - ke->ke_ftick;
1140
1141	return (pctcpu);
1142}
1143
1144int
1145sched_sizeof_kse(void)
1146{
1147	return (sizeof(struct kse) + sizeof(struct ke_sched));
1148}
1149
1150int
1151sched_sizeof_ksegrp(void)
1152{
1153	return (sizeof(struct ksegrp) + sizeof(struct kg_sched));
1154}
1155
1156int
1157sched_sizeof_proc(void)
1158{
1159	return (sizeof(struct proc));
1160}
1161
1162int
1163sched_sizeof_thread(void)
1164{
1165	return (sizeof(struct thread) + sizeof(struct td_sched));
1166}
1167