//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: Kernel\Singularity\Scheduling\CpuResource.cs // // Note: // using System; using System.Collections; using System.Diagnostics; using System.Threading; using Microsoft.Singularity; #if SIMULATOR using Thread = Microsoft.Singularity.Scheduling.Thread; using Processor = Microsoft.Singularity.Scheduling.Processor; #endif namespace Microsoft.Singularity.Scheduling { /// /// The CPU resource provider object. /// [CLSCompliant(false)] public class CpuResource : IResource { /// /// Return a reference to the CPU resource provider object. /// static public CpuResource Provider() { return cpuResourceProvider; } public override string ResourceString { get { return "Microsoft.Singularity.Scheduling.CpuResource"; } } /// /// Constructor for the static CPU Resource Provider object /// private CpuResource() { } /// /// The static CPU Resource Provider object /// private static CpuResource cpuResourceProvider = new CpuResource(); //Establishes the system scheduler -- should be called by system initialization, and should //throw an error when called a 2nd time. public static void RegisterSystemScheduler(ICpuScheduler scheduler) { if(cpuResourceScheduler == null) { cpuResourceScheduler = scheduler; } else { //TODO: Throw Exception Perhaps! } } /// /// This is the actual system CPU scheduler. It is used for CPU reservations, /// constraints, to interact with the timer, and to allow the CPU scheduler /// to be swapped out while maintaining a consistent interface. /// private static ICpuScheduler cpuResourceScheduler; public static ISchedulerActivity CreateSchedulerActivity() { return cpuResourceScheduler.CreateSchedulerActivity(); } public static ISchedulerThread CreateSchedulerThread(Thread thread) { return cpuResourceScheduler.CreateSchedulerThread(thread); } public static ISchedulerProcessor CreateSchedulerProcessor(Processor processor) { return cpuResourceScheduler.CreateSchedulerProcessor(processor); } public static readonly TimeSpan MaxPeriod = new TimeSpan(1 * TimeSpan.TicksPerSecond); /// /// Return amount of CPU available for reservation for the specified Activity and period /// public CpuResourceAmount AvailableCpu(Activity activity, TimeSpan period) { // XXX TBD return new CpuResourceAmount((cyclesPerSecond * period.Ticks) / TimeSpan.TicksPerSecond); } /// /// Reserve CPU on an ongoing basis for a resource container. /// Replaces any existing reservation for that resource container. /// Specify 0 cycles to end the CPU reservation for the resource container. /// Returns null if reservation is denied. XXX Should this throw an exception instead? /// public CpuResourceReservation ReserveCpu(Activity activity, CpuResourceAmount amount, TimeSpan period) { object tempOldReservation = activity.GetResourceReservation(CpuResource.Provider().ResourceString); Debug.Assert(tempOldReservation == null || tempOldReservation is CpuResourceReservation); CpuResourceReservation oldReservation = (CpuResourceReservation)tempOldReservation; ISchedulerCpuReservation schedulerReservation = cpuResourceScheduler.ReserveCpu(activity.schedulerActivity, amount, period); CpuResourceReservation reservation = null; if(schedulerReservation != null) { reservation = new CpuResourceReservation(amount, period, schedulerReservation); schedulerReservation.EnclosingCpuReservation = reservation; } activity.SetResourceReservation(CpuResource.Provider().ResourceString, reservation); return reservation; } /// /// Convert a CPU amount to the minimum amount of time required for that amount. /// This conversion assumes that the CPU is running at its maximum rate. /// public CpuResourceAmount TimeToCpu(TimeSpan time) { return new CpuResourceAmount((cyclesPerSecond * time.Ticks) / TimeSpan.TicksPerSecond); } /// /// Convert a timespan to the maximum amount of CPU that can be used in that timespan. /// This conversion assumes that the CPU is running at its maximum rate. /// public TimeSpan CpuToTime(CpuResourceAmount amount) { if(amount == null) { return new TimeSpan(0); } return new TimeSpan((TimeSpan.TicksPerSecond * amount.Cycles) / cyclesPerSecond); } private long cyclesPerSecond; volatile static int do_something = 0; static void Spinner() { do_something++; } public bool NextThread(out Thread nextThread) { return cpuResourceScheduler.NextThread(out nextThread); } public bool ShouldReschedule() { return cpuResourceScheduler.ShouldReschedule(); } //XXX: One resource world only. /// /// Note that as tasks now contain resource accounting, there is /// no need to pass out the resource usage from the scheduler. /// For consistency we'll still pass it out of the Task API at least /// until instantaneous usage is fixed. /// /// /// /// /// /// Returns true if admitted. internal bool BeginConstraint(Hashtable resourceEstimates, DateTime deadline, Task taskToEnd, out ISchedulerTask schedulerTask) { return cpuResourceScheduler.BeginConstraint(resourceEstimates, deadline, ((taskToEnd==null)?null:taskToEnd.schedulerTask), out schedulerTask); } internal void BeginDelayedConstraint(Hashtable resourceEstimates, TimeSpan relativeDeadline, Task taskToEnd, out ISchedulerTask schedulerTask) { cpuResourceScheduler.BeginDelayedConstraint(resourceEstimates, relativeDeadline, ((taskToEnd==null)?null:taskToEnd.schedulerTask), out schedulerTask); } internal Hashtable EndConstraint(Task taskToEnd) { cpuResourceScheduler.EndConstraint(((taskToEnd==null)?null:taskToEnd.schedulerTask)); return taskToEnd.resourcesUsed; } public void Initialize() { Debug.Assert(cpuResourceScheduler != null, "No registered scheduler!"); cyclesPerSecond = (long)Processor.CyclesPerSecond; Debug.Assert(Processor.processorTable != null, "Processor table is null!"); for (int i = 0; i < Processor.processorTable.Length; i++) { Debug.Assert(Processor.processorTable[i] != null, "Processor is null!"); Processor.processorTable[i].InitializeSchedulerProcessor(); } cpuResourceScheduler.Initialize(); } } }