direct-io.hg
changeset 4609:9c88ba91d330
bitkeeper revision 1.1346.1.1 (42670505dNhgnJm5dQD81pCalXMZgw)
manual merge
manual merge
author | iap10@freefall.cl.cam.ac.uk |
---|---|
date | Thu Apr 21 01:42:29 2005 +0000 (2005-04-21) |
parents | 717d7dbd06ea 18d709f72233 |
children | 214ccc480724 |
files | .rootkeys docs/misc/sedf_scheduler_mini-HOWTO.txt tools/libxc/Makefile tools/libxc/xc.h tools/libxc/xc_sedf.c tools/python/xen/lowlevel/xc/xc.c tools/python/xen/xend/XendClient.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/server/SrvDomain.py tools/python/xen/xm/main.py xen/common/sched_sedf.c xen/common/schedule.c xen/include/public/sched_ctl.h xen/include/xen/adv_sched_hist.h xen/include/xen/sched-if.h |
line diff
1.1 --- a/.rootkeys Wed Apr 20 21:22:46 2005 +0000 1.2 +++ b/.rootkeys Thu Apr 21 01:42:29 2005 +0000 1.3 @@ -21,6 +21,7 @@ 4022a73cgxX1ryj1HgS-IwwB6NUi2A docs/misc 1.4 412f4bd9sm5mCQ8BkrgKcAKZGadq7Q docs/misc/blkif-drivers-explained.txt 1.5 420b949cy9ZGzED74Fz_DaWlK7tT4g docs/misc/crashdb.txt 1.6 4251a1f82AexscYEiF4Iku8Gc_kWfQ docs/misc/grant-tables.txt 1.7 +424d462b5GuApQ_NyMsRFt9LbrsWow docs/misc/sedf_scheduler_mini-HOWTO.txt 1.8 40d6ccbfKKBq8jE0ula4eHEzBiQuDA docs/misc/xen_config.html 1.9 410a4c2bAO_m_l4RsiiPHnZ4ixHWbQ docs/misc/xend.tex 1.10 3f9e7d564bWFB-Czjv1qdmE6o0GqNg docs/src/interface.tex 1.11 @@ -732,6 +733,7 @@ 41cc934aO1m6NxEh_8eDr9bJIMoLFA tools/lib 1.12 3fbba6dctWRWlFJkYb6hdix2X4WMuw tools/libxc/xc_private.c 1.13 3fbba6dcbVrG2hPzEzwdeV_UC8kydQ tools/libxc/xc_private.h 1.14 42337174PxyzzPk62raDiYCIsfStDg tools/libxc/xc_ptrace.c 1.15 +41ebbfe9U0b0kI-HgjK7VEY4EvW7_w tools/libxc/xc_sedf.c 1.16 41dde8b0pLfAKMs_L9Uri2hnzHiCRQ tools/libxc/xc_vmx_build.c 1.17 40e1b09dMYB4ItGCqcMIzirdMd9I-w tools/libxutil/Makefile 1.18 40e033325Sjqs-_4TuzeUEprP_gYFg tools/libxutil/allocate.c 1.19 @@ -1266,6 +1268,7 @@ 3e54c38dkHAev597bPr71-hGzTdocg xen/commo 1.20 4051bcecFeq4DE70p4zGO5setf47CA xen/common/physdev.c 1.21 3ddb79bdHqdQpATqC0rmUZNbsb6L6A xen/common/resource.c 1.22 40589968dD2D1aejwSOvrROg7fOvGQ xen/common/sched_bvt.c 1.23 +41ebbfe9oF1BF3cH5v7yE3eOL9uPbA xen/common/sched_sedf.c 1.24 3e397e6619PgAfBbw2XFbXkewvUWgw xen/common/schedule.c 1.25 3ddb79bd0gVQYmL2zvuJnldvD0AGxQ xen/common/softirq.c 1.26 3e7f358awXBC3Vw-wFRwPw18qL1khg xen/common/string.c 1.27 @@ -1434,6 +1437,7 @@ 4266bd01Ul-pC01ZVvBkhBnv5eqzvw xen/inclu 1.28 3ddb79c25UE59iu4JJcbRalx95mvcg xen/include/public/xen.h 1.29 3e397e66m2tO3s-J8Jnr7Ws_tGoPTg xen/include/xen/ac_timer.h 1.30 40715b2epYl2jBbxzz9CI2rgIca7Zg xen/include/xen/acpi.h 1.31 +422f0995xCgnbsVhTjSncnqIABs64g xen/include/xen/adv_sched_hist.h 1.32 3ddb79c0c0cX_DZE209-Bb-Rx1v-Aw xen/include/xen/cache.h 1.33 41f2cea7Yna7xc0X9fyavIjoSFFeVg xen/include/xen/compile.h.in 1.34 3f840f12CkbYSlwMrY2S11Mpyxg7Nw xen/include/xen/compiler.h
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/docs/misc/sedf_scheduler_mini-HOWTO.txt Thu Apr 21 01:42:29 2005 +0000 2.3 @@ -0,0 +1,44 @@ 2.4 +sEDF scheduler 2.5 +-------------- 2.6 +Author: 2.7 + Stephan.Diestelhorst@{cl.cam.ac.uk, inf.tu-dresden.de} 2.8 + 2.9 +Overview: 2.10 + This scheduler provides weighted CPU sharing in an intuitive way and 2.11 + uses realtime-algorithms to ensure time guarantees. 2.12 + 2.13 +Usage: 2.14 + -add "sched=sedf" on Xen's boot command-line 2.15 + -create domains as usual 2.16 + -use "xm sedf <dom-id> <period> <slice> <latency-hint> <extra> <weight>" 2.17 + Where: 2.18 + -period/slice are the normal EDF scheduling parameters in nanosecs 2.19 + -latency-hint is the scaled period in case the domain is doing heavy I/O 2.20 + (unused by the currently compiled version) 2.21 + -extra is a flag (0/1), which controls whether the domain can run in 2.22 + extra-time 2.23 + -weight is mutually exclusive with period/slice and specifies another 2.24 + way of setting a domains cpu slice 2.25 + 2.26 +Examples: 2.27 + normal EDF (20ms/5ms): 2.28 + xm sedf <dom-id> 20000000 5000000 0 0 0 2.29 + 2.30 + best-effort domains (i.e. non-realtime): 2.31 + xm sedf <dom-id> 20000000 0 0 1 0 2.32 + 2.33 + normal EDF (20ms/5ms) + share of extra-time: 2.34 + xm sedf <dom-id> 20000000 5000000 0 1 0 2.35 + 2.36 + 4 domains with weights 2:3:4:2 2.37 + xm sedf <d1> 0 0 0 0 2 2.38 + xm sedf <d2> 0 0 0 0 3 2.39 + xm sedf <d3> 0 0 0 0 4 2.40 + xm sedf <d4> 0 0 0 0 2 2.41 + 2.42 + 1 fully-specified (10ms/3ms) domain, 3 other domains share 2.43 + available rest in 2:7:3 ratio: 2.44 + xm sedf <d1> 10000000 3000000 0 0 0 2.45 + xm sedf <d2> 0 0 0 0 2 2.46 + xm sedf <d3> 0 0 0 0 7 2.47 + xm sedf <d4> 0 0 0 0 3 2.48 \ No newline at end of file
3.1 --- a/tools/libxc/Makefile Wed Apr 20 21:22:46 2005 +0000 3.2 +++ b/tools/libxc/Makefile Thu Apr 21 01:42:29 2005 +0000 3.3 @@ -16,6 +16,7 @@ vpath %c $(XEN_LIBXUTIL) 3.4 INCLUDES += -I $(XEN_LIBXUTIL) 3.5 3.6 SRCS := 3.7 +SRCS += xc_sedf.c 3.8 SRCS += xc_bvtsched.c 3.9 SRCS += xc_domain.c 3.10 SRCS += xc_evtchn.c
4.1 --- a/tools/libxc/xc.h Wed Apr 20 21:22:46 2005 +0000 4.2 +++ b/tools/libxc/xc.h Thu Apr 21 01:42:29 2005 +0000 4.3 @@ -257,6 +257,14 @@ int xc_bvtsched_domain_get(int xc_handle 4.4 long long *warpl, 4.5 long long *warpu); 4.6 4.7 +int xc_sedf_domain_set(int xc_handle, 4.8 + u32 domid, 4.9 + u64 period, u64 slice, u64 latency, u16 extratime, u16 weight); 4.10 + 4.11 +int xc_sedf_domain_get(int xc_handle, 4.12 + u32 domid, 4.13 + u64* period, u64 *slice, u64 *latency, u16 *extratime, u16* weight); 4.14 + 4.15 typedef evtchn_status_t xc_evtchn_status_t; 4.16 4.17 /*
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/tools/libxc/xc_sedf.c Thu Apr 21 01:42:29 2005 +0000 5.3 @@ -0,0 +1,51 @@ 5.4 +/****************************************************************************** 5.5 + * xc_sedf.c 5.6 + * 5.7 + * API for manipulating parameters of the Simple EDF scheduler. 5.8 + * 5.9 + * changes by Stephan Diestelhorst 5.10 + * based on code 5.11 + * by Mark Williamson, Copyright (c) 2004 Intel Research Cambridge. 5.12 + */ 5.13 + 5.14 +#include "xc_private.h" 5.15 + 5.16 +int xc_sedf_domain_set(int xc_handle, 5.17 + u32 domid, u64 period, u64 slice,u64 latency, u16 extratime,u16 weight) 5.18 +{ 5.19 + dom0_op_t op; 5.20 + struct sedf_adjdom *p = &op.u.adjustdom.u.sedf; 5.21 + 5.22 + op.cmd = DOM0_ADJUSTDOM; 5.23 + op.u.adjustdom.domain = (domid_t)domid; 5.24 + op.u.adjustdom.sched_id = SCHED_SEDF; 5.25 + op.u.adjustdom.direction = SCHED_INFO_PUT; 5.26 + 5.27 + p->period = period; 5.28 + p->slice = slice; 5.29 + p->latency = latency; 5.30 + p->extratime = extratime; 5.31 + p->weight = weight; 5.32 + return do_dom0_op(xc_handle, &op); 5.33 +} 5.34 + 5.35 +int xc_sedf_domain_get(int xc_handle, u32 domid, u64 *period, u64 *slice, u64* latency, u16* extratime, u16* weight) 5.36 +{ 5.37 + dom0_op_t op; 5.38 + int ret; 5.39 + struct sedf_adjdom *p = &op.u.adjustdom.u.sedf; 5.40 + 5.41 + op.cmd = DOM0_ADJUSTDOM; 5.42 + op.u.adjustdom.domain = (domid_t)domid; 5.43 + op.u.adjustdom.sched_id = SCHED_SEDF; 5.44 + op.u.adjustdom.direction = SCHED_INFO_GET; 5.45 + 5.46 + ret = do_dom0_op(xc_handle, &op); 5.47 + 5.48 + *period = p->period; 5.49 + *slice = p->slice; 5.50 + *latency = p->latency; 5.51 + *extratime = p->extratime; 5.52 + *weight = p->weight; 5.53 + return ret; 5.54 +}
6.1 --- a/tools/python/xen/lowlevel/xc/xc.c Wed Apr 20 21:22:46 2005 +0000 6.2 +++ b/tools/python/xen/lowlevel/xc/xc.c Thu Apr 21 01:42:29 2005 +0000 6.3 @@ -800,6 +800,52 @@ static PyObject *pyxc_physinfo(PyObject 6.4 "cpu_khz", info.cpu_khz); 6.5 } 6.6 6.7 +static PyObject *pyxc_sedf_domain_set(PyObject *self, 6.8 + PyObject *args, 6.9 + PyObject *kwds) 6.10 +{ 6.11 + XcObject *xc = (XcObject *)self; 6.12 + u32 domid; 6.13 + u64 period, slice, latency; 6.14 + u16 extratime, weight; 6.15 + static char *kwd_list[] = { "dom", "period", "slice", "latency", "extratime", "weight",NULL }; 6.16 + 6.17 + if( !PyArg_ParseTupleAndKeywords(args, kwds, "iLLLhh", kwd_list, &domid, 6.18 + &period, &slice, &latency, &extratime, &weight) ) 6.19 + return NULL; 6.20 + if ( xc_sedf_domain_set(xc->xc_handle, domid, period, slice, latency, extratime,weight) != 0 ) 6.21 + return PyErr_SetFromErrno(xc_error); 6.22 + 6.23 + Py_INCREF(zero); 6.24 + return zero; 6.25 +} 6.26 + 6.27 +static PyObject *pyxc_sedf_domain_get(PyObject *self, 6.28 + PyObject *args, 6.29 + PyObject *kwds) 6.30 +{ 6.31 + XcObject *xc = (XcObject *)self; 6.32 + u32 domid; 6.33 + u64 period, slice,latency; 6.34 + u16 weight, extratime; 6.35 + 6.36 + static char *kwd_list[] = { "dom", NULL }; 6.37 + 6.38 + if( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &domid) ) 6.39 + return NULL; 6.40 + 6.41 + if ( xc_sedf_domain_get( xc->xc_handle, domid, &period, 6.42 + &slice,&latency,&extratime,&weight) ) 6.43 + return PyErr_SetFromErrno(xc_error); 6.44 + 6.45 + return Py_BuildValue("{s:i,s:L,s:L,s:L,s:i}", 6.46 + "domain", domid, 6.47 + "period", period, 6.48 + "slice", slice, 6.49 + "latency", latency, 6.50 + "extratime", extratime); 6.51 +} 6.52 + 6.53 static PyObject *pyxc_shadow_control(PyObject *self, 6.54 PyObject *args, 6.55 PyObject *kwds) 6.56 @@ -992,6 +1038,30 @@ static PyMethodDef pyxc_methods[] = { 6.57 " warpu [long]: Unwarp requirement.\n" 6.58 " warpl [long]: Warp limit,\n" 6.59 }, 6.60 + 6.61 + { "sedf_domain_set", 6.62 + (PyCFunction)pyxc_sedf_domain_set, 6.63 + METH_KEYWORDS, "\n" 6.64 + "Set the scheduling parameters for a domain when running with Atropos.\n" 6.65 + " dom [int]: domain to set\n" 6.66 + " period [long]: domain's scheduling period\n" 6.67 + " slice [long]: domain's slice per period\n" 6.68 + " latency [long]: domain's wakeup latency hint\n" 6.69 + " extratime [int]: domain aware of extratime?\n" 6.70 + "Returns: [int] 0 on success; -1 on error.\n" }, 6.71 + 6.72 + { "sedf_domain_get", 6.73 + (PyCFunction)pyxc_sedf_domain_get, 6.74 + METH_KEYWORDS, "\n" 6.75 + "Get the current scheduling parameters for a domain when running with\n" 6.76 + "the Atropos scheduler." 6.77 + " dom [int]: domain to query\n" 6.78 + "Returns: [dict]\n" 6.79 + " domain [int]: domain ID\n" 6.80 + " period [long]: scheduler period\n" 6.81 + " slice [long]: CPU reservation per period\n" 6.82 + " latency [long]: domain's wakeup latency hint\n" 6.83 + " extratime [int]: domain aware of extratime?\n"}, 6.84 6.85 { "evtchn_alloc_unbound", 6.86 (PyCFunction)pyxc_evtchn_alloc_unbound,
7.1 --- a/tools/python/xen/xend/XendClient.py Wed Apr 20 21:22:46 2005 +0000 7.2 +++ b/tools/python/xen/xend/XendClient.py Thu Apr 21 01:42:29 2005 +0000 7.3 @@ -260,6 +260,15 @@ class Xend: 7.4 'warpl' : warpl, 7.5 'warpu' : warpu }) 7.6 7.7 + def xend_domain_cpu_sedf_set(self, id, period, slice, latency, extratime, weight): 7.8 + return self.xendPost(self.domainurl(id), 7.9 + {'op' : 'cpu_sedf_set', 7.10 + 'period' : period, 7.11 + 'slice' : slice, 7.12 + 'latency' : latency, 7.13 + 'extratime' : extratime, 7.14 + 'weight' : weight }) 7.15 + 7.16 def xend_domain_maxmem_set(self, id, memory): 7.17 return self.xendPost(self.domainurl(id), 7.18 { 'op' : 'maxmem_set',
8.1 --- a/tools/python/xen/xend/XendDomain.py Wed Apr 20 21:22:46 2005 +0000 8.2 +++ b/tools/python/xen/xend/XendDomain.py Thu Apr 21 01:42:29 2005 +0000 8.3 @@ -642,6 +642,24 @@ class XendDomain: 8.4 except Exception, ex: 8.5 raise XendError(str(ex)) 8.6 8.7 + 8.8 + def domain_cpu_sedf_set(self, id, period, slice, latency, extratime, weight): 8.9 + """Set Simple EDF scheduler parameters for a domain. 8.10 + """ 8.11 + dominfo = self.domain_lookup(id) 8.12 + try: 8.13 + return xc.sedf_domain_set(dominfo.dom, period, slice, latency, extratime, weight) 8.14 + except Exception, ex: 8.15 + raise XendError(str(ex)) 8.16 + 8.17 + def domain_cpu_sedf_get(self, id): 8.18 + """Get Atropos scheduler parameters for a domain. 8.19 + """ 8.20 + dominfo = self.domain_lookup(id) 8.21 + try: 8.22 + return xc.sedf_domain_get(dominfo.dom) 8.23 + except Exception, ex: 8.24 + raise XendError(str(ex)) 8.25 def domain_device_create(self, id, devconfig): 8.26 """Create a new device for a domain. 8.27
9.1 --- a/tools/python/xen/xend/server/SrvDomain.py Wed Apr 20 21:22:46 2005 +0000 9.2 +++ b/tools/python/xen/xend/server/SrvDomain.py Thu Apr 21 01:42:29 2005 +0000 9.3 @@ -107,6 +107,18 @@ class SrvDomain(SrvDir): 9.4 val = fn(req.args, {'dom': self.dom.id}) 9.5 return val 9.6 9.7 + 9.8 + def op_cpu_sedf_set(self, op, req): 9.9 + fn = FormFn(self.xd.domain_cpu_sedf_set, 9.10 + [['dom', 'str'], 9.11 + ['period', 'int'], 9.12 + ['slice', 'int'], 9.13 + ['latency', 'int'], 9.14 + ['extratime', 'int'], 9.15 + ['weight', 'int']]) 9.16 + val = fn(req.args, {'dom': self.dom.id}) 9.17 + return val 9.18 + 9.19 def op_maxmem_set(self, op, req): 9.20 fn = FormFn(self.xd.domain_maxmem_set, 9.21 [['dom', 'str'],
10.1 --- a/tools/python/xen/xm/main.py Wed Apr 20 21:22:46 2005 +0000 10.2 +++ b/tools/python/xen/xm/main.py Thu Apr 21 01:42:29 2005 +0000 10.3 @@ -591,6 +591,23 @@ class ProgBvtslice(Prog): 10.4 10.5 xm.prog(ProgBvtslice) 10.6 10.7 +class ProgSedf(Prog): 10.8 + group = 'scheduler' 10.9 + name= "sedf" 10.10 + info = """Set simple EDF parameters.""" 10.11 + 10.12 + def help(self, args): 10.13 + print args[0], "DOM PERIOD SLICE LATENCY EXTRATIME WEIGHT" 10.14 + print "\nSet simple EDF parameters." 10.15 + 10.16 + def main(self, args): 10.17 + if len(args) != 7: self.err("%s: Invalid argument(s)" % args[0]) 10.18 + dom = args[1] 10.19 + v = map(int, args[2:7]) 10.20 + server.xend_domain_cpu_sedf_set(dom, *v) 10.21 + 10.22 +xm.prog(ProgSedf) 10.23 + 10.24 class ProgInfo(Prog): 10.25 group = 'host' 10.26 name = "info"
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/xen/common/sched_sedf.c Thu Apr 21 01:42:29 2005 +0000 11.3 @@ -0,0 +1,1420 @@ 11.4 +/**************************************************************************** 11.5 + * Simple EDF scheduler for xen 11.6 + * 11.7 + * by Stephan Diestelhorst (C) 2004 Cambridge University 11.8 + * based on code by Mark Williamson (C) 2004 Intel Research Cambridge 11.9 + */ 11.10 + 11.11 +#include <xen/sched.h> 11.12 +#include <xen/sched-if.h> 11.13 +#include <public/sched_ctl.h> 11.14 +#include <xen/ac_timer.h> 11.15 +#include <xen/softirq.h> 11.16 +#include <xen/time.h> 11.17 +#include <xen/slab.h> 11.18 + 11.19 +/*#include <xen/adv_sched_hist.h>*/ 11.20 + 11.21 +/*verbosity settings*/ 11.22 +#define SEDFLEVEL 0 11.23 +#define PRINT(_f, _a...) \ 11.24 +if ((_f)<=SEDFLEVEL) printk(_a ); 11.25 + 11.26 +#ifdef DEBUG 11.27 + #define SEDF_STATS 11.28 +#endif 11.29 + 11.30 +/*various ways of unblocking domains*/ 11.31 +#define UNBLOCK_ISOCHRONOUS_EDF 1 11.32 +#define UNBLOCK_EDF 2 11.33 +#define UNBLOCK_ATROPOS 3 11.34 +#define UNBLOCK_SHORT_RESUME 4 11.35 +#define UNBLOCK_BURST 5 11.36 +#define UNBLOCK_EXTRA_SUPPORT 6 11.37 +#define UNBLOCK UNBLOCK_EXTRA_SUPPORT 11.38 + 11.39 +/*various ways of treating extra-time*/ 11.40 +#define EXTRA_OFF 1 11.41 +#define EXTRA_ROUNDR 2 11.42 +#define EXTRA_SLICE_WEIGHT 3 11.43 +#define EXTRA_BLOCK_WEIGHT 4 11.44 + 11.45 +#define EXTRA EXTRA_BLOCK_WEIGHT 11.46 + 11.47 +#define EXTRA_NONE (0) 11.48 +#define EXTRA_AWARE (1) 11.49 +#define EXTRA_RUN_PEN (2) 11.50 +#define EXTRA_RUN_UTIL (4) 11.51 +#define EXTRA_WANT_PEN_Q (8) 11.52 +#define EXTRA_PEN_Q (0) 11.53 +#define EXTRA_UTIL_Q (1) 11.54 + 11.55 +#define extra_runs(inf) ((inf->extra) & 6) 11.56 +#define extra_get_cur_q(inf) (((inf->extra & 6) >> 1)-1) 11.57 + 11.58 +#define EXTRA_QUANTUM (MICROSECS(500)) 11.59 +#define WEIGHT_PERIOD (MILLISECS(100)) 11.60 +#define WEIGHT_SAFETY (MILLISECS(5)) 11.61 + 11.62 + 11.63 +struct sedf_dom_info 11.64 +{ 11.65 + struct domain *owner; 11.66 + struct list_head list; 11.67 + struct list_head extralist[2]; 11.68 + 11.69 + /*Parameters for EDF*/ 11.70 + s_time_t period; /*=(relative deadline)*/ 11.71 + s_time_t slice; /*=worst case execution time*/ 11.72 + 11.73 + /*Advaced Parameters*/ 11.74 + /*Latency Scaling*/ 11.75 + s_time_t period_orig; 11.76 + s_time_t slice_orig; 11.77 + s_time_t latency; 11.78 + 11.79 + /*extra-time status of domain*/ 11.80 + short extra; 11.81 + /*weights for "Scheduling for beginners/ lazy/ etc." ;)*/ 11.82 + short weight; 11.83 + 11.84 + /*Bookkeeping*/ 11.85 + s_time_t absdead; 11.86 + s_time_t sched_start; 11.87 + s_time_t cputime; 11.88 + s_time_t absblock; 11.89 + 11.90 + /*time the domain unblocked, used to determine unblocking intervals*/ 11.91 + s_time_t absunblock; 11.92 + 11.93 + /*scores for {util, block penalty}-weighted extratime distribution*/ 11.94 + int score[2]; 11.95 + s_time_t short_block_lost_tot; 11.96 + 11.97 + /*Statistics*/ 11.98 + s_time_t extra_time_tot; 11.99 + 11.100 +#ifdef SEDF_STATS 11.101 + s_time_t block_time_tot; 11.102 + s_time_t penalty_time_tot; 11.103 + int block_tot; 11.104 + int short_block_tot; 11.105 + int long_block_tot; 11.106 + int short_cont; 11.107 + int pen_extra_blocks; 11.108 + int pen_extra_slices; 11.109 +#endif 11.110 +}; 11.111 + 11.112 +struct sedf_cpu_info { 11.113 + struct list_head runnableq; 11.114 + struct list_head waitq; 11.115 + struct list_head extraq[2]; 11.116 +}; 11.117 + 11.118 +#define DOM_INFO(d) ((struct sedf_dom_info *)((d)->sched_priv)) 11.119 +#define CPU_INFO(cpu) ((struct sedf_cpu_info *)schedule_data[cpu].sched_priv) 11.120 +#define LIST(d) (&DOM_INFO(d)->list) 11.121 +#define EXTRALIST(d,i) (&(DOM_INFO(d)->extralist[i])) 11.122 +#define RUNQ(cpu) (&CPU_INFO(cpu)->runnableq) 11.123 +#define WAITQ(cpu) (&CPU_INFO(cpu)->waitq) 11.124 +#define EXTRAQ(cpu,i) (&(CPU_INFO(cpu)->extraq[i])) 11.125 +#define IDLETASK(cpu) ((struct domain *)schedule_data[cpu].idle) 11.126 + 11.127 +#define PERIOD_BEGIN(inf) ((inf)->absdead - (inf)->period) 11.128 + 11.129 +#define MIN(x,y) (((x)<(y))?(x):(y)) 11.130 +#define DIV_UP(x,y) (((x) + (y) - 1) / y) 11.131 + 11.132 +static xmem_cache_t *dom_info_cache; 11.133 + 11.134 +static void sedf_dump_cpu_state(int i); 11.135 + 11.136 +static inline int extraq_on(struct domain *d, int i) { 11.137 + return ((EXTRALIST(d,i)->next != NULL) && 11.138 + (EXTRALIST(d,i)->next != EXTRALIST(d,i))); 11.139 +} 11.140 + 11.141 +static inline void extraq_add_head(struct domain *d, int i) 11.142 +{ 11.143 + list_add(EXTRALIST(d,i), EXTRAQ(d->processor,i)); 11.144 +} 11.145 + 11.146 +static inline void extraq_add_tail(struct domain *d, int i) 11.147 +{ 11.148 + list_add_tail(EXTRALIST(d,i), EXTRAQ(d->processor,i)); 11.149 +} 11.150 + 11.151 +static inline void extraq_del(struct domain *d, int i) 11.152 +{ 11.153 + struct list_head *list = EXTRALIST(d,i); 11.154 + /*if (!extraq_on(d,i)) { 11.155 + PRINT(0,"extraq_del: domain %i is NOT on L%i extraq "\ 11.156 + "HALTING\n",d->id,i); 11.157 + sedf_dump_cpu_state(0);(*((int*)0))++; 11.158 + }*/ 11.159 + PRINT(3, "Removing domain %i from L%i extraq\n", d->id,i); 11.160 + list_del(list); 11.161 + list->next = NULL; 11.162 +} 11.163 + 11.164 +/* adds a domain to the queue of processes which are aware of extra time. List 11.165 + is sorted by score, where a lower score means higher priority for an extra 11.166 + slice. It also updates the score, by simply subtracting a fixed value from 11.167 + each entry, in order to avoid overflow. The algorithm works by simply 11.168 + charging each domain that recieved extratime with an inverse of its weight. 11.169 + */ 11.170 +static inline void extraq_add_sort_update(struct domain *d, int i, int sub) { 11.171 + struct list_head *cur; 11.172 + struct sedf_dom_info *curinf; 11.173 + 11.174 + /*if (extraq_on(d,i)) { 11.175 + PRINT(0,"extraq_add_sort_update: domain %i is already on "\ 11.176 + "L%i extraq! HALTING\n",d->id,i); 11.177 + sedf_dump_cpu_state(0);(*((int*)0))++; 11.178 + }*/ 11.179 + PRINT(3, "Adding domain %i (score= %i, short_pen= %lli) to L%i "\ 11.180 + "extraq\n", d->id, DOM_INFO(d)->score[i], 11.181 + DOM_INFO(d)->short_block_lost_tot, i); 11.182 + /*iterate through all elements to find our "hole" and on our way 11.183 + update all the other scores*/ 11.184 + list_for_each(cur,EXTRAQ(d->processor,i)){ 11.185 + curinf = list_entry(cur,struct sedf_dom_info,extralist[i]); 11.186 + curinf->score[i] -= sub; 11.187 + if (DOM_INFO(d)->score[i] < curinf->score[i]) 11.188 + break; 11.189 + else 11.190 + PRINT(4,"\tbehind domain %i (score= %i)\n", 11.191 + curinf->owner->id, curinf->score[i]); 11.192 + } 11.193 + /*cur now contains the element, before which we'll enqueue*/ 11.194 + PRINT(3, "\tlist_add to %x\n", cur->prev); 11.195 + list_add(EXTRALIST(d,i),cur->prev); 11.196 + 11.197 + /*continue updating the extraq*/ 11.198 + if ((cur != EXTRAQ(d->processor,i)) && sub) 11.199 + for (cur = cur->next; cur != EXTRAQ(d->processor,i); 11.200 + cur = cur-> next) { 11.201 + curinf = list_entry(cur,struct sedf_dom_info, 11.202 + extralist[i]); 11.203 + curinf->score[i] -= sub; 11.204 + PRINT(4, "\tupdating domain %i (score= %llu)\n", 11.205 + curinf->owner->id, curinf->score[i]); 11.206 + } 11.207 +} 11.208 +static inline void extraq_check(struct domain *d) { 11.209 + if (extraq_on(d, EXTRA_UTIL_Q)) { 11.210 + PRINT(2,"Dom %i is on extraQ\n",d->id); 11.211 + if (!(DOM_INFO(d)->extra & EXTRA_AWARE) && 11.212 + !extra_runs(DOM_INFO(d))) { 11.213 + extraq_del(d, EXTRA_UTIL_Q); 11.214 + PRINT(2,"Removed dom %i from L1 extraQ\n",d->id); 11.215 + } 11.216 + } else { 11.217 + PRINT(2,"Dom %i is NOT on L1 extraQ\n",d->id); 11.218 + if ((DOM_INFO(d)->extra & EXTRA_AWARE) && domain_runnable(d)) 11.219 + { 11.220 + #if (EXTRA == EXTRA_ROUNDR) 11.221 + /*Favour domains which got short unblocked*/ 11.222 + extraq_add_tail(d, EXTRA_UTIL_Q); 11.223 + #elif (EXTRA == EXTRA_SLICE_WEIGHT || \ 11.224 + EXTRA == EXTRA_BLOCK_WEIGHT) 11.225 + extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); 11.226 + #elif 11.227 + ; 11.228 + #endif 11.229 + PRINT(2,"Added dom %i to L1 extraQ\n",d->id); 11.230 + } 11.231 + } 11.232 +} 11.233 +static inline void __del_from_queue(struct domain *d) 11.234 +{ 11.235 + struct list_head *list = LIST(d); 11.236 + PRINT(3,"Removing domain %i (bop= %llu) from runq/waitq\n", d->id, 11.237 + PERIOD_BEGIN(DOM_INFO(d))); 11.238 + list_del(list); 11.239 + list->next = NULL; 11.240 +} 11.241 + 11.242 +/* adds a domain to the queue of processes which wait for the beginning of the 11.243 + next period; this list is therefore sortet by this time, which is simply 11.244 + absol. deadline - period 11.245 + */ 11.246 +static inline void __add_to_waitqueue_sort(struct domain *d) { 11.247 + struct list_head *cur; 11.248 + struct sedf_dom_info *curinf; 11.249 + 11.250 + PRINT(3,"Adding domain %i (bop= %llu) to waitq\n", d->id, 11.251 + PERIOD_BEGIN(DOM_INFO(d))); 11.252 + 11.253 + /*iterate through all elements to find our "hole"*/ 11.254 + list_for_each(cur,WAITQ(d->processor)){ 11.255 + curinf = list_entry(cur,struct sedf_dom_info,list); 11.256 + if (PERIOD_BEGIN(DOM_INFO(d)) < PERIOD_BEGIN(curinf)) 11.257 + break; 11.258 + else 11.259 + PRINT(4,"\tbehind domain %i (bop= %llu)\n", 11.260 + curinf->owner->id, PERIOD_BEGIN(curinf)); 11.261 + } 11.262 + /*cur now contains the element, before which we'll enqueue*/ 11.263 + PRINT(3,"\tlist_add to %x\n",cur->prev); 11.264 + list_add(LIST(d),cur->prev); 11.265 + 11.266 +} 11.267 + 11.268 +/* adds a domain to the queue of processes which have started their current 11.269 + period and are runnable (i.e. not blocked, dieing,...). The first element 11.270 + on this list is running on the processor, if the list is empty the idle 11.271 + task will run. As we are implementing EDF, this list is sorted by deadlines. 11.272 + */ 11.273 +static inline void __add_to_runqueue_sort(struct domain *d) { 11.274 + struct list_head *cur; 11.275 + struct sedf_dom_info *curinf; 11.276 + 11.277 + PRINT(3,"Adding domain %i (deadl= %llu) to runq\n", d->id, 11.278 + DOM_INFO(d)->absdead); 11.279 + 11.280 + /*iterate through all elements to find our "hole"*/ 11.281 + list_for_each(cur, RUNQ(d->processor)) { 11.282 + curinf = list_entry(cur, struct sedf_dom_info, list); 11.283 + if (DOM_INFO(d)->absdead < curinf->absdead) 11.284 + break; 11.285 + else 11.286 + PRINT(4,"\tbehind domain %i (deadl= %llu)\n", 11.287 + curinf->owner->id, curinf->absdead); 11.288 + } 11.289 + 11.290 + /*cur now contains the element, before which we'll enqueue*/ 11.291 + PRINT(3,"\tlist_add to %x\n",cur->prev); 11.292 + list_add(LIST(d),cur->prev); 11.293 + 11.294 +} 11.295 +static inline int __task_on_queue(struct domain *d) { 11.296 + return (((LIST(d))->next != NULL) && (LIST(d)->next != LIST(d))); 11.297 +} 11.298 + 11.299 +/* Initialises the queues and creates the domain info cache */ 11.300 +static int sedf_init_scheduler() { 11.301 + int i; 11.302 + PRINT(2,"sedf_init_scheduler was called\n"); 11.303 + 11.304 + for ( i = 0; i < NR_CPUS; i++ ) { 11.305 + schedule_data[i].sched_priv = 11.306 + xmalloc(sizeof(struct sedf_cpu_info)); 11.307 + if ( schedule_data[i].sched_priv == NULL ) 11.308 + return -1; 11.309 + INIT_LIST_HEAD(WAITQ(i)); 11.310 + INIT_LIST_HEAD(RUNQ(i)); 11.311 + INIT_LIST_HEAD(EXTRAQ(i,EXTRA_PEN_Q)); 11.312 + INIT_LIST_HEAD(EXTRAQ(i,EXTRA_UTIL_Q)); 11.313 + } 11.314 + dom_info_cache = xmem_cache_create("SEDF dom info", 11.315 + sizeof(struct sedf_dom_info), 0, 0, 0, NULL); 11.316 + if ( dom_info_cache == NULL ) 11.317 + { 11.318 + printk("Could not allocate SLAB cache.\n"); 11.319 + return -1; 11.320 + } 11.321 + 11.322 + return 0; 11.323 +} 11.324 + 11.325 +/* Allocates memory for per domain private scheduling data*/ 11.326 +static int sedf_alloc_task(struct domain *d) { 11.327 + PRINT(2,"sedf_alloc_task was called, domain-id %i\n",d->id); 11.328 + if ( (d->sched_priv = xmem_cache_alloc(dom_info_cache)) == NULL ) 11.329 + return -1; 11.330 + memset(d->sched_priv, 0, sizeof(struct sedf_dom_info)); 11.331 + return 0; 11.332 +} 11.333 + 11.334 +/* Setup the sedf_dom_info */ 11.335 +static void sedf_add_task(struct domain *d) 11.336 +{ 11.337 + struct sedf_dom_info *inf=DOM_INFO(d); 11.338 + inf->owner = d; 11.339 + 11.340 + PRINT(2,"sedf_add_task was called, domain-id %i\n",d->id); 11.341 + if (d->id==0) { 11.342 + /*set dom0 to something useful to boot the machine*/ 11.343 + inf->period = MILLISECS(20); 11.344 + inf->slice = MILLISECS(15); 11.345 + inf->latency = 0; 11.346 + inf->absdead = 0; 11.347 + inf->extra = EXTRA_NONE;/*EXTRA_AWARE; */ 11.348 + } 11.349 + else { 11.350 + /*other domains run in best effort mode*/ 11.351 + inf->period = MILLISECS(20); 11.352 + inf->slice = 0; 11.353 + inf->absdead = 0; 11.354 + inf->latency = 0; 11.355 + inf->extra = EXTRA_AWARE; 11.356 + } 11.357 + inf->period_orig = inf->period; inf->slice_orig = inf->slice; 11.358 + INIT_LIST_HEAD(&(inf->list)); 11.359 + INIT_LIST_HEAD(&(inf->extralist[EXTRA_PEN_Q])); 11.360 + INIT_LIST_HEAD(&(inf->extralist[EXTRA_UTIL_Q])); 11.361 +} 11.362 + 11.363 +/* Frees memory used by domain info */ 11.364 +static void sedf_free_task(struct domain *d) 11.365 +{ 11.366 + PRINT(2,"sedf_free_task was called, domain-id %i\n",d->id); 11.367 + ASSERT(d->sched_priv != NULL); 11.368 + xmem_cache_free(dom_info_cache, d->sched_priv); 11.369 +} 11.370 + 11.371 +/* Initialises idle task */ 11.372 +static int sedf_init_idle_task(struct domain *d) { 11.373 + PRINT(2,"sedf_init_idle_task was called, domain-id %i\n",d->id); 11.374 + if ( sedf_alloc_task(d) < 0 ) 11.375 + return -1; 11.376 + 11.377 + sedf_add_task(d); 11.378 + DOM_INFO(d)->absdead = 0; 11.379 + set_bit(DF_RUNNING, &d->flags); 11.380 + /*the idle task doesn't have to turn up on any list...*/ 11.381 + return 0; 11.382 +} 11.383 + 11.384 +/* handles the rescheduling, bookkeeping of domains running in their realtime-time :)*/ 11.385 +static inline void desched_edf_dom (s_time_t now, struct domain* d) { 11.386 + struct sedf_dom_info* inf = DOM_INFO(d); 11.387 + /*current domain is running in real time mode*/ 11.388 + 11.389 + /*update the domains cputime*/ 11.390 + inf->cputime += now - inf->sched_start; 11.391 + 11.392 + /*scheduling decisions, which don't remove the running domain 11.393 + from the runq*/ 11.394 + if ((inf->cputime < inf->slice) && domain_runnable(d)) 11.395 + return; 11.396 + 11.397 + __del_from_queue(d); 11.398 + /*if (__task_on_queue(current)) { 11.399 + PRINT(0,"domain %i was removed but still on run/waitq => "\ 11.400 + "HALT\n",current->id); 11.401 + sedf_dump_cpu_state(0);(*((int*)0))++; 11.402 + }*/ 11.403 + 11.404 + /*manage bookkeeping (i.e. calculate next deadline, 11.405 + memorize overun-time of slice) of finished domains*/ 11.406 + if (inf->cputime >= inf->slice) { 11.407 + inf->cputime -= inf->slice; 11.408 + 11.409 + if (inf->period < inf->period_orig) { 11.410 + /*this domain runs in latency scaling or burst mode*/ 11.411 + #if (UNBLOCK == UNBLOCK_BURST) 11.412 + if (now - inf->absunblock >= 2 * inf->period) 11.413 + #endif 11.414 + { 11.415 + inf->period *= 2; inf->slice *= 2; 11.416 + if ((inf->period > inf->period_orig) || 11.417 + (inf->slice > inf->slice_orig)) { 11.418 + /*reset slice & period*/ 11.419 + inf->period = inf->period_orig; 11.420 + inf->slice = inf->slice_orig; 11.421 + } 11.422 + } 11.423 + } 11.424 + /*set next deadline*/ 11.425 + inf->absdead += inf->period; 11.426 + } 11.427 + /*if (inf->absdead<now) 11.428 + printk("Domain %i exceeded it't deadline!!!! "\ 11.429 + "(now: %llu ddl: %llu)\n", current->id, now, 11.430 + inf->absdead);*/ 11.431 + 11.432 + /*add a runnable domain to the waitqueue*/ 11.433 + if (domain_runnable(d)) 11.434 + __add_to_waitqueue_sort(d); 11.435 + else { 11.436 + /*we have a blocked realtime task*/ 11.437 + inf->absblock = now; 11.438 + #if (EXTRA > EXTRA_OFF) 11.439 + #if (EXTRA == EXTRA_BLOCK_WEIGHT) 11.440 + if (extraq_on(d,EXTRA_PEN_Q)) extraq_del(d,EXTRA_PEN_Q); 11.441 + #endif 11.442 + if (extraq_on(d,EXTRA_UTIL_Q)) extraq_del(d,EXTRA_UTIL_Q); 11.443 + #endif 11.444 + } 11.445 +} 11.446 + 11.447 +/* Update all elements on the queues */ 11.448 +static inline void update_queues( 11.449 +s_time_t now, struct list_head* runq, struct list_head* waitq) { 11.450 + struct list_head *cur,*tmp; 11.451 + struct sedf_dom_info *curinf; 11.452 + 11.453 + PRINT(3,"Updating waitq..\n"); 11.454 + /*check for the first elements of the waitqueue, whether their 11.455 + next period has already started*/ 11.456 + list_for_each_safe(cur, tmp, waitq) { 11.457 + curinf = list_entry(cur, struct sedf_dom_info, list); 11.458 + PRINT(4,"\tLooking @ dom %i\n", curinf->owner->id); 11.459 + if (PERIOD_BEGIN(curinf) <= now) { 11.460 + __del_from_queue(curinf->owner); 11.461 + __add_to_runqueue_sort(curinf->owner); 11.462 + } 11.463 + else 11.464 + break; 11.465 + } 11.466 + 11.467 + PRINT(3,"Updating runq..\n"); 11.468 + /*process the runq, find domains that are on 11.469 + the runqueue which shouldn't be there*/ 11.470 + list_for_each_safe(cur, tmp, runq) { 11.471 + curinf = list_entry(cur,struct sedf_dom_info,list); 11.472 + PRINT(4,"\tLooking @ dom %i\n", curinf->owner->id); 11.473 + if (unlikely(curinf->slice == 0)) { 11.474 + /*ignore domains with empty slice*/ 11.475 + PRINT(4,"\tUpdating zero-slice domain %i\n", 11.476 + curinf->owner->id); 11.477 + __del_from_queue(curinf->owner); 11.478 + 11.479 + /*move them to their next period*/ 11.480 + curinf->absdead += curinf->period; 11.481 + /*and put them back into the queue*/ 11.482 + __add_to_waitqueue_sort(curinf->owner); 11.483 + } 11.484 + else { 11.485 + if (unlikely((curinf->absdead < now) || 11.486 + (curinf->cputime > curinf->slice))) { 11.487 + /*we missed the deadline or the slice was 11.488 + already finished... might hapen because 11.489 + of dom_adj.*/ 11.490 + PRINT(4,"\tDomain %i exceeded it's deadline/"\ 11.491 + "slice (%llu / %llu) now: %llu "\ 11.492 + "cputime: %llu\n", curinf->owner->id, 11.493 + curinf->absdead, curinf->slice, now, 11.494 + curinf->cputime); 11.495 + __del_from_queue(curinf->owner); 11.496 + /*common case: we miss one period!*/ 11.497 + curinf->absdead += curinf->period; 11.498 + 11.499 + /*if we are still behind: modulo arithmetic, 11.500 + force deadline to be in future and 11.501 + aligned to period borders!*/ 11.502 + if (unlikely(curinf->absdead < now)) 11.503 + curinf->absdead += 11.504 + DIV_UP(now - curinf->absdead, 11.505 + curinf->period) * curinf->period; 11.506 + 11.507 + /*give a fresh slice*/ 11.508 + curinf->cputime = 0; 11.509 + if (PERIOD_BEGIN(curinf) < now) 11.510 + __add_to_waitqueue_sort(curinf->owner); 11.511 + else 11.512 + __add_to_runqueue_sort(curinf->owner); 11.513 + } 11.514 + else 11.515 + break; 11.516 + } 11.517 + } 11.518 + PRINT(3,"done updating the queues\n"); 11.519 +} 11.520 + 11.521 +#if (EXTRA > EXTRA_OFF) 11.522 +/* removes a domain from the head of the according extraQ and 11.523 + requeues it at a specified position: 11.524 + round-robin extratime: end of extraQ 11.525 + weighted ext.: insert in sorted list by score 11.526 + if the domain is blocked / has regained its short-block-loss 11.527 + time it is not put on any queue */ 11.528 +static inline void desched_extra_dom(s_time_t now, struct domain* d) { 11.529 + struct sedf_dom_info *inf = DOM_INFO(d); 11.530 + int i = extra_get_cur_q(inf); 11.531 + 11.532 + #if (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) 11.533 + unsigned long oldscore; 11.534 + #endif 11.535 + 11.536 + /*unset all running flags*/ 11.537 + inf->extra &= ~(EXTRA_RUN_PEN | EXTRA_RUN_UTIL); 11.538 + /*fresh slice for the next run*/ 11.539 + inf->cputime = 0; 11.540 + /*accumulate total extratime*/ 11.541 + inf->extra_time_tot += now - inf->sched_start; 11.542 + /*remove extradomain from head of the queue*/ 11.543 + extraq_del(d, i); 11.544 + 11.545 + #if (EXTRA == EXTRA_ROUNDR) 11.546 + if (domain_runnable(d)) 11.547 + /*add to the tail if it is runnable => round-robin*/ 11.548 + extraq_add_tail(d, EXTRA_UTIL_Q); 11.549 + #elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) 11.550 + /*update the score*/ 11.551 + oldscore = inf->score[i]; 11.552 + #if (EXTRA == EXTRA_BLOCK_WEIGHT) 11.553 + if (i == EXTRA_PEN_Q) { 11.554 + /*domain was running in L0 extraq*/ 11.555 + /*reduce block lost, probably more sophistication here!*/ 11.556 + /*inf->short_block_lost_tot -= EXTRA_QUANTUM;*/ 11.557 + inf->short_block_lost_tot -= now - inf->sched_start; 11.558 + PRINT(3,"Domain %i: Short_block_lost: %lli\n", 11.559 + inf->owner->id, inf->short_block_lost_tot); 11.560 + if (inf->short_block_lost_tot <= 0) { 11.561 + PRINT(4,"Domain %i compensated short block loss!\n"); 11.562 + /*we have (over-)compensated our block penalty*/ 11.563 + inf->short_block_lost_tot = 0; 11.564 + /*we don't want a place on the penalty queue anymore!*/ 11.565 + inf->extra &= ~EXTRA_WANT_PEN_Q; 11.566 + /*do not add us on this block extraq again!*/ 11.567 + return; 11.568 + } 11.569 + /*we have to go again for another try in the block-extraq, 11.570 + the score is not used incremantally here, as this is 11.571 + already done by recalculating the block_lost*/ 11.572 + inf->score[EXTRA_PEN_Q] = (inf->period << 10) / 11.573 + inf->short_block_lost_tot; 11.574 + oldscore = 0; 11.575 + } else 11.576 + #endif 11.577 + { 11.578 + /*domain was running in L1 extraq => score is inverse of 11.579 + utilization and is used somewhat incremental!*/ 11.580 + if (inf->slice) 11.581 + /*NB: use fixed point arithmetic with 10 bits*/ 11.582 + inf->score[EXTRA_UTIL_Q] = (inf->period << 10) / 11.583 + inf->slice; 11.584 + else 11.585 + /*set best effort domains to the maximum value*/ 11.586 + inf->score[EXTRA_UTIL_Q] = 2^10; 11.587 + } 11.588 + if (domain_runnable(d)) 11.589 + /*add according to score: weighted round robin*/ 11.590 + extraq_add_sort_update(d, i, oldscore); 11.591 + else { 11.592 + inf->absblock = now; 11.593 + /*if (!__task_on_queue(d)) 11.594 + printf("Oops... We attempt to remove d %i from the "\ 11.595 + "waitq, but it is not on :(\n",d->id);*/ 11.596 + /*remove this blocked domain from the waitq!*/ 11.597 + __del_from_queue(d); 11.598 + /*make sure that we remove a blocked domain from the other 11.599 + extraq aswell (this caused hours of debugging!)*/ 11.600 + #if (EXTRA == EXTRA_BLOCK_WEIGHT) 11.601 + if (i == EXTRA_PEN_Q) { 11.602 + if (extraq_on(d,EXTRA_UTIL_Q)) 11.603 + extraq_del(d,EXTRA_UTIL_Q); 11.604 + } 11.605 + else { 11.606 + if (extraq_on(d,EXTRA_PEN_Q)) 11.607 + extraq_del(d,EXTRA_PEN_Q); 11.608 + } 11.609 + #endif 11.610 + } 11.611 + #endif 11.612 + /*if (!domain_runnable(d)) { 11.613 + if (extraq_on(d,EXTRA_UTIL_Q)) { 11.614 + PRINT(0,"domain %i is blocked but still on L1 "\ 11.615 + "xq=> HALT\n",d->id); 11.616 + sedf_dump_cpu_state(0);(*((int*)0))++; 11.617 + } 11.618 + if (__task_on_queue(d)) { 11.619 + PRINT(0,"domain %i is blocked but still on run/waitq"\ 11.620 + "=> HALT\n",d->id); 11.621 + sedf_dump_cpu_state(0);(*((int*)0))++; 11.622 + } 11.623 + }*/ 11.624 +} 11.625 +#endif 11.626 + 11.627 + 11.628 +static inline task_slice_t sedf_do_extra_schedule 11.629 +(s_time_t now, s_time_t end_xt, struct list_head *extraq[], int cpu) { 11.630 + task_slice_t ret; 11.631 + struct sedf_dom_info *runinf; 11.632 + 11.633 + if (end_xt - now < EXTRA_QUANTUM) 11.634 + goto return_idle; 11.635 +#if (EXTRA == EXTRA_BLOCK_WEIGHT) 11.636 + if (!list_empty(extraq[EXTRA_PEN_Q])) { 11.637 + /*we still have elements on the level 0 extraq 11.638 + => let those run first!*/ 11.639 + runinf = list_entry(extraq[EXTRA_PEN_Q]->next, 11.640 + struct sedf_dom_info, extralist[EXTRA_PEN_Q]); 11.641 + runinf->extra |= EXTRA_RUN_PEN; 11.642 + ret.task = runinf->owner; 11.643 + ret.time = EXTRA_QUANTUM; 11.644 +#ifdef SEDF_STATS 11.645 + runinf->pen_extra_slices++; 11.646 +#endif 11.647 + } else 11.648 +#endif 11.649 + if (!list_empty(extraq[EXTRA_UTIL_Q])) { 11.650 + /*use elements from the normal extraqueue*/ 11.651 + runinf = list_entry(extraq[EXTRA_UTIL_Q]->next, 11.652 + struct sedf_dom_info,extralist[EXTRA_UTIL_Q]); 11.653 + runinf->extra |= EXTRA_RUN_UTIL; 11.654 + ret.task = runinf->owner; 11.655 + ret.time = EXTRA_QUANTUM; 11.656 + } 11.657 + else 11.658 + goto return_idle; 11.659 + 11.660 + return ret; 11.661 + 11.662 +return_idle: 11.663 + ret.task = IDLETASK(cpu); 11.664 + ret.time = end_xt - now; 11.665 + return ret; 11.666 +} 11.667 +/* Main scheduling function 11.668 + Reasons for calling this function are: 11.669 + -timeslice for the current period used up 11.670 + -domain on waitqueue has started it's period 11.671 + -and various others ;) in general: determine which domain to run next*/ 11.672 +static task_slice_t sedf_do_schedule(s_time_t now) 11.673 +{ 11.674 + int cpu = current->processor; 11.675 + struct list_head *runq = RUNQ(cpu); 11.676 + struct list_head *waitq = WAITQ(cpu); 11.677 + #if (EXTRA > EXTRA_OFF) 11.678 + struct sedf_dom_info *inf = DOM_INFO(current); 11.679 + struct list_head *extraq[] = {EXTRAQ(cpu,EXTRA_PEN_Q), 11.680 + EXTRAQ(cpu, EXTRA_UTIL_Q)}; 11.681 + #endif 11.682 + task_slice_t ret; 11.683 + /*int i = 0;*/ 11.684 + /*idle tasks don't need any of the following stuf*/ 11.685 + if (is_idle_task(current)) 11.686 + goto check_waitq; 11.687 + 11.688 + #if (EXTRA > EXTRA_OFF) 11.689 + if (unlikely(extra_runs(inf))) { 11.690 + /*i=1;*/ 11.691 + /*special treatment of domains running in extra time*/ 11.692 + desched_extra_dom(now, current); 11.693 + } 11.694 + else 11.695 + #endif 11.696 + { 11.697 + /*i=2;*/ 11.698 + desched_edf_dom(now, current); 11.699 + } 11.700 + /*if (!domain_runnable(current)) { 11.701 + if (extraq_on(current,EXTRA_UTIL_Q)) { 11.702 + PRINT(0,"domain %i is blocked but still on L1 xq"\ 11.703 + " branch %i=> HALT\n", current->id, i); 11.704 + sedf_dump_cpu_state(0);(*((int*)0))++; 11.705 + } 11.706 + if (__task_on_queue(current)) { 11.707 + PRINT(0,"domain %i is blocked but still on run/waitq"\ 11.708 + " branch %i=> HALT\n",current->id,i); 11.709 + sedf_dump_cpu_state(0);(*((int*)0))++; 11.710 + } 11.711 + }*/ 11.712 +check_waitq: 11.713 + update_queues(now, runq, waitq); 11.714 + 11.715 + /*now simply pick the first domain from the runqueue*/ 11.716 + struct sedf_dom_info *runinf, *waitinf; 11.717 + 11.718 + if (!list_empty(runq)) { 11.719 + runinf = list_entry(runq->next,struct sedf_dom_info,list); 11.720 + ret.task = runinf->owner; 11.721 + if (!list_empty(waitq)) { 11.722 + waitinf = list_entry(waitq->next, 11.723 + struct sedf_dom_info,list); 11.724 + /*rerun scheduler, when scheduled domain reaches it's 11.725 + end of slice or the first domain from the waitqueue 11.726 + gets ready*/ 11.727 + ret.time = MIN(now + runinf->slice - runinf->cputime, 11.728 + PERIOD_BEGIN(waitinf)) - now; 11.729 + } 11.730 + else { 11.731 + ret.time = runinf->slice - runinf->cputime; 11.732 + } 11.733 + goto sched_done; 11.734 + } 11.735 + 11.736 + if (!list_empty(waitq)) { 11.737 + waitinf = list_entry(waitq->next,struct sedf_dom_info,list); 11.738 + /*we could not find any suitable domain 11.739 + => look for domains that are aware of extratime*/ 11.740 + #if (EXTRA > EXTRA_OFF) 11.741 + ret = sedf_do_extra_schedule(now, PERIOD_BEGIN(waitinf), 11.742 + extraq, cpu); 11.743 + #else 11.744 + ret.task = IDLETASK(cpu); 11.745 + ret.time = PERIOD_BEGIN(waitinf) - now; 11.746 + #endif 11.747 + } 11.748 + else { 11.749 + /*this could probably never happen, but one never knows...*/ 11.750 + /*it can... imagine a second CPU, which is pure scifi ATM, 11.751 + but one never knows ;)*/ 11.752 + ret.task = IDLETASK(cpu); 11.753 + ret.time = SECONDS(1); 11.754 + } 11.755 + 11.756 +sched_done: 11.757 + /*TODO: Do something USEFUL when this happens and find out, why it 11.758 + still can happen!!!*/ 11.759 + if (ret.time<0) { 11.760 + printk("Ouch! We are seriously BEHIND schedule! %lli\n", 11.761 + ret.time); 11.762 + ret.time = EXTRA_QUANTUM; 11.763 + } 11.764 + DOM_INFO(ret.task)->sched_start=now; 11.765 + return ret; 11.766 +} 11.767 + 11.768 +static void sedf_sleep(struct domain *d) { 11.769 + PRINT(2,"sedf_sleep was called, domain-id %i\n",d->id); 11.770 + if ( test_bit(DF_RUNNING, &d->flags) ) { 11.771 +#ifdef ADV_SCHED_HISTO 11.772 + adv_sched_hist_start(d->processor); 11.773 +#endif 11.774 + cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ); 11.775 + } 11.776 + else { 11.777 + if ( __task_on_queue(d) ) 11.778 + __del_from_queue(d); 11.779 + #if (EXTRA > EXTRA_OFF) 11.780 + if (extraq_on(d, EXTRA_UTIL_Q)) 11.781 + extraq_del(d, EXTRA_UTIL_Q); 11.782 + #endif 11.783 + #if (EXTRA == EXTRA_BLOCK_WEIGHT) 11.784 + if (extraq_on(d, EXTRA_PEN_Q)) 11.785 + extraq_del(d, EXTRA_PEN_Q); 11.786 + #endif 11.787 + } 11.788 +} 11.789 + 11.790 +/* This function wakes up a domain, i.e. moves them into the waitqueue 11.791 + * things to mention are: admission control is taking place nowhere at 11.792 + * the moment, so we can't be sure, whether it is safe to wake the domain 11.793 + * up at all. Anyway, even if it is safe (total cpu usage <=100%) there are 11.794 + * some considerations on when to allow the domain to wake up and have it's 11.795 + * first deadline... 11.796 + * I detected 3 cases, which could describe the possible behaviour of the 11.797 + * scheduler, 11.798 + * and I'll try to make them more clear: 11.799 + * 11.800 + * 1. Very conservative 11.801 + * -when a blocked domain unblocks, it is allowed to start execution at 11.802 + * the beginning of the next complete period 11.803 + * (D..deadline, R..running, B..blocking/sleeping, U..unblocking/waking up 11.804 + * 11.805 + * DRRB_____D__U_____DRRRRR___D________ ... 11.806 + * 11.807 + * -this causes the domain to miss a period (and a deadlline) 11.808 + * -doesn't disturb the schedule at all 11.809 + * -deadlines keep occuring isochronous 11.810 + * 11.811 + * 2. Conservative Part 1: Short Unblocking 11.812 + * -when a domain unblocks in the same period as it was blocked it 11.813 + * unblocks and may consume the rest of it's original time-slice minus 11.814 + * the time it was blocked 11.815 + * (assume period=9, slice=5) 11.816 + * 11.817 + * DRB_UR___DRRRRR___D... 11.818 + * 11.819 + * -this also doesn't disturb scheduling, but might lead to the fact, that 11.820 + * the domain can't finish it's workload in the period 11.821 + * -in addition to that the domain can be treated prioritised when 11.822 + * extratime is available 11.823 + * -addition: experiments hve shown that this may have a HUGE impact on 11.824 + * performance of other domains, becaus it can lead to excessive context 11.825 + * switches 11.826 + 11.827 + * Part2: Long Unblocking 11.828 + * Part 2a 11.829 + * -it is obvious that such accounting of block time, applied when 11.830 + * unblocking is happening in later periods, works fine aswell 11.831 + * -the domain is treated as if it would have been running since the start 11.832 + * of its new period 11.833 + * 11.834 + * DRB______D___UR___D... 11.835 + * 11.836 + * Part 2b 11.837 + * -if one needs the full slice in the next period, it is necessary to 11.838 + * treat the unblocking time as the start of the new period, i.e. move 11.839 + * the deadline further back (later) 11.840 + * -this doesn't disturb scheduling as well, because for EDF periods can 11.841 + * be treated as minimal inter-release times and scheduling stays 11.842 + * correct, when deadlines are kept relative to the time the process 11.843 + * unblocks 11.844 + * 11.845 + * DRB______D___URRRR___D...<prev [Thread] next> 11.846 + * (D) <- old deadline was here 11.847 + * -problem: deadlines don't occur isochronous anymore 11.848 + * Part 2c (Improved Atropos design) 11.849 + * -when a domain unblocks it is given a very short period (=latency hint) 11.850 + * and slice length scaled accordingly 11.851 + * -both rise again to the original value (e.g. get doubled every period) 11.852 + * 11.853 + * 3. Unconservative (i.e. incorrect) 11.854 + * -to boost the performance of I/O dependent domains it would be possible 11.855 + * to put the domain into the runnable queue immediately, and let it run 11.856 + * for the remainder of the slice of the current period 11.857 + * (or even worse: allocate a new full slice for the domain) 11.858 + * -either behaviour can lead to missed deadlines in other domains as 11.859 + * opposed to approaches 1,2a,2b 11.860 + */ 11.861 +static inline void unblock_short_vcons 11.862 +(struct sedf_dom_info* inf, s_time_t now) { 11.863 + inf->absdead += inf->period; 11.864 + inf->cputime = 0; 11.865 +} 11.866 + 11.867 +static inline void unblock_short_cons(struct sedf_dom_info* inf, s_time_t now) 11.868 +{ 11.869 + /*treat blocked time as consumed by the domain*/ 11.870 + inf->cputime += now - inf->absblock; 11.871 + if (inf->cputime + EXTRA_QUANTUM > inf->slice) { 11.872 + /*we don't have a reasonable amount of time in 11.873 + our slice left :( => start in next period!*/ 11.874 + unblock_short_vcons(inf, now); 11.875 + } 11.876 +#ifdef SEDF_STATS 11.877 + else 11.878 + inf->short_cont++; 11.879 +#endif 11.880 +} 11.881 +static inline void unblock_short_extra_support (struct sedf_dom_info* inf, 11.882 + s_time_t now) { 11.883 + /*this unblocking scheme tries to support the domain, by assigning it 11.884 + a priority in extratime distribution according to the loss of time 11.885 + in this slice due to blocking*/ 11.886 + s_time_t pen; 11.887 + 11.888 + /*no more realtime execution in this period!*/ 11.889 + inf->absdead += inf->period; 11.890 + if (likely(inf->absblock)) { 11.891 + //treat blocked time as consumed by the domain*/ 11.892 + /*inf->cputime += now - inf->absblock;*/ 11.893 + pen = (inf->slice - inf->cputime); 11.894 + if (pen < 0) pen = 0; 11.895 + /*accumulate all penalties over the periods*/ 11.896 + /*inf->short_block_lost_tot += pen;*/ 11.897 + /*set penalty to the current value*/ 11.898 + inf->short_block_lost_tot = pen; 11.899 + /*not sure which one is better.. but seems to work well...*/ 11.900 + 11.901 + if (inf->short_block_lost_tot) { 11.902 + inf->score[0] = (inf->period << 10) / 11.903 + inf->short_block_lost_tot; 11.904 +#ifdef SEDF_STATS 11.905 + inf->pen_extra_blocks++; 11.906 +#endif 11.907 + if (extraq_on(inf->owner, EXTRA_PEN_Q)) 11.908 + /*remove domain for possible resorting!*/ 11.909 + extraq_del(inf->owner, EXTRA_PEN_Q); 11.910 + else 11.911 + /*remember that we want to be on the penalty q 11.912 + so that we can continue when we (un-)block 11.913 + in penalty-extratime*/ 11.914 + inf->extra |= EXTRA_WANT_PEN_Q; 11.915 + 11.916 + /*(re-)add domain to the penalty extraq*/ 11.917 + extraq_add_sort_update(inf->owner, 11.918 + EXTRA_PEN_Q, 0); 11.919 + } 11.920 + } 11.921 + /*give it a fresh slice in the next period!*/ 11.922 + inf->cputime = 0; 11.923 +} 11.924 +static inline void unblock_long_vcons(struct sedf_dom_info* inf, s_time_t now) 11.925 +{ 11.926 + /* align to next future period */ 11.927 + inf->absdead += ((now - inf->absdead) / inf->period + 1) 11.928 + * inf->period; 11.929 + inf->cputime = 0; 11.930 +} 11.931 + 11.932 +static inline void unblock_long_cons_a (struct sedf_dom_info* inf, 11.933 + s_time_t now) { 11.934 + /*treat the time the domain was blocked in the 11.935 + CURRENT period as consumed by the domain*/ 11.936 + inf->cputime = (now - inf->absdead) % inf->period; 11.937 + if (inf->cputime + EXTRA_QUANTUM > inf->slice) { 11.938 + /*we don't have a reasonable amount of time in our slice 11.939 + left :( => start in next period!*/ 11.940 + unblock_long_vcons(inf, now); 11.941 + } 11.942 +} 11.943 +static inline void unblock_long_cons_b(struct sedf_dom_info* inf,s_time_t now) { 11.944 + /*Conservative 2b*/ 11.945 + /*Treat the unblocking time as a start of a new period */ 11.946 + inf->absdead = now + inf->period; 11.947 + inf->cputime = 0; 11.948 +} 11.949 +static inline void unblock_long_cons_c(struct sedf_dom_info* inf,s_time_t now) { 11.950 + if (likely(inf->latency)) { 11.951 + /*scale the slice and period accordingly to the latency hint*/ 11.952 + /*reduce period temporarily to the latency hint*/ 11.953 + inf->period = inf->latency; 11.954 + /*this results in max. 4s slice/period length*/ 11.955 + ASSERT((inf->period < ULONG_MAX) 11.956 + && (inf->slice_orig < ULONG_MAX)); 11.957 + /*scale slice accordingly, so that utilisation stays the same*/ 11.958 + inf->slice = (inf->period * inf->slice_orig) 11.959 + / inf->period_orig; 11.960 + inf->absdead = now + inf->period; 11.961 + inf->cputime = 0; 11.962 + } 11.963 + else { 11.964 + /*we don't have a latency hint.. use some other technique*/ 11.965 + unblock_long_cons_b(inf, now); 11.966 + } 11.967 +} 11.968 +/*a new idea of dealing with short blocks: burst period scaling*/ 11.969 +static inline void unblock_short_burst(struct sedf_dom_info* inf, s_time_t now) 11.970 +{ 11.971 + /*treat blocked time as consumed by the domain*/ 11.972 + inf->cputime += now - inf->absblock; 11.973 + 11.974 + if (inf->cputime + EXTRA_QUANTUM <= inf->slice) { 11.975 + /*if we can still use some time in the current slice 11.976 + then use it!*/ 11.977 +#ifdef SEDF_STATS 11.978 + /*we let the domain run in the current period*/ 11.979 + inf->short_cont++; 11.980 +#endif 11.981 + } 11.982 + else { 11.983 + /*we don't have a reasonable amount of time in 11.984 + our slice left => switch to burst mode*/ 11.985 + if (likely(inf->absunblock)) { 11.986 + /*set the period-length to the current blocking 11.987 + interval, possible enhancements: average over last 11.988 + blocking intervals, user-specified minimum,...*/ 11.989 + inf->period = now - inf->absunblock; 11.990 + /*check for overflow on multiplication*/ 11.991 + ASSERT((inf->period < ULONG_MAX) 11.992 + && (inf->slice_orig < ULONG_MAX)); 11.993 + /*scale slice accordingly, so that utilisation 11.994 + stays the same*/ 11.995 + inf->slice = (inf->period * inf->slice_orig) 11.996 + / inf->period_orig; 11.997 + /*set new (shorter) deadline*/ 11.998 + inf->absdead += inf->period; 11.999 + } 11.1000 + else { 11.1001 + /*in case we haven't unblocked before 11.1002 + start in next period!*/ 11.1003 + inf->cputime=0; 11.1004 + inf->absdead += inf->period; 11.1005 + } 11.1006 + } 11.1007 + inf->absunblock = now; 11.1008 +} 11.1009 +static inline void unblock_long_burst(struct sedf_dom_info* inf,s_time_t now) { 11.1010 + if (unlikely(inf->latency && (inf->period > inf->latency))) { 11.1011 + /*scale the slice and period accordingly to the latency hint*/ 11.1012 + inf->period = inf->latency; 11.1013 + /*check for overflows on multiplication*/ 11.1014 + ASSERT((inf->period < ULONG_MAX) 11.1015 + && (inf->slice_orig < ULONG_MAX)); 11.1016 + /*scale slice accordingly, so that utilisation stays the same*/ 11.1017 + inf->slice = (inf->period * inf->slice_orig) 11.1018 + / inf->period_orig; 11.1019 + inf->absdead = now + inf->period; 11.1020 + inf->cputime = 0; 11.1021 + } 11.1022 + else { 11.1023 + /*we don't have a latency hint.. or we are currently in 11.1024 + "burst mode": use some other technique 11.1025 + NB: this should be in fact the normal way of operation, 11.1026 + when we are in sync with the device!*/ 11.1027 + unblock_long_cons_b(inf, now); 11.1028 + } 11.1029 + inf->absunblock = now; 11.1030 +} 11.1031 + 11.1032 +#define DOMAIN_EDF 1 11.1033 +#define DOMAIN_EXTRA_PEN 2 11.1034 +#define DOMAIN_EXTRA_UTIL 3 11.1035 +#define DOMAIN_IDLE 4 11.1036 +static inline int get_run_type(struct domain* d) { 11.1037 + struct sedf_dom_info* inf = DOM_INFO(d); 11.1038 + if (is_idle_task(d)) 11.1039 + return DOMAIN_IDLE; 11.1040 + if (inf->extra & EXTRA_RUN_PEN) 11.1041 + return DOMAIN_EXTRA_PEN; 11.1042 + if (inf->extra & EXTRA_RUN_UTIL) 11.1043 + return DOMAIN_EXTRA_UTIL; 11.1044 + return DOMAIN_EDF; 11.1045 +} 11.1046 +/*Compares two domains in the relation of whether the one is allowed to 11.1047 + interrupt the others execution. 11.1048 + It returns true (!=0) if a switch to the other domain is good. 11.1049 + Current Priority scheme is as follows: 11.1050 + EDF > L0 (penalty based) extra-time > 11.1051 + L1 (utilization) extra-time > idle-domain 11.1052 + In the same class priorities are assigned as following: 11.1053 + EDF: early deadline > late deadline 11.1054 + L0 extra-time: lower score > higher score*/ 11.1055 +static inline int should_switch(struct domain* cur, struct domain* other, 11.1056 + s_time_t now) { 11.1057 + struct sedf_dom_info *cur_inf, *other_inf; 11.1058 + cur_inf = DOM_INFO(cur); 11.1059 + other_inf = DOM_INFO(other); 11.1060 + 11.1061 + /*check whether we need to make an earlier sched-decision*/ 11.1062 + if ((PERIOD_BEGIN(other_inf) < 11.1063 + schedule_data[other->processor].s_timer.expires)) 11.1064 + return 1; 11.1065 + /*no timing-based switches need to be taken into account here*/ 11.1066 + switch (get_run_type(cur)) { 11.1067 + case DOMAIN_EDF: 11.1068 + /* do not interrupt a running EDF domain */ 11.1069 + return 0; 11.1070 + case DOMAIN_EXTRA_PEN: 11.1071 + /*check whether we also want 11.1072 + the L0 ex-q with lower score*/ 11.1073 + if ((other_inf->extra & EXTRA_WANT_PEN_Q) 11.1074 + && (other_inf->score[EXTRA_PEN_Q] < 11.1075 + cur_inf->score[EXTRA_PEN_Q])) 11.1076 + return 1; 11.1077 + else return 0; 11.1078 + case DOMAIN_EXTRA_UTIL: 11.1079 + /*check whether we want the L0 extraq, don't 11.1080 + switch if both domains want L1 extraq */ 11.1081 + if (other_inf->extra & EXTRA_WANT_PEN_Q) 11.1082 + return 1; 11.1083 + else return 0; 11.1084 + case DOMAIN_IDLE: 11.1085 + return 1; 11.1086 + } 11.1087 +} 11.1088 +void sedf_wake(struct domain *d) { 11.1089 + s_time_t now = NOW(); 11.1090 + struct sedf_dom_info* inf = DOM_INFO(d); 11.1091 + 11.1092 + PRINT(3,"sedf_wake was called, domain-id %i\n",d->id); 11.1093 + 11.1094 + if (unlikely(is_idle_task(d))) 11.1095 + return; 11.1096 + 11.1097 + if ( unlikely(__task_on_queue(d)) ) { 11.1098 + PRINT(3,"\tdomain %i is already in some queue\n",d->id); 11.1099 + return; 11.1100 + } 11.1101 + if ( unlikely(extraq_on(d,EXTRA_UTIL_Q) || extraq_on(d,EXTRA_PEN_Q)) ) { 11.1102 + PRINT(3,"\tdomain %i is already in the extraQ\n",d->id); 11.1103 + } 11.1104 + if (unlikely(inf->absdead == 0)) 11.1105 + /*initial setup of the deadline*/ 11.1106 + inf->absdead = now + inf->slice; 11.1107 + 11.1108 + PRINT(3,"waking up domain %i (deadl= %llu period= %llu "\ 11.1109 + "now= %llu)\n",d->id,inf->absdead,inf->period,now); 11.1110 +#ifdef SEDF_STATS 11.1111 + inf->block_tot++; 11.1112 +#endif 11.1113 + if (unlikely(now< PERIOD_BEGIN(inf))) { 11.1114 + PRINT(4,"extratime unblock\n"); 11.1115 + /*this might happen, imagine unblocking in extra-time!*/ 11.1116 + #if (EXTRA == EXTRA_BLOCK_WEIGHT) 11.1117 + if (inf->extra & EXTRA_WANT_PEN_Q) { 11.1118 + /*we have a domain that wants compensation 11.1119 + for block penalty and did just block in 11.1120 + its compensation time. Give it another 11.1121 + chance!*/ 11.1122 + extraq_add_sort_update(d, EXTRA_PEN_Q, 0); 11.1123 + } 11.1124 + #endif 11.1125 + if (inf->extra & EXTRA_AWARE) 11.1126 + #if (EXTRA == EXTRA_ROUNDR) 11.1127 + extraq_add_tail(d,EXTRA_UTIL_Q); 11.1128 + #elif (EXTRA == EXTRA_SLICE_WEIGHT \ 11.1129 + || EXTRA == EXTRA_BLOCK_WEIGHT) 11.1130 + /*put in on the weighted extraq, 11.1131 + without updating any scores*/ 11.1132 + extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); 11.1133 + #else 11.1134 + ; 11.1135 + #endif 11.1136 + /*else*/ 11.1137 + /*This is very very unlikely, ie. might even be an error?!*/ 11.1138 + } 11.1139 + else { 11.1140 + if (now < inf->absdead) { 11.1141 + PRINT(4,"short unblocking\n"); 11.1142 + /*short blocking*/ 11.1143 +#ifdef SEDF_STATS 11.1144 + inf->short_block_tot++; 11.1145 +#endif 11.1146 + #if (UNBLOCK <= UNBLOCK_ATROPOS) 11.1147 + unblock_short_vcons(inf, now); 11.1148 + #elif (UNBLOCK == UNBLOCK_SHORT_RESUME) 11.1149 + unblock_short_cons(inf, now); 11.1150 + #elif (UNBLOCK == UNBLOCK_BURST) 11.1151 + unblock_short_burst(inf, now); 11.1152 + #elif (UNBLOCK == UNBLOCK_EXTRA_SUPPORT) 11.1153 + unblock_short_extra_support(inf, now); 11.1154 + #endif 11.1155 + 11.1156 + if (inf->extra & EXTRA_AWARE) 11.1157 + #if (EXTRA == EXTRA_OFF) 11.1158 + ; 11.1159 + #elif (EXTRA == EXTRA_ROUNDR) 11.1160 + /*Favour domains which got short unblocked*/ 11.1161 + extraq_add_head(d, EXTRA_UTIL_Q); 11.1162 + #elif (EXTRA == EXTRA_SLICE_WEIGHT \ 11.1163 + || EXTRA == EXTRA_BLOCK_WEIGHT) 11.1164 + extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); 11.1165 + #endif 11.1166 + } 11.1167 + else { 11.1168 + PRINT(4,"long unblocking\n"); 11.1169 + /*long unblocking*/ 11.1170 +#ifdef SEDF_STATS 11.1171 + inf->long_block_tot++; 11.1172 +#endif 11.1173 + #if (UNBLOCK == UNBLOCK_ISOCHRONOUS_EDF) 11.1174 + unblock_long_vcons(inf, now); 11.1175 + #elif (UNBLOCK == UNBLOCK_EDF \ 11.1176 + || UNBLOCK == UNBLOCK_EXTRA_SUPPORT) 11.1177 + unblock_long_cons_b(inf, now); 11.1178 + #elif (UNBLOCK == UNBLOCK_ATROPOS) 11.1179 + unblock_long_cons_c(inf, now); 11.1180 + #elif (UNBLOCK == UNBLOCK_SHORT_RESUME) 11.1181 + unblock_long_cons_b(inf, now); 11.1182 + /*unblock_short_cons_c(inf, now);*/ 11.1183 + #elif (UNBLOCK == UNBLOCK_BURST) 11.1184 + unblock_long_burst(inf, now); 11.1185 + #endif 11.1186 + 11.1187 + if (inf->extra & EXTRA_AWARE) { 11.1188 + #if (EXTRA == EXTRA_OFF) 11.1189 + ; 11.1190 + #elif (EXTRA == EXTRA_ROUNDR) 11.1191 + extraq_add_head(d, EXTRA_UTIL_Q); 11.1192 + #elif (EXTRA == EXTRA_SLICE_WEIGHT \ 11.1193 + || EXTRA == EXTRA_BLOCK_WEIGHT) 11.1194 + extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); 11.1195 + #endif 11.1196 + } 11.1197 + 11.1198 + } 11.1199 + } 11.1200 + PRINT(3,"woke up domain %i (deadl= %llu period= %llu "\ 11.1201 + "now= %llu)\n",d->id,inf->absdead,inf->period,now); 11.1202 + __add_to_waitqueue_sort(d); 11.1203 + PRINT(3,"added to waitq\n"); 11.1204 + 11.1205 +#ifdef SEDF_STATS 11.1206 + /*do some statistics here...*/ 11.1207 + if (inf->absblock != 0) { 11.1208 + inf->block_time_tot += now - inf->absblock; 11.1209 + inf->penalty_time_tot += 11.1210 + PERIOD_BEGIN(inf) + inf->cputime - inf->absblock; 11.1211 + } 11.1212 +#endif 11.1213 + /*sanity check: make sure each extra-aware domain IS on the util-q!*/ 11.1214 + /*if (inf->extra & EXTRA_AWARE) { 11.1215 + if (!extraq_on(d, EXTRA_UTIL_Q)) 11.1216 + printf("sedf_wake: domain %i is extra-aware, "\ 11.1217 + "but NOT on L1 extraq!\n",d->id); 11.1218 + }*/ 11.1219 + 11.1220 + /*check whether the awakened task needs to invoke the do_schedule 11.1221 + routine. Try to avoid unnecessary runs but: 11.1222 + Save approximation: Always switch to scheduler!*/ 11.1223 + if (should_switch(schedule_data[d->processor].curr, d, now)){ 11.1224 +#ifdef ADV_SCHED_HISTO 11.1225 + adv_sched_hist_start(d->processor); 11.1226 +#endif 11.1227 + cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ); 11.1228 + } 11.1229 +} 11.1230 + 11.1231 +/*Print a lot of use-{full, less} information about a domains in the system*/ 11.1232 +static void sedf_dump_domain(struct domain *d) { 11.1233 + printk("%u has=%c ", d->id, 11.1234 + test_bit(DF_RUNNING, &d->flags) ? 'T':'F'); 11.1235 + printk("p=%llu sl=%llu ddl=%llu w=%hu c=%llu sc=%i xtr(%s)=%llu", 11.1236 + DOM_INFO(d)->period, DOM_INFO(d)->slice, DOM_INFO(d)->absdead, 11.1237 + DOM_INFO(d)->weight, d->cpu_time, DOM_INFO(d)->score[EXTRA_UTIL_Q], 11.1238 + (DOM_INFO(d)->extra & EXTRA_AWARE) ? "yes" : "no", 11.1239 + DOM_INFO(d)->extra_time_tot); 11.1240 + if (d->cpu_time !=0) 11.1241 + printf(" (%lu%)", (DOM_INFO(d)->extra_time_tot * 100) 11.1242 + / d->cpu_time); 11.1243 +#ifdef SEDF_STATS 11.1244 + if (DOM_INFO(d)->block_time_tot!=0) 11.1245 + printf(" pen=%lu%", (DOM_INFO(d)->penalty_time_tot * 100) / 11.1246 + DOM_INFO(d)->block_time_tot); 11.1247 + if (DOM_INFO(d)->block_tot!=0) 11.1248 + printf("\n blks=%lu sh=%lu (%lu%) (shc=%lu (%lu%) shex=%i "\ 11.1249 + "shexsl=%i) l=%lu (%lu%) avg: b=%llu p=%llu", 11.1250 + DOM_INFO(d)->block_tot, DOM_INFO(d)->short_block_tot, 11.1251 + (DOM_INFO(d)->short_block_tot * 100) 11.1252 + / DOM_INFO(d)->block_tot, DOM_INFO(d)->short_cont, 11.1253 + (DOM_INFO(d)->short_cont * 100) / DOM_INFO(d)->block_tot, 11.1254 + DOM_INFO(d)->pen_extra_blocks, 11.1255 + DOM_INFO(d)->pen_extra_slices, 11.1256 + DOM_INFO(d)->long_block_tot, 11.1257 + (DOM_INFO(d)->long_block_tot * 100) / DOM_INFO(d)->block_tot, 11.1258 + (DOM_INFO(d)->block_time_tot) / DOM_INFO(d)->block_tot, 11.1259 + (DOM_INFO(d)->penalty_time_tot) / DOM_INFO(d)->block_tot); 11.1260 +#endif 11.1261 + printf("\n"); 11.1262 +} 11.1263 + 11.1264 +/*dumps all domains on hte specified cpu*/ 11.1265 +static void sedf_dump_cpu_state(int i) 11.1266 +{ 11.1267 + struct list_head *list, *queue, *tmp; 11.1268 + int loop = 0; 11.1269 + struct sedf_dom_info *d_inf; 11.1270 + struct domain* d; 11.1271 + 11.1272 + printk("now=%llu\n",NOW()); 11.1273 + queue = RUNQ(i); 11.1274 + printk("RUNQ rq %lx n: %lx, p: %lx\n", (unsigned long)queue, 11.1275 + (unsigned long) queue->next, (unsigned long) queue->prev); 11.1276 + list_for_each_safe ( list, tmp, queue ) { 11.1277 + printk("%3d: ",loop++); 11.1278 + d_inf = list_entry(list, struct sedf_dom_info, list); 11.1279 + sedf_dump_domain(d_inf->owner); 11.1280 + } 11.1281 + 11.1282 + queue = WAITQ(i); loop = 0; 11.1283 + printk("\nWAITQ rq %lx n: %lx, p: %lx\n", (unsigned long)queue, 11.1284 + (unsigned long) queue->next, (unsigned long) queue->prev); 11.1285 + list_for_each_safe ( list, tmp, queue ) { 11.1286 + printk("%3d: ",loop++); 11.1287 + d_inf = list_entry(list, struct sedf_dom_info, list); 11.1288 + sedf_dump_domain(d_inf->owner); 11.1289 + } 11.1290 + 11.1291 + queue = EXTRAQ(i,EXTRA_PEN_Q); loop = 0; 11.1292 + printk("\nEXTRAQ (penalty) rq %lx n: %lx, p: %lx\n", 11.1293 + (unsigned long)queue, (unsigned long) queue->next, 11.1294 + (unsigned long) queue->prev); 11.1295 + list_for_each_safe ( list, tmp, queue ) { 11.1296 + d_inf = list_entry(list, struct sedf_dom_info, 11.1297 + extralist[EXTRA_PEN_Q]); 11.1298 + printk("%3d: ",loop++); 11.1299 + sedf_dump_domain(d_inf->owner); 11.1300 + } 11.1301 + 11.1302 + queue = EXTRAQ(i,EXTRA_UTIL_Q); loop = 0; 11.1303 + printk("\nEXTRAQ (utilization) rq %lx n: %lx, p: %lx\n", 11.1304 + (unsigned long)queue, (unsigned long) queue->next, 11.1305 + (unsigned long) queue->prev); 11.1306 + list_for_each_safe ( list, tmp, queue ) { 11.1307 + d_inf = list_entry(list, struct sedf_dom_info, 11.1308 + extralist[EXTRA_UTIL_Q]); 11.1309 + printk("%3d: ",loop++); 11.1310 + sedf_dump_domain(d_inf->owner); 11.1311 + } 11.1312 + 11.1313 + loop = 0; 11.1314 + printk("\nnot on Q\n"); 11.1315 + for_each_domain(d) { 11.1316 + if (!__task_on_queue(d) && (d->processor == i)) { 11.1317 + printk("%3d: ",loop++); 11.1318 + sedf_dump_domain(d); 11.1319 + } 11.1320 + } 11.1321 +} 11.1322 +/*Adjusts periods and slices of the domains accordingly to their weights*/ 11.1323 +static inline int sedf_adjust_weights(struct domain *p, 11.1324 +struct sched_adjdom_cmd *cmd) { 11.1325 + int sumw[NR_CPUS]; 11.1326 + s_time_t sumt[NR_CPUS]; 11.1327 + int cpu; 11.1328 + 11.1329 + for (cpu=0; cpu < NR_CPUS; cpu++) { 11.1330 + sumw[cpu] = 0; 11.1331 + sumt[cpu] = 0; 11.1332 + } 11.1333 + /*sum up all weights*/ 11.1334 + for_each_domain(p) { 11.1335 + if (DOM_INFO(p)->weight) 11.1336 + sumw[p->processor] += DOM_INFO(p)->weight; 11.1337 + else { 11.1338 + /*don't modify domains who don't have a weight, but sum 11.1339 + up the time they need, projected to a WEIGHT_PERIOD, 11.1340 + so that this time is not given to the weight-driven 11.1341 + domains*/ 11.1342 + /*check for overflows*/ 11.1343 + ASSERT((WEIGHT_PERIOD < ULONG_MAX) 11.1344 + && (DOM_INFO(p)->slice_orig < ULONG_MAX)); 11.1345 + sumt[p->processor] += (WEIGHT_PERIOD * 11.1346 + DOM_INFO(p)->slice_orig) / DOM_INFO(p)->period_orig; 11.1347 + } 11.1348 + } 11.1349 + /*adjust all slices (and periods) to the new weight*/ 11.1350 + for_each_domain(p) { 11.1351 + if (DOM_INFO(p)->weight) { 11.1352 + DOM_INFO(p)->period_orig = 11.1353 + DOM_INFO(p)->period = WEIGHT_PERIOD; 11.1354 + DOM_INFO(p)->slice_orig = 11.1355 + DOM_INFO(p)->slice = (DOM_INFO(p)->weight * 11.1356 + (WEIGHT_PERIOD -WEIGHT_SAFETY - 11.1357 + sumt[p->processor])) / sumw[p->processor]; 11.1358 + } 11.1359 + } 11.1360 + return 0; 11.1361 +} 11.1362 + 11.1363 +/* set or fetch domain scheduling parameters */ 11.1364 +static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { 11.1365 + PRINT(2,"sedf_adjdom was called, domain-id %i new period %llu "\ 11.1366 + "new slice %llu\nlatency %llu extra:%s\n", 11.1367 + p->id, cmd->u.sedf.period, cmd->u.sedf.slice, 11.1368 + cmd->u.sedf.latency, (cmd->u.sedf.extratime)?"yes":"no"); 11.1369 + if ( cmd->direction == SCHED_INFO_PUT ) 11.1370 + { 11.1371 + /*check for sane parameters*/ 11.1372 + if (!cmd->u.sedf.period && !cmd->u.sedf.weight) 11.1373 + return -EINVAL; 11.1374 + /*weight driven domains*/ 11.1375 + if (cmd->u.sedf.weight) { 11.1376 + DOM_INFO(p)->weight = cmd->u.sedf.weight; 11.1377 + } 11.1378 + else { 11.1379 + /*time driven domains*/ 11.1380 + DOM_INFO(p)->weight = 0; 11.1381 + /* sanity checking! */ 11.1382 + if(cmd->u.sedf.slice > cmd->u.sedf.period ) 11.1383 + return -EINVAL; 11.1384 + DOM_INFO(p)->period_orig = 11.1385 + DOM_INFO(p)->period = cmd->u.sedf.period; 11.1386 + DOM_INFO(p)->slice_orig = 11.1387 + DOM_INFO(p)->slice = cmd->u.sedf.slice; 11.1388 + } 11.1389 + if (sedf_adjust_weights(p,cmd)) 11.1390 + return -EINVAL; 11.1391 + DOM_INFO(p)->extra = (DOM_INFO(p)-> extra & ~EXTRA_AWARE) 11.1392 + | (cmd->u.sedf.extratime & EXTRA_AWARE); 11.1393 + DOM_INFO(p)->latency = cmd->u.sedf.latency; 11.1394 + extraq_check(p); 11.1395 + } 11.1396 + else if ( cmd->direction == SCHED_INFO_GET ) 11.1397 + { 11.1398 + cmd->u.sedf.period = DOM_INFO(p)->period; 11.1399 + cmd->u.sedf.slice = DOM_INFO(p)->slice; 11.1400 + cmd->u.sedf.extratime = DOM_INFO(p)->extra & EXTRA_AWARE; 11.1401 + cmd->u.sedf.latency = DOM_INFO(p)->latency; 11.1402 + cmd->u.sedf.weight = DOM_INFO(p)->weight; 11.1403 + } 11.1404 + PRINT(2,"sedf_adjdom_finished\n"); 11.1405 + return 0; 11.1406 +} 11.1407 + 11.1408 +struct scheduler sched_sedf_def = { 11.1409 + .name = "Simple EDF Scheduler", 11.1410 + .opt_name = "sedf", 11.1411 + .sched_id = SCHED_SEDF, 11.1412 + 11.1413 + .init_idle_task = sedf_init_idle_task, 11.1414 + .alloc_task = sedf_alloc_task, 11.1415 + .add_task = sedf_add_task, 11.1416 + .free_task = sedf_free_task, 11.1417 + .init_scheduler = sedf_init_scheduler, 11.1418 + .do_schedule = sedf_do_schedule, 11.1419 + .dump_cpu_state = sedf_dump_cpu_state, 11.1420 + .sleep = sedf_sleep, 11.1421 + .wake = sedf_wake, 11.1422 + .adjdom = sedf_adjdom, 11.1423 +};
12.1 --- a/xen/common/schedule.c Wed Apr 20 21:22:46 2005 +0000 12.2 +++ b/xen/common/schedule.c Thu Apr 21 01:42:29 2005 +0000 12.3 @@ -40,6 +40,17 @@ 12.4 static char opt_sched[10] = "bvt"; 12.5 string_param("sched", opt_sched); 12.6 12.7 +/*#define WAKE_HISTO*/ 12.8 +/*#define BLOCKTIME_HISTO*/ 12.9 +/*#define ADV_SCHED_HISTO*/ 12.10 +//#include <xen/adv_sched_hist.h> 12.11 + 12.12 +#if defined(WAKE_HISTO) 12.13 +#define BUCKETS 31 12.14 +#elif defined(BLOCKTIME_HISTO) 12.15 +#define BUCKETS 200 12.16 +#endif 12.17 + 12.18 #define TIME_SLOP (s32)MICROSECS(50) /* allow time to slip a bit */ 12.19 12.20 /* Various timer handlers. */ 12.21 @@ -51,8 +62,10 @@ static void dom_timer_fn(unsigned long d 12.22 struct schedule_data schedule_data[NR_CPUS]; 12.23 12.24 extern struct scheduler sched_bvt_def; 12.25 +extern struct scheduler sched_sedf_def; 12.26 static struct scheduler *schedulers[] = { 12.27 &sched_bvt_def, 12.28 + &sched_sedf_def, 12.29 NULL 12.30 }; 12.31 12.32 @@ -223,6 +236,10 @@ long do_block(void) 12.33 { 12.34 struct exec_domain *ed = current; 12.35 12.36 +#ifdef ADV_SCHED_HISTO 12.37 + adv_sched_hist_start(current->processor); 12.38 +#endif 12.39 + 12.40 ed->vcpu_info->evtchn_upcall_mask = 0; 12.41 set_bit(EDF_BLOCKED, &ed->ed_flags); 12.42 12.43 @@ -241,6 +258,10 @@ long do_block(void) 12.44 /* Voluntarily yield the processor for this allocation. */ 12.45 static long do_yield(void) 12.46 { 12.47 +#ifdef ADV_SCHED_HISTO 12.48 + adv_sched_hist_start(current->processor); 12.49 +#endif 12.50 + 12.51 TRACE_2D(TRC_SCHED_YIELD, current->domain->id, current->eid); 12.52 __enter_scheduler(); 12.53 return 0; 12.54 @@ -320,7 +341,7 @@ long sched_adjdom(struct sched_adjdom_cm 12.55 12.56 if ( cmd->sched_id != ops.sched_id ) 12.57 return -EINVAL; 12.58 - 12.59 + 12.60 if ( cmd->direction != SCHED_INFO_PUT && cmd->direction != SCHED_INFO_GET ) 12.61 return -EINVAL; 12.62 12.63 @@ -353,8 +374,14 @@ static void __enter_scheduler(void) 12.64 perfc_incrc(sched_run); 12.65 12.66 spin_lock_irq(&schedule_data[cpu].schedule_lock); 12.67 - 12.68 + 12.69 +#ifdef ADV_SCHED_HISTO 12.70 + adv_sched_hist_from_stop(cpu); 12.71 +#endif 12.72 now = NOW(); 12.73 +#ifdef ADV_SCHED_HISTO 12.74 + adv_sched_hist_start(cpu); 12.75 +#endif 12.76 12.77 rem_ac_timer(&schedule_data[cpu].s_timer); 12.78 12.79 @@ -381,9 +408,12 @@ static void __enter_scheduler(void) 12.80 12.81 spin_unlock_irq(&schedule_data[cpu].schedule_lock); 12.82 12.83 - if ( unlikely(prev == next) ) 12.84 + if ( unlikely(prev == next) ) { 12.85 +#ifdef ADV_SCHED_HISTO 12.86 + adv_sched_hist_to_stop(cpu); 12.87 +#endif 12.88 return; 12.89 - 12.90 + } 12.91 perfc_incrc(sched_ctx); 12.92 12.93 #if defined(WAKE_HISTO) 12.94 @@ -418,6 +448,10 @@ static void __enter_scheduler(void) 12.95 prev->domain->id, prev->eid, 12.96 next->domain->id, next->eid); 12.97 12.98 +#ifdef ADV_SCHED_HISTO 12.99 + adv_sched_hist_to_stop(cpu); 12.100 +#endif 12.101 + 12.102 context_switch(prev, next); 12.103 } 12.104 12.105 @@ -439,6 +473,10 @@ int idle_cpu(int cpu) 12.106 /* The scheduler timer: force a run through the scheduler */ 12.107 static void s_timer_fn(unsigned long unused) 12.108 { 12.109 +#ifdef ADV_SCHED_HISTO 12.110 + adv_sched_hist_start(current->processor); 12.111 +#endif 12.112 + 12.113 raise_softirq(SCHEDULE_SOFTIRQ); 12.114 perfc_incrc(sched_irq); 12.115 } 12.116 @@ -582,9 +620,66 @@ void reset_sched_histo(unsigned char key 12.117 schedule_data[j].hist[i] = 0; 12.118 } 12.119 #else 12.120 +#if defined(ADV_SCHED_HISTO) 12.121 +void print_sched_histo(unsigned char key) 12.122 +{ 12.123 + int i, j, k,t; 12.124 + printf("Hello!\n"); 12.125 + for ( k = 0; k < smp_num_cpus; k++ ) 12.126 + { 12.127 + j = 0; 12.128 + t = 0; 12.129 + printf ("CPU[%02d]: scheduler latency histogram FROM (ms:[count])\n", k); 12.130 + for ( i = 0; i < BUCKETS; i++ ) 12.131 + { 12.132 + //if ( schedule_data[k].hist[i] != 0 ) 12.133 + { 12.134 + t += schedule_data[k].from_hist[i]; 12.135 + if ( i < BUCKETS-1 ) 12.136 + printk("%3d:[%7u] ", i, schedule_data[k].from_hist[i]); 12.137 + else 12.138 + printk(" >:[%7u] ", schedule_data[k].from_hist[i]); 12.139 + //if ( !(++j % 5) ) 12.140 + printk("\n"); 12.141 + } 12.142 + } 12.143 + printk("\nTotal: %i\n",t); 12.144 + } 12.145 + for ( k = 0; k < smp_num_cpus; k++ ) 12.146 + { 12.147 + j = 0; t = 0; 12.148 + printf ("CPU[%02d]: scheduler latency histogram TO (ms:[count])\n", k); 12.149 + for ( i = 0; i < BUCKETS; i++ ) 12.150 + { 12.151 + //if ( schedule_data[k].hist[i] != 0 ) 12.152 + { 12.153 + t += schedule_data[k].from_hist[i]; 12.154 + if ( i < BUCKETS-1 ) 12.155 + printk("%3d:[%7u] ", i, schedule_data[k].to_hist[i]); 12.156 + else 12.157 + printk(" >:[%7u] ", schedule_data[k].to_hist[i]); 12.158 + //if ( !(++j % 5) ) 12.159 + printk("\n"); 12.160 + } 12.161 + } 12.162 + printk("\nTotal: %i\n",t); 12.163 + } 12.164 + 12.165 +} 12.166 +void reset_sched_histo(unsigned char key) 12.167 +{ 12.168 + int i, j; 12.169 + for ( j = 0; j < smp_num_cpus; j++ ) { 12.170 + for ( i=0; i < BUCKETS; i++ ) 12.171 + schedule_data[j].to_hist[i] = schedule_data[j].from_hist[i] = 0; 12.172 + schedule_data[j].save_tsc = 0; 12.173 + } 12.174 +} 12.175 +#else 12.176 void print_sched_histo(unsigned char key) { } 12.177 void reset_sched_histo(unsigned char key) { } 12.178 #endif 12.179 +#endif 12.180 12.181 /* 12.182 * Local variables:
13.1 --- a/xen/include/public/sched_ctl.h Wed Apr 20 21:22:46 2005 +0000 13.2 +++ b/xen/include/public/sched_ctl.h Thu Apr 21 01:42:29 2005 +0000 13.3 @@ -9,6 +9,7 @@ 13.4 13.5 /* Scheduler types. */ 13.6 #define SCHED_BVT 0 13.7 +#define SCHED_SEDF 4 13.8 13.9 /* Set or get info? */ 13.10 #define SCHED_INFO_PUT 0 13.11 @@ -31,18 +32,31 @@ struct sched_ctl_cmd 13.12 13.13 struct sched_adjdom_cmd 13.14 { 13.15 - u32 sched_id; 13.16 - u32 direction; 13.17 - domid_t domain; 13.18 - union { 13.19 - struct bvt_adjdom { 13.20 - u32 mcu_adv; /* mcu advance: inverse of weight */ 13.21 - u32 warpback; /* warp? */ 13.22 - s32 warpvalue; /* warp value */ 13.23 - long long warpl; /* warp limit */ 13.24 - long long warpu; /* unwarp time requirement */ 13.25 - } bvt; 13.26 - } u; 13.27 -}; 13.28 + u32 sched_id; /* 0 */ 13.29 + u32 direction; /* 4 */ 13.30 + domid_t domain; /* 8 */ 13.31 + u16 __pad0; 13.32 + u32 __pad1; 13.33 + union { /* 16 */ 13.34 + struct bvt_adjdom 13.35 + { 13.36 + u32 mcu_adv; /* 16: mcu advance: inverse of weight */ 13.37 + u32 warpback; /* 20: warp? */ 13.38 + s32 warpvalue; /* 24: warp value */ 13.39 + long long warpl; /* 32: warp limit */ 13.40 + long long warpu; /* 40: unwarp time requirement */ 13.41 + } PACKED bvt; 13.42 + 13.43 + struct sedf_adjdom 13.44 + { 13.45 + u64 period; /* 16 */ 13.46 + u64 slice; /* 24 */ 13.47 + u64 latency; /* 32 */ 13.48 + u16 extratime; /* 36 */ 13.49 + u16 weight; /* 38 */ 13.50 + } PACKED sedf; 13.51 + 13.52 + } PACKED u; 13.53 +} PACKED; /* 40 bytes */ 13.54 13.55 #endif /* __XEN_PUBLIC_SCHED_CTL_H__ */
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/xen/include/xen/adv_sched_hist.h Thu Apr 21 01:42:29 2005 +0000 14.3 @@ -0,0 +1,40 @@ 14.4 +/* Some functions to suport advanced scheduler histograms 14.5 + Author: Stephan.Diestelhorst@cl.cam.ac.uk */ 14.6 +//#include <xen/sched.h> 14.7 +//#include <xen/sched-if.h> 14.8 +#include <asm/msr.h> 14.9 +#define ADV_SCHED_HISTO 14.10 +static inline void adv_sched_hist_start(int cpu) { 14.11 + u64 now; 14.12 + rdtscll(now); 14.13 + if (!schedule_data[cpu].save_tsc) 14.14 + schedule_data[cpu].save_tsc = now; 14.15 +} 14.16 +static inline void adv_sched_hist_from_stop(int cpu) { 14.17 + u64 now; 14.18 + rdtscll(now); 14.19 + if (schedule_data[cpu].save_tsc) { 14.20 + now -= schedule_data[cpu].save_tsc; 14.21 + now /= 7; 14.22 + if (now < BUCKETS-1) 14.23 + schedule_data[cpu].from_hist[now]++; 14.24 + else 14.25 + schedule_data[cpu].from_hist[BUCKETS-1]++; 14.26 + 14.27 + schedule_data[cpu].save_tsc = 0; 14.28 + } 14.29 +} 14.30 +static inline void adv_sched_hist_to_stop(int cpu) { 14.31 + u64 now; 14.32 + rdtscll(now); 14.33 + if (schedule_data[cpu].save_tsc) { 14.34 + now -= schedule_data[cpu].save_tsc; 14.35 + now /= 24; 14.36 + if (now < BUCKETS-1) 14.37 + schedule_data[cpu].to_hist[now]++; 14.38 + else 14.39 + schedule_data[cpu].to_hist[BUCKETS-1]++; 14.40 + 14.41 + schedule_data[cpu].save_tsc = 0; 14.42 + } 14.43 +}
15.1 --- a/xen/include/xen/sched-if.h Wed Apr 20 21:22:46 2005 +0000 15.2 +++ b/xen/include/xen/sched-if.h Thu Apr 21 01:42:29 2005 +0000 15.3 @@ -8,6 +8,10 @@ 15.4 #ifndef __XEN_SCHED_IF_H__ 15.5 #define __XEN_SCHED_IF_H__ 15.6 15.7 +//#define ADV_SCHED_HISTO 15.8 +#define BUCKETS 10 15.9 +/*300*/ 15.10 + 15.11 struct schedule_data { 15.12 spinlock_t schedule_lock; /* spinlock protecting curr */ 15.13 struct exec_domain *curr; /* current task */ 15.14 @@ -15,6 +19,11 @@ struct schedule_data { 15.15 void *sched_priv; 15.16 struct ac_timer s_timer; /* scheduling timer */ 15.17 unsigned long tick; /* current periodic 'tick' */ 15.18 +#ifdef ADV_SCHED_HISTO 15.19 + u32 to_hist[BUCKETS]; 15.20 + u32 from_hist[BUCKETS]; 15.21 + u64 save_tsc; 15.22 +#endif 15.23 #ifdef BUCKETS 15.24 u32 hist[BUCKETS]; /* for scheduler latency histogram */ 15.25 #endif