/**************************************************************************** * (C) 2002-2003 - Rolf Neugebauer - Intel Research Cambridge * (C) 2002-2003 University of Cambridge * (C) 2004 - Mark Williamson - Intel Research Cambridge **************************************************************************** * * File: common/schedule.c * Author: Rolf Neugebauer & Keir Fraser * Updated for generic API by Mark Williamson * * Description: Generic CPU scheduling code * implements support functionality for the Xen scheduler API. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* opt_sched: scheduler - default to Borrowed Virtual Time */ static char opt_sched[10] = "bvt"; string_param("sched", opt_sched); /*#define WAKE_HISTO*/ /*#define BLOCKTIME_HISTO*/ #if defined(WAKE_HISTO) #define BUCKETS 31 #elif defined(BLOCKTIME_HISTO) #define BUCKETS 200 #endif #define TIME_SLOP (s32)MICROSECS(50) /* allow time to slip a bit */ /* * TODO MAW pull trace-related #defines out of here and into an auto-generated * header file later on! */ #define TRC_SCHED_DOM_ADD 0x00010000 #define TRC_SCHED_DOM_REM 0x00010001 #define TRC_SCHED_WAKE 0x00010002 #define TRC_SCHED_BLOCK 0x00010003 #define TRC_SCHED_YIELD 0x00010004 #define TRC_SCHED_SET_TIMER 0x00010005 #define TRC_SCHED_CTL 0x00010006 #define TRC_SCHED_ADJDOM 0x00010007 #define TRC_SCHED_RESCHED 0x00010008 #define TRC_SCHED_SWITCH 0x00010009 #define TRC_SCHED_S_TIMER_FN 0x0001000A #define TRC_SCHED_T_TIMER_FN 0x0001000B #define TRC_SCHED_DOM_TIMER_FN 0x0001000C /* Various timer handlers. */ static void s_timer_fn(unsigned long unused); static void t_timer_fn(unsigned long unused); static void dom_timer_fn(unsigned long data); /* This is global for now so that private implementations can reach it */ schedule_data_t schedule_data[NR_CPUS]; extern struct scheduler sched_bvt_def; // extern struct scheduler sched_rrobin_def; // extern struct scheduler sched_atropos_def; static struct scheduler *schedulers[] = { &sched_bvt_def, // &sched_rrobin_def, // &sched_atropos_def, NULL }; /* Operations for the current scheduler. */ static struct scheduler ops; #define SCHED_OP(fn, ...) \ (( ops.fn != NULL ) ? ops.fn( __VA_ARGS__ ) \ : (typeof(ops.fn(__VA_ARGS__)))0 ) /* Per-CPU periodic timer sends an event to the currently-executing domain. */ static struct ac_timer t_timer[NR_CPUS]; void free_domain_struct(struct domain *d) { int i; SCHED_OP(free_task, d); for (i = 0; i < MAX_VIRT_CPUS; i++) if ( d->exec_domain[i] ) arch_free_exec_domain_struct(d->exec_domain[i]); arch_free_domain_struct(d); } struct exec_domain *alloc_exec_domain_struct(struct domain *d, unsigned long vcpu) { struct exec_domain *ed, *edc; ASSERT( d->exec_domain[vcpu] == NULL ); if ( (ed = arch_alloc_exec_domain_struct()) == NULL ) return NULL; memset(ed, 0, sizeof(*ed)); d->exec_domain[vcpu] = ed; ed->domain = d; ed->eid = vcpu; if ( SCHED_OP(alloc_task, ed) < 0 ) goto out; if (vcpu != 0) { ed->vcpu_info = &d->shared_info->vcpu_data[ed->eid]; for_each_exec_domain(d, edc) { if (edc->ed_next_list == NULL || edc->ed_next_list->eid > vcpu) break; } ed->ed_next_list = edc->ed_next_list; edc->ed_next_list = ed; if (test_bit(EDF_CPUPINNED, &edc->ed_flags)) { ed->processor = (edc->processor + 1) % smp_num_cpus; set_bit(EDF_CPUPINNED, &ed->ed_flags); } else { ed->processor = (edc->processor + 1) % smp_num_cpus; /* XXX */ } } return ed; out: d->exec_domain[vcpu] = NULL; arch_free_exec_domain_struct(ed); return NULL; } struct domain *alloc_domain_struct(void) { struct domain *d; if ( (d = arch_alloc_domain_struct()) == NULL ) return NULL; memset(d, 0, sizeof(*d)); if ( alloc_exec_domain_struct(d, 0) == NULL ) goto out; return d; out: arch_free_domain_struct(d); return NULL; } /* * Add and remove a domain */ void sched_add_domain(struct exec_domain *ed) { struct domain *d = ed->domain; /* Must be unpaused by control software to start execution. */ set_bit(EDF_CTRLPAUSE, &ed->ed_flags); if ( d->id != IDLE_DOMAIN_ID ) { /* Initialise the per-domain timer. */ init_ac_timer(&ed->timer); ed->timer.cpu = ed->processor; ed->timer.data = (unsigned long)ed; ed->timer.function = &dom_timer_fn; } else { schedule_data[ed->processor].idle = ed; } SCHED_OP(add_task, ed); TRACE_2D(TRC_SCHED_DOM_ADD, d->id, ed); } void sched_rem_domain(struct exec_domain *ed) { rem_ac_timer(&ed->timer); SCHED_OP(rem_task, ed); TRACE_3D(TRC_SCHED_DOM_REM, ed->domain->id, ed->eid, ed); } void init_idle_task(vo
#!/usr/bin/env perl

use strict;
use warnings;
use Config;

if (@ARGV < 2) {
	die "Usage: $0 <prefix> <command...>\n";
}

sub gettime {
	my ($sec, $usec);

	eval {
		require Time::HiRes;
		($sec, $usec) = Time::HiRes::gettimeofday();
	};

	unless (defined($sec) && defined($usec)) {
		my $tv_t = ($Config{'longsize'} == 8) ? 'qq' : 'll';
		my $tv = pack $tv_t, 0, 0;

		eval {
			require 'syscall.ph';
			syscall(SYS_gettimeofday(), $tv, 0);
		};

		($sec, $usec) = unpack $tv_t, $tv;
	}

	return ($sec, $usec);
}

my ($prefix, @cmd) = @ARGV;
my ($sec, $usec) = gettime();
my $pid = fork();

if (!defined($pid)) {
	die "$0: Failure to fork(): $!\n";
}
elsif ($pid == 0) {
	exec(@cmd);
	die "$0: Failure to exec(): $!\n";
}
else {
	$SIG{'INT'} = 'IGNORE';
	$SIG{'QUIT'} = 'IGNORE';

	if (waitpid($pid, 0) == -1) {
		die "$0: Failure to waitpid(): $!\n";
	}

	my $exitcode = $? >> 8;
	my ($sec2, $usec2) = gettime();
	my (undef, undef, $cuser, $csystem) = times();

	printf STDOUT "%s#%.2f#%.2f#%.2f\n",
		$prefix, $cuser, $csystem,
		($sec2 - $sec) + ($usec2 - $usec) / 1000000;

	$SIG{'INT'} = 'DEFAULT';
	$SIG{'QUIT'} = 'DEFAULT';

	exit $exitcode;
}