<commit_before>use crate::*;
use bls::create_proof_of_possession;

/// Builds a `BeaconState` for use in testing or benchmarking.
///
/// Building the `BeaconState` is a three step processes:
///
/// 1. Create a new `BeaconStateBuilder`.
/// 2. Call `Self::build()` or `Self::build_fast()` generate a  `BeaconState`.
/// 3. (Optional) Use builder functions to modify the `BeaconState`.
/// 4. Call `Self::cloned_state()` to obtain a `BeaconState` cloned from this struct.
///
/// Step (2) happens prior to step (3) because some functionality requires an existing
/// `BeaconState`.
///
/// Step (4) produces a clone of the BeaconState and doesn't consume the `BeaconStateBuilder` to
/// allow access to `self.keypairs` and `self.spec`.
pub struct BeaconStateBuilder {
    pub validator_count: usize,
    pub state: Option<BeaconState>,
    pub genesis_time: u64,
    pub latest_eth1_data: Eth1Data,
    pub spec: ChainSpec,
    pub keypairs: Vec<Keypair>,
}

impl BeaconStateBuilder {
    /// Create a new builder with the given number of validators.
    pub fn new(validator_count: usize) -> Self {
        let genesis_time = 10_000_000;

        let latest_eth1_data = Eth1Data {
            deposit_root: Hash256::zero(),
            block_hash: Hash256::zero(),
        };

        let spec = ChainSpec::foundation();

        Self {
            validator_count,
            state: None,
            genesis_time,
            latest_eth1_data,
            spec,
            keypairs: vec![],
        }
    }

    /// Builds a `BeaconState` using the `BeaconState::genesis(..)` function.
    ///
    /// Each validator is assigned a unique, randomly-generated keypair and all
    /// proof-of-possessions are verified during genesis.
    pub fn build(&mut self) -> Result<(), BeaconStateError> {
        self.keypairs = (0..self.validator_count)
            .collect::<Vec<usize>>()
            .iter()
            .map(|_| Keypair::random())
            .collect();

        let initial_validator_deposits = self
            .keypairs
            .iter()
            .map(|keypair| Deposit {
                branch: vec![], // branch verification is not specified.
                index: 0,       // index verification is not specified.
                deposit_data: DepositData {
                    amount: 32_000_000_000, // 32 ETH (in Gwei)
                    timestamp: self.genesis_time - 1,
                    deposit_input: DepositInput {
                        pubkey: keypair.pk.clone(),
                        withdrawal_credentials: Hash256::zero(), // Withdrawal not possible.
                        proof_of_possession: create_proof_of_possession(&keypair),
                    },
                },
            })
            .collect();

        let state = BeaconState::genesis(
            self.genesis_time,
            initial_validator_deposits,
            self.latest_eth1_data.clone(),
            &self.spec,
        )?;

        self.state = Some(state);

        Ok(())
    }

    /// Builds a `BeaconState` using the `BeaconState::genesis(..)` function, without supplying any
    /// validators. Instead validators are added to the state post-genesis.
    ///
    /// One keypair is randomly generated and all validators are assigned this same keypair.
    /// Proof-of-possessions are not created (or validated).
    ///
    /// This function runs orders of magnitude faster than `Self::build()`, however it will be
    /// erroneous for functions which use a validators public key as an identifier (e.g.,
    /// deposits).
    /// proof-of-possessions are verified during genesis.
    pub fn build_fast(&mut self) -> Result<(), BeaconStateError> {
        let common_keypair = Keypair::random();

        let mut validator_registry = Vec::with_capacity(self.validator_count);
        let mut validator_balances = Vec::with_capacity(self.validator_count);
        self.keypairs = Vec::with_capacity(self.validator_count);

        for _ in 0..self.validator_count {
            self.keypairs.push(common_keypair.clone());
            validator_balances.push(32_000_000_000);
            validator_registry.push(Validator {
                pubkey: common_keypair.pk.clone(),
                withdrawal_credentials: Hash256::zero(),
                activation_epoch: self.spec.genesis_epoch,
                ..Validator::default()
            })
        }

        let state = BeaconState {
            validator_registry,
            validator_balances,
            ..BeaconState::genesis(
                self.genesis_time,
                vec![],
                self.latest_eth1_data.clone(),
                &self.spec,
            )?
        };

        self.state = Some(state);

        Ok(())
    }

    /// Sets the `BeaconState` to be in the last slot of the given epoch.
    ///
    /// Sets all justification/finalization parameters to be be as "perfect" as possible (i.e.,
    /// highest justified and finalized slots, full justification bitfield, etc).
    pub fn teleport_to_end_of_epoch(&mut self, epoch: Epoch) {
        let state = self.state.as_mut().expect("Genesis required");

        let slot = epoch.end_slot(self.spec.epoch_length);

        state.slot = slot;
        state.validator_registry_update_epoch = epoch - 1;

        state.previous_calculation_epoch = epoch - 1;
        state.current_calculation_epoch = epoch;

        state.previous_epoch_seed = Hash256::from(&b"previous_seed"[..]);
        state.current_epoch_seed = Hash256::from(&b"current_seed"[..]);

        state.previous_justified_epoch = epoch - 2;
        state.justified_epoch = epoch - 1;
        state.justification_bitfield = u64::max_value();
        state.finalized_epoch = epoch - 1;
    }

    /// Creates a full set of attestations for the `BeaconState`. Each attestation has full
    /// participation from its committee and references the expected beacon_block hashes.
    ///
    /// These attestations should be fully conducive to justification and finalization.
    pub fn insert_attestations(&mut self) {
        let state = self.state.as_mut().expect("Genesis required");

        state
            .build_epoch_cache(RelativeEpoch::Previous, &self.spec)
            .unwrap();
        state
            .build_epoch_cache(RelativeEpoch::Current, &self.spec)
            .unwrap();

        let current_epoch = state.current_epoch(&self.spec);
        let previous_epoch = state.previous_epoch(&self.spec);
        let current_epoch_depth =
            (state.slot - current_epoch.end_slot(self.spec.epoch_length)).as_usize();

        let previous_epoch_slots = previous_epoch.slot_iter(self.spec.epoch_length);
        let current_epoch_slots = current_epoch
            .slot_iter(self.spec.epoch_length)
            .take(current_epoch_depth);

        for slot in previous_epoch_slots.chain(current_epoch_slots) {
            let committees = state
                .get_crosslink_committees_at_slot(slot, &self.spec)
                .unwrap()
                .clone();

            for (committee, shard) in committees {
                state
                    .latest_attestations
                    .push(committee_to_pending_attestation(
                        state, &committee, shard, slot, &self.spec,
                    ))
            }
        }
    }

    /// Returns a cloned `BeaconState`.
    pub fn cloned_state(&self) -> BeaconState {
        self.state.as_ref().expect("Genesis required").clone()
    }
}

/// Builds a valid PendingAttestation with full participation for some committee.
fn committee_to_pending_attestation(
    state: &BeaconState,
    committee: &[usize],
    shard: u64,
    slot: Slot,
    spec: &ChainSpec,
) -> PendingAttestation {
    let current_epoch = state.current_epoch(spec);
    let previous_epoch = state.previous_epoch(spec);

    let mut aggregation_bitfield = Bitfield::new();
    let mut custody_bitfield = Bitfield::new();

    for (i, _) in committee.iter().enumerate() {
        aggregation_bitfield.set(i, true);
        custody_bitfield.set(i, true);
    }

    let is_previous_epoch = state.slot.epoch(spec.epoch_length) != slot.epoch(spec.epoch_length);

    let justified_epoch = if is_previous_epoch {
        state.previous_justified_epoch
    } else {
        state.justified_epoch
    };

    let epoch_boundary_root = if is_previous_epoch {
        *state
            .get_block_root(previous_epoch.start_slot(spec.epoch_length), spec)
            .unwrap()
    } else {
        *state
            .get_block_root(current_epoch.start_slot(spec.epoch_length), spec)
            .unwrap()
    };

    let justified_block_root = *state
        .get_block_root(justified_epoch.start_slot(spec.epoch_length), &spec)
        .unwrap();

    PendingAttestation {
        aggregation_bitfield,
        data: AttestationData {
            slot,
            shard,
            beacon_block_root: *state.get_block_root(slot, spec).unwrap(),
            epoch_boundary_root,
            shard_block_root: Hash256::zero(),
            latest_crosslink: Crosslink {
                epoch: slot.epoch(spec.epoch_length),
                shard_block_root: Hash256::zero(),
            },
            justified_epoch,
            justified_block_root,
        },
        custody_bitfield,
        inclusion_slot: slot,
    }
}
<commit_msg>Fix type in `BeaconStateBuilder` comments<commit_after>use crate::*;
use bls::create_proof_of_possession;

/// Builds a `BeaconState` for use in testing or benchmarking.
///
/// Building the `BeaconState` is a three step processes:
///
/// 1. Create a new `BeaconStateBuilder`.
/// 2. Call `Self::build()` or `Self::build_fast()` generate a  `BeaconState`.
/// 3. (Optional) Use builder functions to modify the `BeaconState`.
/// 4. Call `Self::cloned_state()` to obtain a `BeaconState` cloned from this struct.
///
/// Step (2) happens prior to step (3) because some functionality requires an existing
/// `BeaconState`.
///
/// Step (4) produces a clone of the BeaconState and doesn't consume the `BeaconStateBuilder` to
/// allow access to `self.keypairs` and `self.spec`.
pub struct BeaconStateBuilder {
    pub validator_count: usize,
    pub state: Option<BeaconState>,
    pub genesis_time: u64,
    pub latest_eth1_data: Eth1Data,
    pub spec: ChainSpec,
    pub keypairs: Vec<Keypair>,
}

impl BeaconStateBuilder {
    /// Create a new builder with the given number of validators.
    pub fn new(validator_count: usize) -> Self {
        let genesis_time = 10_000_000;

        let latest_eth1_data = Eth1Data {
            deposit_root: Hash256::zero(),
            block_hash: Hash256::zero(),
        };

        let spec = ChainSpec::foundation();

        Self {
            validator_count,
            state: None,
            genesis_time,
            latest_eth1_data,
            spec,
            keypairs: vec![],
        }
    }

    /// Builds a `BeaconState` using the `BeaconState::genesis(..)` function.
    ///
    /// Each validator is assigned a unique, randomly-generated keypair and all
    /// proof-of-possessions are verified during genesis.
    pub fn build(&mut self) -> Result<(), BeaconStateError> {
        self.keypairs = (0..self.validator_count)
            .collect::<Vec<usize>>()
            .iter()
            .map(|_| Keypair::random())
            .collect();

        let initial_validator_deposits = self
            .keypairs
            .iter()
            .map(|keypair| Deposit {
                branch: vec![], // branch verification is not specified.
                index: 0,       // index verification is not specified.
                deposit_data: DepositData {
                    amount: 32_000_000_000, // 32 ETH (in Gwei)
                    timestamp: self.genesis_time - 1,
                    deposit_input: DepositInput {
                        pubkey: keypair.pk.clone(),
                        withdrawal_credentials: Hash256::zero(), // Withdrawal not possible.
                        proof_of_possession: create_proof_of_possession(&keypair),
                    },
                },
            })
            .collect();

        let state = BeaconState::genesis(
            self.genesis_time,
            initial_validator_deposits,
            self.latest_eth1_data.clone(),
            &self.spec,
        )?;

        self.state = Some(state);

        Ok(())
    }

    /// Builds a `BeaconState` using the `BeaconState::genesis(..)` function, without supplying any
    /// validators. Instead validators are added to the state post-genesis.
    ///
    /// One keypair is randomly generated and all validators are assigned this same keypair.
    /// Proof-of-possessions are not created (or validated).
    ///
    /// This function runs orders of magnitude faster than `Self::build()`, however it will be
    /// erroneous for functions which use a validators public key as an identifier (e.g.,
    /// deposits).
    pub fn build_fast(&mut self) -> Result<(), BeaconStateError> {
        let common_keypair = Keypair::random();

        let mut validator_registry = Vec::with_capacity(self.validator_count);
        let mut validator_balances = Vec::with_capacity(self.validator_count);
        self.keypairs = Vec::with_capacity(self.validator_count);

        for _ in 0..self.validator_count {
            self.keypairs.push(common_keypair.clone());
            validator_balances.push(32_000_000_000);
            validator_registry.push(Validator {
                pubkey: common_keypair.pk.clone(),
                withdrawal_credentials: Hash256::zero(),
                activation_epoch: self.spec.genesis_epoch,
                ..Validator::default()
            })
        }

        let state = BeaconState {
            validator_registry,
            validator_balances,
            ..BeaconState::genesis(
                self.genesis_time,
                vec![],
                self.latest_eth1_data.clone(),
                &self.spec,
            )?
        };

        self.state = Some(state);

        Ok(())
    }

    /// Sets the `BeaconState` to be in the last slot of the given epoch.
    ///
    /// Sets all justification/finalization parameters to be be as "perfect" as possible (i.e.,
    /// highest justified and finalized slots, full justification bitfield, etc).
    pub fn teleport_to_end_of_epoch(&mut self, epoch: Epoch) {
        let state = self.state.as_mut().expect("Genesis required");

        let slot = epoch.end_slot(self.spec.epoch_length);

        state.slot = slot;
        state.validator_registry_update_epoch = epoch - 1;

        state.previous_calculation_epoch = epoch - 1;
        state.current_calculation_epoch = epoch;

        state.previous_epoch_seed = Hash256::from(&b"previous_seed"[..]);
        state.current_epoch_seed = Hash256::from(&b"current_seed"[..]);

        state.previous_justified_epoch = epoch - 2;
        state.justified_epoch = epoch - 1;
        state.justification_bitfield = u64::max_value();
        state.finalized_epoch = epoch - 1;
    }

    /// Creates a full set of attestations for the `BeaconState`. Each attestation has full
    /// participation from its committee and references the expected beacon_block hashes.
    ///
    /// These attestations should be fully conducive to justification and finalization.
    pub fn insert_attestations(&mut self) {
        let state = self.state.as_mut().expect("Genesis required");

        state
            .build_epoch_cache(RelativeEpoch::Previous, &self.spec)
            .unwrap();
        state
            .build_epoch_cache(RelativeEpoch::Current, &self.spec)
            .unwrap();

        let current_epoch = state.current_epoch(&self.spec);
        let previous_epoch = state.previous_epoch(&self.spec);
        let current_epoch_depth =
            (state.slot - current_epoch.end_slot(self.spec.epoch_length)).as_usize();

        let previous_epoch_slots = previous_epoch.slot_iter(self.spec.epoch_length);
        let current_epoch_slots = current_epoch
            .slot_iter(self.spec.epoch_length)
            .take(current_epoch_depth);

        for slot in previous_epoch_slots.chain(current_epoch_slots) {
            let committees = state
                .get_crosslink_committees_at_slot(slot, &self.spec)
                .unwrap()
                .clone();

            for (committee, shard) in committees {
                state
                    .latest_attestations
                    .push(committee_to_pending_attestation(
                        state, &committee, shard, slot, &self.spec,
                    ))
            }
        }
    }

    /// Returns a cloned `BeaconState`.
    pub fn cloned_state(&self) -> BeaconState {
        self.state.as_ref().expect("Genesis required").clone()
    }
}

/// Builds a valid PendingAttestation with full participation for some committee.
fn committee_to_pending_attestation(
    state: &BeaconState,
    committee: &[usize],
    shard: u64,
    slot: Slot,
    spec: &ChainSpec,
) -> PendingAttestation {
    let current_epoch = state.current_epoch(spec);
    let previous_epoch = state.previous_epoch(spec);

    let mut aggregation_bitfield = Bitfield::new();
    let mut custody_bitfield = Bitfield::new();

    for (i, _) in committee.iter().enumerate() {
        aggregation_bitfield.set(i, true);
        custody_bitfield.set(i, true);
    }

    let is_previous_epoch = state.slot.epoch(spec.epoch_length) != slot.epoch(spec.epoch_length);

    let justified_epoch = if is_previous_epoch {
        state.previous_justified_epoch
    } else {
        state.justified_epoch
    };

    let epoch_boundary_root = if is_previous_epoch {
        *state
            .get_block_root(previous_epoch.start_slot(spec.epoch_length), spec)
            .unwrap()
    } else {
        *state
            .get_block_root(current_epoch.start_slot(spec.epoch_length), spec)
            .unwrap()
    };

    let justified_block_root = *state
        .get_block_root(justified_epoch.start_slot(spec.epoch_length), &spec)
        .unwrap();

    PendingAttestation {
        aggregation_bitfield,
        data: AttestationData {
            slot,
            shard,
            beacon_block_root: *state.get_block_root(slot, spec).unwrap(),
            epoch_boundary_root,
            shard_block_root: Hash256::zero(),
            latest_crosslink: Crosslink {
                epoch: slot.epoch(spec.epoch_length),
                shard_block_root: Hash256::zero(),
            },
            justified_epoch,
            justified_block_root,
        },
        custody_bitfield,
        inclusion_slot: slot,
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate sys_util;
extern crate kvm_sys;
extern crate kvm;
extern crate kernel_loader;
extern crate x86_64;
extern crate clap;
extern crate devices;

pub mod machine;

use std::ffi::{CStr, CString};
use std::fs::File;
use std::io::{self, stdout, Write};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Barrier, Mutex};
use std::thread;
use std::thread::JoinHandle;
use kvm::*;
use kvm_sys::kvm_regs;
use sys_util::{register_signal_handler, EventFd, GuestAddress, GuestMemory, Killable, Pollable,
               Poller, Terminal};
use machine::MachineCfg;

const KERNEL_START_OFFSET: usize = 0x200000;
const CMDLINE_OFFSET: usize = 0x20000;

#[derive(Debug)]
pub enum Error {
    ConfigureSystem(x86_64::Error),
    EventFd(sys_util::Error),
    GuestMemory(sys_util::GuestMemoryError),
    Irq(sys_util::Error),
    Kernel(std::io::Error),
    KernelLoader(kernel_loader::Error),
    Kvm(sys_util::Error),
    Vcpu(sys_util::Error),
    VcpuSpawn(std::io::Error),
    Vm(sys_util::Error),
}

impl std::convert::From<kernel_loader::Error> for Error {
    fn from(e: kernel_loader::Error) -> Error {
        Error::KernelLoader(e)
    }
}

impl std::convert::From<x86_64::Error> for Error {
    fn from(e: x86_64::Error) -> Error {
        Error::ConfigureSystem(e)
    }
}

type Result<T> = std::result::Result<T, Error>;

pub fn boot_kernel(cfg: &MachineCfg) -> Result<()> {
    // FIXME branciog@ do not hardcode the vm mem size
    // Hardcoding the vm memory size to 128MB
    let mem_size = 128 << 20;
    let arch_mem_regions = x86_64::arch_memory_regions(mem_size);

    let mut kernel_file;
    match cfg.kernel_path {
        Some(ref kernel_path) => {
            kernel_file = File::open(kernel_path.as_path()).map_err(Error::Kernel)?
        }
        None => {
            return Err(Error::Kernel(io::Error::new(
                io::ErrorKind::NotFound,
                "missing kernel path",
            )))
        }
    }

    let cmdline: CString = match cfg.kernel_cmdline {
        Some(ref v) => CString::new(v.as_bytes()).unwrap(),
        _ => {
            return Err(Error::Kernel(io::Error::new(
                io::ErrorKind::NotFound,
                "missing kernel cmdline",
            )))
        }
    };
    let cmdline: &CStr = &cmdline;
    let vcpu_count = 1;

    let kernel_start_addr = GuestAddress(KERNEL_START_OFFSET);
    let cmdline_addr = GuestAddress(CMDLINE_OFFSET);

    let guest_mem = GuestMemory::new(&arch_mem_regions).map_err(
        Error::GuestMemory,
    )?;

    let kvm = Kvm::new().map_err(Error::Kvm)?;
    let vm = Vm::new(&kvm, guest_mem).map_err(Error::Vm)?;

    let tss_addr = GuestAddress(0xfffbd000);
    vm.set_tss_addr(tss_addr).map_err(Error::Vm)?;
    vm.create_pit().map_err(Error::Vm)?;
    vm.create_irq_chip().map_err(Error::Vm)?;

    kernel_loader::load_kernel(vm.get_memory(), kernel_start_addr, &mut kernel_file)?;
    kernel_loader::load_cmdline(vm.get_memory(), cmdline_addr, cmdline)?;

    x86_64::configure_system(
        vm.get_memory(),
        kernel_start_addr,
        cmdline_addr,
        cmdline.to_bytes().len() + 1,
        vcpu_count as u8,
    )?;

    let mut io_bus = devices::Bus::new();
    let com_evt_1_3 = EventFd::new().map_err(Error::EventFd)?;
    let com_evt_2_4 = EventFd::new().map_err(Error::EventFd)?;
    let stdio_serial = Arc::new(Mutex::new(devices::Serial::new_out(
        com_evt_1_3.try_clone().map_err(Error::EventFd)?,
        Box::new(stdout()),
    )));

    io_bus.insert(stdio_serial.clone(), 0x3f8, 0x8).unwrap();
    io_bus
        .insert(
            Arc::new(Mutex::new(devices::Serial::new_sink(
                com_evt_2_4.try_clone().map_err(Error::EventFd)?,
            ))),
            0x2f8,
            0x8,
        )
        .unwrap();
    io_bus
        .insert(
            Arc::new(Mutex::new(devices::Serial::new_sink(
                com_evt_1_3.try_clone().map_err(Error::EventFd)?,
            ))),
            0x3e8,
            0x8,
        )
        .unwrap();
    io_bus
        .insert(
            Arc::new(Mutex::new(devices::Serial::new_sink(
                com_evt_2_4.try_clone().map_err(Error::EventFd)?,
            ))),
            0x2e8,
            0x8,
        )
        .unwrap();

    vm.register_irqfd(&com_evt_1_3, 4).map_err(Error::Irq)?;
    vm.register_irqfd(&com_evt_2_4, 3).map_err(Error::Irq)?;

    let exit_evt = EventFd::new().map_err(Error::EventFd)?;
    let mut vcpu_handles = Vec::with_capacity(vcpu_count as usize);
    let vcpu_thread_barrier = Arc::new(Barrier::new((vcpu_count + 1) as usize));
    let kill_signaled = Arc::new(AtomicBool::new(false));

    for cpu_id in 0..vcpu_count {
        let io_bus = io_bus.clone();
        let kill_signaled = kill_signaled.clone();
        let vcpu_thread_barrier = vcpu_thread_barrier.clone();
        let vcpu_exit_evt = exit_evt.try_clone().map_err(Error::EventFd)?;

        let vcpu = Vcpu::new(cpu_id as libc::c_ulong, &kvm, &vm).map_err(
            Error::Vcpu,
        )?;
        x86_64::configure_vcpu(
            vm.get_memory(),
            kernel_start_addr,
            &kvm,
            &vcpu,
            cpu_id as u64,
            vcpu_count as u64,
        )?;
        vcpu_handles.push(thread::Builder::new()
            .name(format!("fc_vcpu{}", cpu_id))
            .spawn(move || {
                unsafe {
                    extern "C" fn handle_signal() {}
                    // Our signal handler does nothing and is trivially async signal safe.
                    register_signal_handler(0, handle_signal).expect(
                        "failed to register vcpu signal handler",
                    );
                }

                vcpu_thread_barrier.wait();

                loop {
                    match vcpu.run() {
                        Ok(run) => {
                            match run {
                                VcpuExit::IoIn(addr, data) => {
                                    io_bus.read(addr as u64, data);
                                }
                                VcpuExit::IoOut(addr, data) => {
                                    io_bus.write(addr as u64, data);
                                }
                                VcpuExit::MmioRead(_, _) => {}
                                VcpuExit::MmioWrite(_, _) => {}
                                VcpuExit::Hlt => {
                                    println!("KVM_EXIT_HLT");
                                    break;
                                }
                                VcpuExit::Shutdown => {
                                    println!("KVM_EXIT_SHUTDOWN");
                                    break;
                                }
                                r => {
                                    println!("unexpected exit reason: {:?}", r);
                                    break;
                                }
                            }
                        }
                        Err(e) => {
                            match e.errno() {
                                libc::EAGAIN | libc::EINTR => {}
                                _ => {
                                    println!("vcpu hit unknown error: {:?}", e);
                                    break;
                                }
                            }
                        }
                    }

                    if kill_signaled.load(Ordering::SeqCst) {
                        break;
                    }
                }

                vcpu_exit_evt.write(1).expect(
                    "failed to signal vcpu exit eventfd",
                );

            })
            .map_err(Error::VcpuSpawn)?);
    }

    vcpu_thread_barrier.wait();

    run_control(stdio_serial, exit_evt, kill_signaled, vcpu_handles)
}

fn run_control(
    stdio_serial: Arc<Mutex<devices::Serial>>,
    exit_evt: EventFd,
    kill_signaled: Arc<AtomicBool>,
    vcpu_handles: Vec<JoinHandle<()>>,
) -> Result<()> {
    const EXIT: u32 = 0;
    const STDIN: u32 = 1;

    let stdin_handle = io::stdin();
    let stdin_lock = stdin_handle.lock();
    stdin_lock.set_raw_mode().expect(
        "failed to set terminal raw mode",
    );

    let mut pollables = Vec::new();
    pollables.push((EXIT, &exit_evt as &Pollable));
    pollables.push((STDIN, &stdin_lock as &Pollable));

    let mut poller = Poller::new(pollables.len());

    'poll: loop {
        let tokens = match poller.poll(&pollables[..]) {
            Ok(v) => v,
            Err(e) => {
                println!("failed to poll: {:?}", e);
                break;
            }
        };

        for &token in tokens {
            match token {
                EXIT => {
                    println!("vcpu requested shutdown");
                    break 'poll;
                }
                STDIN => {
                    let mut out = [0u8; 64];
                    match stdin_lock.read_raw(&mut out[..]) {
                        Ok(0) => {
                            // Zero-length read indicates EOF. Remove from pollables.
                            pollables.retain(|&pollable| pollable.0 != STDIN);
                        }
                        Err(e) => {
                            println!("error while reading stdin: {:?}", e);
                            pollables.retain(|&pollable| pollable.0 != STDIN);
                        }
                        Ok(count) => {
                            stdio_serial
                                .lock()
                                .unwrap()
                                .queue_input_bytes(&out[..count])
                                .expect("failed to queue bytes into serial port");
                        }
                    }
                }
                _ => {}
            }
        }
    }

    kill_signaled.store(true, Ordering::SeqCst);
    for handle in vcpu_handles {
        match handle.kill(0) {
            Ok(_) => {
                if let Err(e) = handle.join() {
                    println!("failed to join vcpu thread: {:?}", e);
                }
            }
            Err(e) => println!("failed to kill vcpu thread: {:?}", e),
        }
    }

    stdin_lock.set_canon_mode().expect(
        "failed to restore canonical mode for terminal",
    );

    Ok(())
}

pub fn run_x86_code() {
    // This example based on https://lwn.net/Articles/658511/
    let code = [
        /* mov $0x3f8, %dx */
        0xba,
        0xf8,
        0x03,
        /* add %bl, %al */
        0x00,
        0xd8,
        /* add $'0', %al */
        0x04,
        '0' as u8,
        /* out %al, (%dx) */
        0xee,
        /* mov $'\n', %al */
        0xb0,
        '\n' as u8,
        /* out %al, (%dx) */
        0xee,
        /* hlt */
        0xf4,
    ];

    let mem_size = 0x1000;
    let load_addr = GuestAddress(0x1000);
    let mem = GuestMemory::new(&vec![(load_addr, mem_size)]).unwrap();

    let kvm = Kvm::new().expect("new kvm failed");
    let vm = Vm::new(&kvm, mem).expect("new vm failed");
    let vcpu = Vcpu::new(0, &kvm, &vm).expect("new vcpu failed");

    vm.get_memory()
        .write_slice_at_addr(&code, load_addr)
        .expect("Writing code to memory failed.");

    let mut vcpu_sregs = vcpu.get_sregs().expect("get sregs failed");
    assert_ne!(vcpu_sregs.cs.base, 0);
    assert_ne!(vcpu_sregs.cs.selector, 0);
    vcpu_sregs.cs.base = 0;
    vcpu_sregs.cs.selector = 0;
    vcpu.set_sregs(&vcpu_sregs).expect("set sregs failed");

    let mut vcpu_regs: kvm_regs = unsafe { std::mem::zeroed() };
    vcpu_regs.rip = 0x1000;
    vcpu_regs.rax = 2;
    vcpu_regs.rbx = 2;
    vcpu_regs.rflags = 2;
    vcpu.set_regs(&vcpu_regs).expect("set regs failed");

    loop {
        match vcpu.run().expect("run failed") {
            VcpuExit::IoOut(0x3f8, data) => {
                assert_eq!(data.len(), 1);
                io::stdout().write(data).unwrap();
            }
            VcpuExit::Hlt => {
                io::stdout().write(b"KVM_EXIT_HLT\n").unwrap();
                break;
            }
            r => panic!("unexpected exit reason: {:?}", r),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn run_code() {
        run_x86_code();
    }
}
<commit_msg>vmm: add i8042 device<commit_after>extern crate libc;
extern crate sys_util;
extern crate kvm_sys;
extern crate kvm;
extern crate kernel_loader;
extern crate x86_64;
extern crate clap;
extern crate devices;

pub mod machine;

use std::ffi::{CStr, CString};
use std::fs::File;
use std::io::{self, stdout, Write};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Barrier, Mutex};
use std::thread;
use std::thread::JoinHandle;
use kvm::*;
use kvm_sys::kvm_regs;
use sys_util::{register_signal_handler, EventFd, GuestAddress, GuestMemory, Killable, Pollable,
               Poller, Terminal};
use machine::MachineCfg;

const KERNEL_START_OFFSET: usize = 0x200000;
const CMDLINE_OFFSET: usize = 0x20000;

#[derive(Debug)]
pub enum Error {
    ConfigureSystem(x86_64::Error),
    EventFd(sys_util::Error),
    GuestMemory(sys_util::GuestMemoryError),
    Irq(sys_util::Error),
    Kernel(std::io::Error),
    KernelLoader(kernel_loader::Error),
    Kvm(sys_util::Error),
    Vcpu(sys_util::Error),
    VcpuSpawn(std::io::Error),
    Vm(sys_util::Error),
}

impl std::convert::From<kernel_loader::Error> for Error {
    fn from(e: kernel_loader::Error) -> Error {
        Error::KernelLoader(e)
    }
}

impl std::convert::From<x86_64::Error> for Error {
    fn from(e: x86_64::Error) -> Error {
        Error::ConfigureSystem(e)
    }
}

type Result<T> = std::result::Result<T, Error>;

pub fn boot_kernel(cfg: &MachineCfg) -> Result<()> {
    // FIXME branciog@ do not hardcode the vm mem size
    // Hardcoding the vm memory size to 128MB
    let mem_size = 128 << 20;
    let arch_mem_regions = x86_64::arch_memory_regions(mem_size);

    let mut kernel_file;
    match cfg.kernel_path {
        Some(ref kernel_path) => {
            kernel_file = File::open(kernel_path.as_path()).map_err(Error::Kernel)?
        }
        None => {
            return Err(Error::Kernel(io::Error::new(
                io::ErrorKind::NotFound,
                "missing kernel path",
            )))
        }
    }

    let cmdline: CString = match cfg.kernel_cmdline {
        Some(ref v) => CString::new(v.as_bytes()).unwrap(),
        _ => {
            return Err(Error::Kernel(io::Error::new(
                io::ErrorKind::NotFound,
                "missing kernel cmdline",
            )))
        }
    };
    let cmdline: &CStr = &cmdline;
    let vcpu_count = 1;

    let kernel_start_addr = GuestAddress(KERNEL_START_OFFSET);
    let cmdline_addr = GuestAddress(CMDLINE_OFFSET);

    let guest_mem = GuestMemory::new(&arch_mem_regions).map_err(
        Error::GuestMemory,
    )?;

    let kvm = Kvm::new().map_err(Error::Kvm)?;
    let vm = Vm::new(&kvm, guest_mem).map_err(Error::Vm)?;

    let tss_addr = GuestAddress(0xfffbd000);
    vm.set_tss_addr(tss_addr).map_err(Error::Vm)?;
    vm.create_pit().map_err(Error::Vm)?;
    vm.create_irq_chip().map_err(Error::Vm)?;

    kernel_loader::load_kernel(vm.get_memory(), kernel_start_addr, &mut kernel_file)?;
    kernel_loader::load_cmdline(vm.get_memory(), cmdline_addr, cmdline)?;

    x86_64::configure_system(
        vm.get_memory(),
        kernel_start_addr,
        cmdline_addr,
        cmdline.to_bytes().len() + 1,
        vcpu_count as u8,
    )?;

    let mut io_bus = devices::Bus::new();
    let com_evt_1_3 = EventFd::new().map_err(Error::EventFd)?;
    let com_evt_2_4 = EventFd::new().map_err(Error::EventFd)?;
    let stdio_serial = Arc::new(Mutex::new(devices::Serial::new_out(
        com_evt_1_3.try_clone().map_err(Error::EventFd)?,
        Box::new(stdout()),
    )));

    io_bus.insert(stdio_serial.clone(), 0x3f8, 0x8).unwrap();
    io_bus
        .insert(
            Arc::new(Mutex::new(devices::Serial::new_sink(
                com_evt_2_4.try_clone().map_err(Error::EventFd)?,
            ))),
            0x2f8,
            0x8,
        )
        .unwrap();
    io_bus
        .insert(
            Arc::new(Mutex::new(devices::Serial::new_sink(
                com_evt_1_3.try_clone().map_err(Error::EventFd)?,
            ))),
            0x3e8,
            0x8,
        )
        .unwrap();
    io_bus
        .insert(
            Arc::new(Mutex::new(devices::Serial::new_sink(
                com_evt_2_4.try_clone().map_err(Error::EventFd)?,
            ))),
            0x2e8,
            0x8,
        )
        .unwrap();

    vm.register_irqfd(&com_evt_1_3, 4).map_err(Error::Irq)?;
    vm.register_irqfd(&com_evt_2_4, 3).map_err(Error::Irq)?;

    let exit_evt = EventFd::new().map_err(Error::EventFd)?;
    io_bus
        .insert(
            Arc::new(Mutex::new(devices::I8042Device::new(
                exit_evt.try_clone().map_err(Error::EventFd)?,
            ))),
            0x064,
            0x1,
        )
        .unwrap();

    let mut vcpu_handles = Vec::with_capacity(vcpu_count as usize);
    let vcpu_thread_barrier = Arc::new(Barrier::new((vcpu_count + 1) as usize));
    let kill_signaled = Arc::new(AtomicBool::new(false));

    for cpu_id in 0..vcpu_count {
        let io_bus = io_bus.clone();
        let kill_signaled = kill_signaled.clone();
        let vcpu_thread_barrier = vcpu_thread_barrier.clone();
        let vcpu_exit_evt = exit_evt.try_clone().map_err(Error::EventFd)?;

        let vcpu = Vcpu::new(cpu_id as libc::c_ulong, &kvm, &vm).map_err(
            Error::Vcpu,
        )?;
        x86_64::configure_vcpu(
            vm.get_memory(),
            kernel_start_addr,
            &kvm,
            &vcpu,
            cpu_id as u64,
            vcpu_count as u64,
        )?;
        vcpu_handles.push(thread::Builder::new()
            .name(format!("fc_vcpu{}", cpu_id))
            .spawn(move || {
                unsafe {
                    extern "C" fn handle_signal() {}
                    // Our signal handler does nothing and is trivially async signal safe.
                    register_signal_handler(0, handle_signal).expect(
                        "failed to register vcpu signal handler",
                    );
                }

                vcpu_thread_barrier.wait();

                loop {
                    match vcpu.run() {
                        Ok(run) => {
                            match run {
                                VcpuExit::IoIn(addr, data) => {
                                    io_bus.read(addr as u64, data);
                                }
                                VcpuExit::IoOut(addr, data) => {
                                    io_bus.write(addr as u64, data);
                                }
                                VcpuExit::MmioRead(_, _) => {}
                                VcpuExit::MmioWrite(_, _) => {}
                                VcpuExit::Hlt => {
                                    println!("KVM_EXIT_HLT");
                                    break;
                                }
                                VcpuExit::Shutdown => {
                                    println!("KVM_EXIT_SHUTDOWN");
                                    break;
                                }
                                r => {
                                    println!("unexpected exit reason: {:?}", r);
                                    break;
                                }
                            }
                        }
                        Err(e) => {
                            match e.errno() {
                                libc::EAGAIN | libc::EINTR => {}
                                _ => {
                                    println!("vcpu hit unknown error: {:?}", e);
                                    break;
                                }
                            }
                        }
                    }

                    if kill_signaled.load(Ordering::SeqCst) {
                        break;
                    }
                }

                vcpu_exit_evt.write(1).expect(
                    "failed to signal vcpu exit eventfd",
                );

            })
            .map_err(Error::VcpuSpawn)?);
    }

    vcpu_thread_barrier.wait();

    run_control(stdio_serial, exit_evt, kill_signaled, vcpu_handles)
}

fn run_control(
    stdio_serial: Arc<Mutex<devices::Serial>>,
    exit_evt: EventFd,
    kill_signaled: Arc<AtomicBool>,
    vcpu_handles: Vec<JoinHandle<()>>,
) -> Result<()> {
    const EXIT: u32 = 0;
    const STDIN: u32 = 1;

    let stdin_handle = io::stdin();
    let stdin_lock = stdin_handle.lock();
    stdin_lock.set_raw_mode().expect(
        "failed to set terminal raw mode",
    );

    let mut pollables = Vec::new();
    pollables.push((EXIT, &exit_evt as &Pollable));
    pollables.push((STDIN, &stdin_lock as &Pollable));

    let mut poller = Poller::new(pollables.len());

    'poll: loop {
        let tokens = match poller.poll(&pollables[..]) {
            Ok(v) => v,
            Err(e) => {
                println!("failed to poll: {:?}", e);
                break;
            }
        };

        for &token in tokens {
            match token {
                EXIT => {
                    println!("vcpu requested shutdown");
                    break 'poll;
                }
                STDIN => {
                    let mut out = [0u8; 64];
                    match stdin_lock.read_raw(&mut out[..]) {
                        Ok(0) => {
                            // Zero-length read indicates EOF. Remove from pollables.
                            pollables.retain(|&pollable| pollable.0 != STDIN);
                        }
                        Err(e) => {
                            println!("error while reading stdin: {:?}", e);
                            pollables.retain(|&pollable| pollable.0 != STDIN);
                        }
                        Ok(count) => {
                            stdio_serial
                                .lock()
                                .unwrap()
                                .queue_input_bytes(&out[..count])
                                .expect("failed to queue bytes into serial port");
                        }
                    }
                }
                _ => {}
            }
        }
    }

    kill_signaled.store(true, Ordering::SeqCst);
    for handle in vcpu_handles {
        match handle.kill(0) {
            Ok(_) => {
                if let Err(e) = handle.join() {
                    println!("failed to join vcpu thread: {:?}", e);
                }
            }
            Err(e) => println!("failed to kill vcpu thread: {:?}", e),
        }
    }

    stdin_lock.set_canon_mode().expect(
        "failed to restore canonical mode for terminal",
    );

    Ok(())
}

pub fn run_x86_code() {
    // This example based on https://lwn.net/Articles/658511/
    let code = [
        /* mov $0x3f8, %dx */
        0xba,
        0xf8,
        0x03,
        /* add %bl, %al */
        0x00,
        0xd8,
        /* add $'0', %al */
        0x04,
        '0' as u8,
        /* out %al, (%dx) */
        0xee,
        /* mov $'\n', %al */
        0xb0,
        '\n' as u8,
        /* out %al, (%dx) */
        0xee,
        /* hlt */
        0xf4,
    ];

    let mem_size = 0x1000;
    let load_addr = GuestAddress(0x1000);
    let mem = GuestMemory::new(&vec![(load_addr, mem_size)]).unwrap();

    let kvm = Kvm::new().expect("new kvm failed");
    let vm = Vm::new(&kvm, mem).expect("new vm failed");
    let vcpu = Vcpu::new(0, &kvm, &vm).expect("new vcpu failed");

    vm.get_memory()
        .write_slice_at_addr(&code, load_addr)
        .expect("Writing code to memory failed.");

    let mut vcpu_sregs = vcpu.get_sregs().expect("get sregs failed");
    assert_ne!(vcpu_sregs.cs.base, 0);
    assert_ne!(vcpu_sregs.cs.selector, 0);
    vcpu_sregs.cs.base = 0;
    vcpu_sregs.cs.selector = 0;
    vcpu.set_sregs(&vcpu_sregs).expect("set sregs failed");

    let mut vcpu_regs: kvm_regs = unsafe { std::mem::zeroed() };
    vcpu_regs.rip = 0x1000;
    vcpu_regs.rax = 2;
    vcpu_regs.rbx = 2;
    vcpu_regs.rflags = 2;
    vcpu.set_regs(&vcpu_regs).expect("set regs failed");

    loop {
        match vcpu.run().expect("run failed") {
            VcpuExit::IoOut(0x3f8, data) => {
                assert_eq!(data.len(), 1);
                io::stdout().write(data).unwrap();
            }
            VcpuExit::Hlt => {
                io::stdout().write(b"KVM_EXIT_HLT\n").unwrap();
                break;
            }
            r => panic!("unexpected exit reason: {:?}", r),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn run_code() {
        run_x86_code();
    }
}
<|endoftext|>


<commit_before>/*
 * Unix System Programming Examples / Exemplier de programmation système Unix
 *
 * Copyright (C) 1995-2022 Alain Lebret <alain.lebret [at] ensicaen [dot] fr>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use nix::sys::ptrace;
use nix::sys::signal::Signal;
use nix::sys::wait::{WaitStatus, wait};
use nix::unistd::{fork, ForkResult, Pid};

use std::collections::HashMap;
use std::ffi::c_void;
use std::os::unix::process::CommandExt;
use std::process::{Command, exit};

extern crate linux_personality;
use linux_personality::personality;

fn set_breakpoint(pid: Pid, addr: u64) -> i64 {
    // Read 8 bytes from the process memory
    let value = ptrace::read(pid, addr as *mut c_void).unwrap();

    // Insert breakpoint by write new values
    let bp = (value & (i64::MAX ^ 0xFF)) | 0xCC;

    unsafe {
        ptrace::write(pid, addr as *mut c_void, bp as *mut c_void).unwrap();
    }

    // Return original bytecode
    value
}

fn restore_breakpoint(pid: Pid, addr: u64, orig_value: i64) {
    unsafe {
        // Restore original bytecode
        ptrace::write(pid, addr as *mut c_void, orig_value as *mut c_void).unwrap();
    }
}

fn handle_sigstop(pid: Pid, saved_values: &HashMap<u64, i64>) {
    let mut regs = ptrace::getregs(pid).unwrap();
    println!("Hit breakpoint at 0x{:x}", regs.rip - 1);

    match saved_values.get(&(regs.rip - 1)) {
        Some(orig) => {
            restore_breakpoint(pid, regs.rip - 1, *orig);

            // rewind rip
            regs.rip -= 1;
            ptrace::setregs(pid, regs).expect("Error rewinding RIP");

        }
        _ => print!("Nothing saved here"),
    }

    ptrace::cont(pid, None).expect("Restoring breakpoint failed");

}

// Code that runs only for child
fn manage_child() {
    // Allows process to be traced
    ptrace::traceme().unwrap();

    // Disable ASLR for this process
    personality(linux_personality::ADDR_NO_RANDOMIZE).unwrap();

    // Execute binary replacing
    Command::new("/home/carstein/sample").exec();

    exit(0);
}

// Code that runs only for parent
fn manage_parent(pid: Pid, breakpoints: &[u64]) {
    let mut saved_values = HashMap::new();

    // Placing breakpoints
    wait().unwrap();
    for addr in breakpoints.iter() {
        let orig = set_breakpoint(pid, *addr);
        saved_values.insert(*addr, orig);
    }
    ptrace::cont(pid, None).expect("Failed continue process");

    loop {
        match wait() {
            Ok(WaitStatus::Stopped(pid_t, sig_num)) => {
                match sig_num {
                    Signal::SIGTRAP => {
                        handle_sigstop(pid_t, &saved_values);
                    }

                    Signal::SIGSEGV => {
                        let regs = ptrace::getregs(pid_t).unwrap();
                        println!("Segmentation fault at 0x{:x}", regs.rip);
                        break
                    }
                    _ => {
                        println!("Some other signal - {}", sig_num);
                        break
                    }
                }
            },

            Ok(WaitStatus::Exited(pid, exit_status)) => {
                println!("Process with pid: {} exited with status {}", pid, exit_status);
                break;
            },

            Ok(status) =>  {
                println!("Received status: {:?}", status);
                ptrace::cont(pid, None).expect("Failed to deliver signal");
            },

            Err(err) => {
                println!("Some kind of error - {:?}",err);

            },
        }
    }
}

fn main() {
    // set breakpoints hash map
    let breakpoints: [u64; 1] = [0x8048451];

    match unsafe{fork()} {

        Ok(ForkResult::Child) => {
            manage_child();
        }

        Ok(ForkResult::Parent {child}) => {
            manage_parent(child, &breakpoints);
        }

        Err(err) => {
            panic!("[main] fork() failed: {}", err);
        }
    };
}<commit_msg>Delete process_02.rs<commit_after><|endoftext|>


<commit_before>use std::str::FromStr;
use temperature::circuit::ThreeDICE;
use temperature::{self, Simulator};
use threed_ice::{StackElement, System};

use profile::Profile;
use schedule::{self, Schedule};
use {Config, Error, Job, Result};

pub struct Platform {
    pub elements: Vec<Element>,
    pub schedule: Box<Schedule>,
    pub simulator: Simulator,
    pub power: Profile,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Element {
    pub id: usize,
    pub class: Class,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Class {
    Core,
    L3,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Capacity {
    Single,
    Infinite,
}

impl Platform {
    pub fn new(config: &Config) -> Result<Platform> {
        let path = path!(config, "a stack description");

        info!(target: "Platform", "Reading {:?}...", &path);
        let system = ok!(System::new(&path));

        let mut elements = vec![];
        for element in system.stack.elements.iter().rev() {
            let die = match element {
                &StackElement::Die(ref die) => die,
                _ => continue,
            };
            for element in die.floorplan.elements.iter() {
                let id = elements.len();
                let class = try!(Class::from_str(&element.id));
                elements.push(Element { id: id, class: class });
            }
        }
        info!(target: "Platform", "Found {} processing elements.", elements.len());

        let schedule = Box::new(try!(schedule::Compact::new(&elements)));

        let config = {
            let config = some!(config.branch("temperature"),
                               "a temperature configuration is required");
            try!(new_temperature_config(&config))
        };

        info!(target: "Platform", "Constructing a thermal circuit...");
        let circuit = ok!(ThreeDICE::from(&system));
        info!(target: "Platform", "Obtained {} thermal nodes.", circuit.capacitance.len());

        info!(target: "Platform", "Initializing the temperature simulator...");
        let simulator = ok!(Simulator::new(&circuit, &config));

        let power = Profile::new(elements.len(), config.time_step);

        Ok(Platform {
            elements: elements,
            schedule: schedule,
            simulator: simulator,
            power: power,
        })
    }

    pub fn push(&mut self, job: &Job) -> Result<(f64, f64)> {
        let (start, finish, mapping) = try!(self.schedule.push(job));
        let (from, onto) = (&job.elements, &self.elements);
        for (i, j) in mapping {
            let (from, onto) = (&from[i], &onto[j]);
            self.power.push(onto.id, start, job.time_step, &from.dynamic_power,
                            from.leakage_power);
        }
        Ok((start, finish))
    }

    pub fn next(&mut self, time: f64) -> Option<(Profile, Profile)> {
        self.schedule.pass(time);
        let power = self.power.pull(time);
        let mut temperature = power.clone_zero();
        self.simulator.next(&power, &mut temperature);
        Some((power, temperature))
    }

    #[inline]
    pub fn units(&self) -> usize {
        self.elements.len()
    }

    #[inline]
    pub fn time_step(&self) -> f64 {
        self.power.time_step
    }
}

impl Element {
    #[inline(always)]
    pub fn capacity(&self) -> Capacity {
        if self.class == Class::Core {
            Capacity::Single
        } else {
            Capacity::Infinite
        }
    }
}

impl FromStr for Class {
    type Err = Error;

    fn from_str(id: &str) -> Result<Self> {
        let lower = id.to_lowercase();
        if lower.starts_with("core") {
            return Ok(Class::Core);
        } else if lower.starts_with("l3") {
            return Ok(Class::L3);
        }
        raise!("found an unknown id {:?}", id);
    }
}

fn new_temperature_config(config: &Config) -> Result<temperature::Config> {
    Ok(temperature::Config {
        ambience: *some!(config.get::<f64>("ambience"), "an ambient temperature is required"),
        time_step: *some!(config.get::<f64>("time_step"), "a time step is required"),
    })
}

#[cfg(test)]
mod tests {
    use config::Config;
    use super::{Class, Element, Platform};

    #[test]
    fn new() {
        let config = Config::new("tests/fixtures/streamer.toml").unwrap()
                            .branch("platform").unwrap();
        let platform = Platform::new(&config).unwrap();
        assert_eq!(platform.elements, &[
            Element { id: 0, class: Class::Core },
            Element { id: 1, class: Class::Core },
            Element { id: 2, class: Class::Core },
            Element { id: 3, class: Class::Core },
            Element { id: 4, class: Class::L3 },
        ]);
    }
}
<commit_msg>Make Platform private<commit_after>use std::str::FromStr;
use temperature::circuit::ThreeDICE;
use temperature::{self, Simulator};
use threed_ice::{StackElement, System};

use profile::Profile;
use schedule::{self, Schedule};
use {Config, Error, Job, Result};

pub struct Platform {
    elements: Vec<Element>,
    schedule: Box<Schedule>,
    simulator: Simulator,
    power: Profile,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Element {
    pub id: usize,
    pub class: Class,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Class {
    Core,
    L3,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Capacity {
    Single,
    Infinite,
}

impl Platform {
    pub fn new(config: &Config) -> Result<Platform> {
        let path = path!(config, "a stack description");

        info!(target: "Platform", "Reading {:?}...", &path);
        let system = ok!(System::new(&path));

        let mut elements = vec![];
        for element in system.stack.elements.iter().rev() {
            let die = match element {
                &StackElement::Die(ref die) => die,
                _ => continue,
            };
            for element in die.floorplan.elements.iter() {
                let id = elements.len();
                let class = try!(Class::from_str(&element.id));
                elements.push(Element { id: id, class: class });
            }
        }
        info!(target: "Platform", "Found {} processing elements.", elements.len());

        let schedule = Box::new(try!(schedule::Compact::new(&elements)));

        let config = {
            let config = some!(config.branch("temperature"),
                               "a temperature configuration is required");
            try!(new_temperature_config(&config))
        };

        info!(target: "Platform", "Constructing a thermal circuit...");
        let circuit = ok!(ThreeDICE::from(&system));
        info!(target: "Platform", "Obtained {} thermal nodes.", circuit.capacitance.len());

        info!(target: "Platform", "Initializing the temperature simulator...");
        let simulator = ok!(Simulator::new(&circuit, &config));

        let power = Profile::new(elements.len(), config.time_step);

        Ok(Platform { elements: elements, schedule: schedule, simulator: simulator, power: power })
    }

    pub fn push(&mut self, job: &Job) -> Result<(f64, f64)> {
        let (start, finish, mapping) = try!(self.schedule.push(job));
        let (from, onto) = (&job.elements, &self.elements);
        for (i, j) in mapping {
            let (from, onto) = (&from[i], &onto[j]);
            self.power.push(onto.id, start, job.time_step, &from.dynamic_power,
                            from.leakage_power);
        }
        Ok((start, finish))
    }

    pub fn next(&mut self, time: f64) -> Option<(Profile, Profile)> {
        self.schedule.pass(time);
        let power = self.power.pull(time);
        let mut temperature = power.clone_zero();
        self.simulator.next(&power, &mut temperature);
        Some((power, temperature))
    }

    #[inline]
    pub fn units(&self) -> usize {
        self.elements.len()
    }

    #[inline]
    pub fn time_step(&self) -> f64 {
        self.power.time_step
    }
}

impl Element {
    #[inline(always)]
    pub fn capacity(&self) -> Capacity {
        if self.class == Class::Core {
            Capacity::Single
        } else {
            Capacity::Infinite
        }
    }
}

impl FromStr for Class {
    type Err = Error;

    fn from_str(id: &str) -> Result<Self> {
        let lower = id.to_lowercase();
        if lower.starts_with("core") {
            return Ok(Class::Core);
        } else if lower.starts_with("l3") {
            return Ok(Class::L3);
        }
        raise!("found an unknown id {:?}", id);
    }
}

fn new_temperature_config(config: &Config) -> Result<temperature::Config> {
    Ok(temperature::Config {
        ambience: *some!(config.get::<f64>("ambience"), "an ambient temperature is required"),
        time_step: *some!(config.get::<f64>("time_step"), "a time step is required"),
    })
}

#[cfg(test)]
mod tests {
    use config::Config;
    use super::{Class, Element, Platform};

    #[test]
    fn new() {
        let config = Config::new("tests/fixtures/streamer.toml").unwrap()
                            .branch("platform").unwrap();
        let platform = Platform::new(&config).unwrap();
        assert_eq!(platform.elements, &[
            Element { id: 0, class: Class::Core },
            Element { id: 1, class: Class::Core },
            Element { id: 2, class: Class::Core },
            Element { id: 3, class: Class::Core },
            Element { id: 4, class: Class::L3 },
        ]);
    }
}
<|endoftext|>


<commit_before>

// Simple ANSI color library.
//
// TODO: Windows support.
const u8 color_black = 0u8;

const u8 color_red = 1u8;

const u8 color_green = 2u8;

const u8 color_yellow = 3u8;

const u8 color_blue = 4u8;

const u8 color_magenta = 5u8;

const u8 color_cyan = 6u8;

const u8 color_light_gray = 7u8;

const u8 color_light_grey = 7u8;

const u8 color_dark_gray = 8u8;

const u8 color_dark_grey = 8u8;

const u8 color_bright_red = 9u8;

const u8 color_bright_green = 10u8;

const u8 color_bright_yellow = 11u8;

const u8 color_bright_blue = 12u8;

const u8 color_bright_magenta = 13u8;

const u8 color_bright_cyan = 14u8;

const u8 color_bright_white = 15u8;

fn esc(ioivec::buf_writer writer) { writer.write(~[0x1bu8, '[' as u8]); }

fn reset(ioivec::buf_writer writer) {
    esc(writer);
    writer.write(~['0' as u8, 'm' as u8]);
}

fn color_supported() -> bool {
    auto supported_terms = ~["xterm-color", "xterm", "screen-bce"];
    ret alt (generic_os::getenv("TERM")) {
          case (option::some(?env)) {
            for (str term in supported_terms) {
                if (str::eq(term, env)) { true }
            }
            false
          }
          case (option::none) { false }
        };
}

fn set_color(ioivec::buf_writer writer, u8 first_char, u8 color) {
    assert (color < 16u8);
    esc(writer);
    if (color >= 8u8) { writer.write(~['1' as u8, ';' as u8]); color -= 8u8; }
    writer.write(~[first_char, ('0' as u8) + color, 'm' as u8]);
}

fn fg(ioivec::buf_writer writer, u8 color) {
    ret set_color(writer, '3' as u8, color);
}

fn bg(ioivec::buf_writer writer, u8 color) {
    ret set_color(writer, '4' as u8, color);
}
// export fg;
// export bg;

// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Fix color term detection in std::termivec<commit_after>

// Simple ANSI color library.
//
// TODO: Windows support.
const u8 color_black = 0u8;

const u8 color_red = 1u8;

const u8 color_green = 2u8;

const u8 color_yellow = 3u8;

const u8 color_blue = 4u8;

const u8 color_magenta = 5u8;

const u8 color_cyan = 6u8;

const u8 color_light_gray = 7u8;

const u8 color_light_grey = 7u8;

const u8 color_dark_gray = 8u8;

const u8 color_dark_grey = 8u8;

const u8 color_bright_red = 9u8;

const u8 color_bright_green = 10u8;

const u8 color_bright_yellow = 11u8;

const u8 color_bright_blue = 12u8;

const u8 color_bright_magenta = 13u8;

const u8 color_bright_cyan = 14u8;

const u8 color_bright_white = 15u8;

fn esc(ioivec::buf_writer writer) { writer.write(~[0x1bu8, '[' as u8]); }

fn reset(ioivec::buf_writer writer) {
    esc(writer);
    writer.write(~['0' as u8, 'm' as u8]);
}

fn color_supported() -> bool {
    auto supported_terms = ~["xterm-color", "xterm", "screen-bce"];
    ret alt (generic_os::getenv("TERM")) {
          case (option::some(?env)) {
            for (str term in supported_terms) {
                if (str::eq(term, env)) { ret true; }
            }
            false
          }
          case (option::none) { false }
        };
}

fn set_color(ioivec::buf_writer writer, u8 first_char, u8 color) {
    assert (color < 16u8);
    esc(writer);
    if (color >= 8u8) { writer.write(~['1' as u8, ';' as u8]); color -= 8u8; }
    writer.write(~[first_char, ('0' as u8) + color, 'm' as u8]);
}

fn fg(ioivec::buf_writer writer, u8 color) {
    ret set_color(writer, '3' as u8, color);
}

fn bg(ioivec::buf_writer writer, u8 color) {
    ret set_color(writer, '4' as u8, color);
}
// export fg;
// export bg;

// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

The iteration traits and common implementation

*/

use cmp::{Eq, Ord};
use kinds::Copy;
use option::{None, Option, Some};
use vec;

/// A function used to initialize the elements of a sequence
pub type InitOp<T> = &fn(uint) -> T;

pub trait BaseIter<A> {
    pure fn each(&self, blk: fn(v: &A) -> bool);
    pure fn size_hint(&self) -> Option<uint>;
}

pub trait ExtendedIter<A> {
    pure fn eachi(&self, blk: fn(uint, v: &A) -> bool);
    pure fn all(&self, blk: fn(&A) -> bool) -> bool;
    pure fn any(&self, blk: fn(&A) -> bool) -> bool;
    pure fn foldl<B>(&self, b0: B, blk: fn(&B, &A) -> B) -> B;
    pure fn position(&self, f: fn(&A) -> bool) -> Option<uint>;
    pure fn map_to_vec<B>(&self, op: fn(&A) -> B) -> ~[B];
    pure fn flat_map_to_vec<B,IB: BaseIter<B>>(&self, op: fn(&A) -> IB)
        -> ~[B];
}

pub trait EqIter<A:Eq> {
    pure fn contains(&self, x: &A) -> bool;
    pure fn count(&self, x: &A) -> uint;
}

pub trait Times {
    pure fn times(&self, it: fn() -> bool);
}

pub trait CopyableIter<A:Copy> {
    pure fn filter_to_vec(&self, pred: fn(&A) -> bool) -> ~[A];
    pure fn to_vec(&self) -> ~[A];
    pure fn find(&self, p: fn(&A) -> bool) -> Option<A>;
}

pub trait CopyableOrderedIter<A:Copy Ord> {
    pure fn min(&self) -> A;
    pure fn max(&self) -> A;
}

pub trait CopyableNonstrictIter<A:Copy> {
    // Like "each", but copies out the value. If the receiver is mutated while
    // iterating over it, the semantics must not be memory-unsafe but are
    // otherwise undefined.
    pure fn each_val(&const self, f: &fn(A) -> bool);
}

// A trait for sequences that can be by imperatively pushing elements
// onto them.
pub trait Buildable<A> {
    /**
     * Builds a buildable sequence by calling a provided function with
     * an argument function that pushes an element onto the back of
     * the sequence.
     * This version takes an initial size for the sequence.
     *
     * # Arguments
     *
     * * size - A hint for an initial size of the sequence
     * * builder - A function that will construct the sequence. It receives
     *             as an argument a function that will push an element
     *             onto the sequence being constructed.
     */
     static pure fn build_sized(size: uint,
                                builder: fn(push: pure fn(A))) -> Self;
}

#[inline(always)]
pub pure fn eachi<A,IA:BaseIter<A>>(self: &IA,
                                    blk: fn(uint, &A) -> bool) {
    let mut i = 0;
    for self.each |a| {
        if !blk(i, a) { break; }
        i += 1;
    }
}

#[inline(always)]
pub pure fn all<A,IA:BaseIter<A>>(self: &IA,
                                  blk: fn(&A) -> bool) -> bool {
    for self.each |a| {
        if !blk(a) { return false; }
    }
    return true;
}

#[inline(always)]
pub pure fn any<A,IA:BaseIter<A>>(self: &IA,
                                  blk: fn(&A) -> bool) -> bool {
    for self.each |a| {
        if blk(a) { return true; }
    }
    return false;
}

#[inline(always)]
pub pure fn filter_to_vec<A:Copy,IA:BaseIter<A>>(
    self: &IA, prd: fn(&A) -> bool) -> ~[A] {
    do vec::build_sized_opt(self.size_hint()) |push| {
        for self.each |a| {
            if prd(a) { push(*a); }
        }
    }
}

#[inline(always)]
pub pure fn map_to_vec<A,B,IA:BaseIter<A>>(self: &IA,
                                           op: fn(&A) -> B)
    -> ~[B] {
    do vec::build_sized_opt(self.size_hint()) |push| {
        for self.each |a| {
            push(op(a));
        }
    }
}

#[inline(always)]
pub pure fn flat_map_to_vec<A,B,IA:BaseIter<A>,IB:BaseIter<B>>(
    self: &IA, op: fn(&A) -> IB) -> ~[B] {
    do vec::build |push| {
        for self.each |a| {
            for op(a).each |&b| {
                push(b);
            }
        }
    }
}

#[inline(always)]
pub pure fn foldl<A,B,IA:BaseIter<A>>(self: &IA, b0: B,
                                      blk: fn(&B, &A) -> B)
    -> B {
    let mut b = move b0;
    for self.each |a| {
        b = blk(&b, a);
    }
    move b
}

#[inline(always)]
pub pure fn to_vec<A:Copy,IA:BaseIter<A>>(self: &IA) -> ~[A] {
    foldl::<A,~[A],IA>(self, ~[], |r, a| vec::append(copy (*r), ~[*a]))
}

#[inline(always)]
pub pure fn contains<A:Eq,IA:BaseIter<A>>(self: &IA, x: &A) -> bool {
    for self.each |a| {
        if *a == *x { return true; }
    }
    return false;
}

#[inline(always)]
pub pure fn count<A:Eq,IA:BaseIter<A>>(self: &IA, x: &A) -> uint {
    do foldl(self, 0) |count, value| {
        if *value == *x {
            *count + 1
        } else {
            *count
        }
    }
}

#[inline(always)]
pub pure fn position<A,IA:BaseIter<A>>(self: &IA, f: fn(&A) -> bool)
    -> Option<uint>
{
    let mut i = 0;
    for self.each |a| {
        if f(a) { return Some(i); }
        i += 1;
    }
    return None;
}

// note: 'rposition' would only make sense to provide with a bidirectional
// iter interface, such as would provide "reach" in addition to "each". as is,
// it would have to be implemented with foldr, which is too inefficient.

#[inline(always)]
pub pure fn repeat(times: uint, blk: fn() -> bool) {
    let mut i = 0;
    while i < times {
        if !blk() { break }
        i += 1;
    }
}

#[inline(always)]
pub pure fn min<A:Copy Ord,IA:BaseIter<A>>(self: &IA) -> A {
    match do foldl::<A,Option<A>,IA>(self, None) |a, b| {
        match a {
          &Some(ref a_) if *a_ < *b => {
             *(move a)
          }
          _ => Some(*b)
        }
    } {
        Some(move val) => val,
        None => die!(~"min called on empty iterator")
    }
}

#[inline(always)]
pub pure fn max<A:Copy Ord,IA:BaseIter<A>>(self: &IA) -> A {
    match do foldl::<A,Option<A>,IA>(self, None) |a, b| {
        match a {
          &Some(ref a_) if *a_ > *b => {
              *(move a)
          }
          _ => Some(*b)
        }
    } {
        Some(move val) => val,
        None => die!(~"max called on empty iterator")
    }
}

#[inline(always)]
pub pure fn find<A: Copy,IA:BaseIter<A>>(self: &IA,
                                   f: fn(&A) -> bool) -> Option<A> {
    for self.each |i| {
        if f(i) { return Some(*i) }
    }
    return None;
}

// Some functions for just building

/**
 * Builds a sequence by calling a provided function with an argument
 * function that pushes an element to the back of a sequence.
 *
 * # Arguments
 *
 * * builder - A function that will construct the sequence. It receives
 *             as an argument a function that will push an element
 *             onto the sequence being constructed.
 */
#[inline(always)]
pub pure fn build<A,B: Buildable<A>>(builder: fn(push: pure fn(A)))
    -> B {
    Buildable::build_sized(4, builder)
}

/**
 * Builds a sequence by calling a provided function with an argument
 * function that pushes an element to the back of a sequence.
 * This version takes an initial size for the sequence.
 *
 * # Arguments
 *
 * * size - An option, maybe containing initial size of the sequence
 *          to reserve
 * * builder - A function that will construct the sequence. It receives
 *             as an argument a function that will push an element
 *             onto the sequence being constructed.
 */
#[inline(always)]
pub pure fn build_sized_opt<A,B: Buildable<A>>(
    size: Option<uint>,
    builder: fn(push: pure fn(A))) -> B {

    Buildable::build_sized(size.get_or_default(4), builder)
}

// Functions that combine iteration and building

/// Apply a function to each element of an iterable and return the results
#[inline(always)]
pub fn map<T,IT: BaseIter<T>,U,BU: Buildable<U>>(v: &IT, f: fn(&T) -> U)
    -> BU {
    do build_sized_opt(v.size_hint()) |push| {
        for v.each() |elem| {
            push(f(elem));
        }
    }
}

/**
 * Creates and initializes a generic sequence from a function
 *
 * Creates a generic sequence of size `n_elts` and initializes the elements
 * to the value returned by the function `op`.
 */
#[inline(always)]
pub pure fn from_fn<T,BT: Buildable<T>>(n_elts: uint,
                                        op: InitOp<T>) -> BT {
    do Buildable::build_sized(n_elts) |push| {
        let mut i: uint = 0u;
        while i < n_elts { push(op(i)); i += 1u; }
    }
}

/**
 * Creates and initializes a generic sequence with some element
 *
 * Creates an immutable vector of size `n_elts` and initializes the elements
 * to the value `t`.
 */
#[inline(always)]
pub pure fn from_elem<T: Copy,BT: Buildable<T>>(n_elts: uint,
                                                t: T) -> BT {
    do Buildable::build_sized(n_elts) |push| {
        let mut i: uint = 0;
        while i < n_elts { push(t); i += 1; }
    }
}

/// Appending two generic sequences
#[inline(always)]
pub pure fn append<T: Copy,IT: BaseIter<T>,BT: Buildable<T>>(
    lhs: &IT, rhs: &IT) -> BT {
    let size_opt = lhs.size_hint().chain_ref(
        |sz1| rhs.size_hint().map(|sz2| *sz1+*sz2));
    do build_sized_opt(size_opt) |push| {
        for lhs.each |x| { push(*x); }
        for rhs.each |x| { push(*x); }
    }
}

/// Copies a generic sequence, possibly converting it to a different
/// type of sequence.
#[inline(always)]
pub pure fn copy_seq<T: Copy,IT: BaseIter<T>,BT: Buildable<T>>(
    v: &IT) -> BT {
    do build_sized_opt(v.size_hint()) |push| {
        for v.each |x| { push(*x); }
    }
}
<commit_msg>add a ReverseIter trait<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

The iteration traits and common implementation

*/

use cmp::{Eq, Ord};
use kinds::Copy;
use option::{None, Option, Some};
use vec;

/// A function used to initialize the elements of a sequence
pub type InitOp<T> = &fn(uint) -> T;

pub trait BaseIter<A> {
    pure fn each(&self, blk: fn(v: &A) -> bool);
    pure fn size_hint(&self) -> Option<uint>;
}

pub trait ReverseIter<A>: BaseIter<A> {
    pure fn each_reverse(&self, blk: fn(&A) -> bool);
}

pub trait ExtendedIter<A> {
    pure fn eachi(&self, blk: fn(uint, v: &A) -> bool);
    pure fn all(&self, blk: fn(&A) -> bool) -> bool;
    pure fn any(&self, blk: fn(&A) -> bool) -> bool;
    pure fn foldl<B>(&self, b0: B, blk: fn(&B, &A) -> B) -> B;
    pure fn position(&self, f: fn(&A) -> bool) -> Option<uint>;
    pure fn map_to_vec<B>(&self, op: fn(&A) -> B) -> ~[B];
    pure fn flat_map_to_vec<B,IB: BaseIter<B>>(&self, op: fn(&A) -> IB)
        -> ~[B];
}

pub trait EqIter<A:Eq> {
    pure fn contains(&self, x: &A) -> bool;
    pure fn count(&self, x: &A) -> uint;
}

pub trait Times {
    pure fn times(&self, it: fn() -> bool);
}

pub trait CopyableIter<A:Copy> {
    pure fn filter_to_vec(&self, pred: fn(&A) -> bool) -> ~[A];
    pure fn to_vec(&self) -> ~[A];
    pure fn find(&self, p: fn(&A) -> bool) -> Option<A>;
}

pub trait CopyableOrderedIter<A:Copy Ord> {
    pure fn min(&self) -> A;
    pure fn max(&self) -> A;
}

pub trait CopyableNonstrictIter<A:Copy> {
    // Like "each", but copies out the value. If the receiver is mutated while
    // iterating over it, the semantics must not be memory-unsafe but are
    // otherwise undefined.
    pure fn each_val(&const self, f: &fn(A) -> bool);
}

// A trait for sequences that can be by imperatively pushing elements
// onto them.
pub trait Buildable<A> {
    /**
     * Builds a buildable sequence by calling a provided function with
     * an argument function that pushes an element onto the back of
     * the sequence.
     * This version takes an initial size for the sequence.
     *
     * # Arguments
     *
     * * size - A hint for an initial size of the sequence
     * * builder - A function that will construct the sequence. It receives
     *             as an argument a function that will push an element
     *             onto the sequence being constructed.
     */
     static pure fn build_sized(size: uint,
                                builder: fn(push: pure fn(A))) -> Self;
}

#[inline(always)]
pub pure fn eachi<A,IA:BaseIter<A>>(self: &IA,
                                    blk: fn(uint, &A) -> bool) {
    let mut i = 0;
    for self.each |a| {
        if !blk(i, a) { break; }
        i += 1;
    }
}

#[inline(always)]
pub pure fn all<A,IA:BaseIter<A>>(self: &IA,
                                  blk: fn(&A) -> bool) -> bool {
    for self.each |a| {
        if !blk(a) { return false; }
    }
    return true;
}

#[inline(always)]
pub pure fn any<A,IA:BaseIter<A>>(self: &IA,
                                  blk: fn(&A) -> bool) -> bool {
    for self.each |a| {
        if blk(a) { return true; }
    }
    return false;
}

#[inline(always)]
pub pure fn filter_to_vec<A:Copy,IA:BaseIter<A>>(
    self: &IA, prd: fn(&A) -> bool) -> ~[A] {
    do vec::build_sized_opt(self.size_hint()) |push| {
        for self.each |a| {
            if prd(a) { push(*a); }
        }
    }
}

#[inline(always)]
pub pure fn map_to_vec<A,B,IA:BaseIter<A>>(self: &IA,
                                           op: fn(&A) -> B)
    -> ~[B] {
    do vec::build_sized_opt(self.size_hint()) |push| {
        for self.each |a| {
            push(op(a));
        }
    }
}

#[inline(always)]
pub pure fn flat_map_to_vec<A,B,IA:BaseIter<A>,IB:BaseIter<B>>(
    self: &IA, op: fn(&A) -> IB) -> ~[B] {
    do vec::build |push| {
        for self.each |a| {
            for op(a).each |&b| {
                push(b);
            }
        }
    }
}

#[inline(always)]
pub pure fn foldl<A,B,IA:BaseIter<A>>(self: &IA, b0: B,
                                      blk: fn(&B, &A) -> B)
    -> B {
    let mut b = move b0;
    for self.each |a| {
        b = blk(&b, a);
    }
    move b
}

#[inline(always)]
pub pure fn to_vec<A:Copy,IA:BaseIter<A>>(self: &IA) -> ~[A] {
    foldl::<A,~[A],IA>(self, ~[], |r, a| vec::append(copy (*r), ~[*a]))
}

#[inline(always)]
pub pure fn contains<A:Eq,IA:BaseIter<A>>(self: &IA, x: &A) -> bool {
    for self.each |a| {
        if *a == *x { return true; }
    }
    return false;
}

#[inline(always)]
pub pure fn count<A:Eq,IA:BaseIter<A>>(self: &IA, x: &A) -> uint {
    do foldl(self, 0) |count, value| {
        if *value == *x {
            *count + 1
        } else {
            *count
        }
    }
}

#[inline(always)]
pub pure fn position<A,IA:BaseIter<A>>(self: &IA, f: fn(&A) -> bool)
    -> Option<uint>
{
    let mut i = 0;
    for self.each |a| {
        if f(a) { return Some(i); }
        i += 1;
    }
    return None;
}

// note: 'rposition' would only make sense to provide with a bidirectional
// iter interface, such as would provide "reach" in addition to "each". as is,
// it would have to be implemented with foldr, which is too inefficient.

#[inline(always)]
pub pure fn repeat(times: uint, blk: fn() -> bool) {
    let mut i = 0;
    while i < times {
        if !blk() { break }
        i += 1;
    }
}

#[inline(always)]
pub pure fn min<A:Copy Ord,IA:BaseIter<A>>(self: &IA) -> A {
    match do foldl::<A,Option<A>,IA>(self, None) |a, b| {
        match a {
          &Some(ref a_) if *a_ < *b => {
             *(move a)
          }
          _ => Some(*b)
        }
    } {
        Some(move val) => val,
        None => die!(~"min called on empty iterator")
    }
}

#[inline(always)]
pub pure fn max<A:Copy Ord,IA:BaseIter<A>>(self: &IA) -> A {
    match do foldl::<A,Option<A>,IA>(self, None) |a, b| {
        match a {
          &Some(ref a_) if *a_ > *b => {
              *(move a)
          }
          _ => Some(*b)
        }
    } {
        Some(move val) => val,
        None => die!(~"max called on empty iterator")
    }
}

#[inline(always)]
pub pure fn find<A: Copy,IA:BaseIter<A>>(self: &IA,
                                   f: fn(&A) -> bool) -> Option<A> {
    for self.each |i| {
        if f(i) { return Some(*i) }
    }
    return None;
}

// Some functions for just building

/**
 * Builds a sequence by calling a provided function with an argument
 * function that pushes an element to the back of a sequence.
 *
 * # Arguments
 *
 * * builder - A function that will construct the sequence. It receives
 *             as an argument a function that will push an element
 *             onto the sequence being constructed.
 */
#[inline(always)]
pub pure fn build<A,B: Buildable<A>>(builder: fn(push: pure fn(A)))
    -> B {
    Buildable::build_sized(4, builder)
}

/**
 * Builds a sequence by calling a provided function with an argument
 * function that pushes an element to the back of a sequence.
 * This version takes an initial size for the sequence.
 *
 * # Arguments
 *
 * * size - An option, maybe containing initial size of the sequence
 *          to reserve
 * * builder - A function that will construct the sequence. It receives
 *             as an argument a function that will push an element
 *             onto the sequence being constructed.
 */
#[inline(always)]
pub pure fn build_sized_opt<A,B: Buildable<A>>(
    size: Option<uint>,
    builder: fn(push: pure fn(A))) -> B {

    Buildable::build_sized(size.get_or_default(4), builder)
}

// Functions that combine iteration and building

/// Apply a function to each element of an iterable and return the results
#[inline(always)]
pub fn map<T,IT: BaseIter<T>,U,BU: Buildable<U>>(v: &IT, f: fn(&T) -> U)
    -> BU {
    do build_sized_opt(v.size_hint()) |push| {
        for v.each() |elem| {
            push(f(elem));
        }
    }
}

/**
 * Creates and initializes a generic sequence from a function
 *
 * Creates a generic sequence of size `n_elts` and initializes the elements
 * to the value returned by the function `op`.
 */
#[inline(always)]
pub pure fn from_fn<T,BT: Buildable<T>>(n_elts: uint,
                                        op: InitOp<T>) -> BT {
    do Buildable::build_sized(n_elts) |push| {
        let mut i: uint = 0u;
        while i < n_elts { push(op(i)); i += 1u; }
    }
}

/**
 * Creates and initializes a generic sequence with some element
 *
 * Creates an immutable vector of size `n_elts` and initializes the elements
 * to the value `t`.
 */
#[inline(always)]
pub pure fn from_elem<T: Copy,BT: Buildable<T>>(n_elts: uint,
                                                t: T) -> BT {
    do Buildable::build_sized(n_elts) |push| {
        let mut i: uint = 0;
        while i < n_elts { push(t); i += 1; }
    }
}

/// Appending two generic sequences
#[inline(always)]
pub pure fn append<T: Copy,IT: BaseIter<T>,BT: Buildable<T>>(
    lhs: &IT, rhs: &IT) -> BT {
    let size_opt = lhs.size_hint().chain_ref(
        |sz1| rhs.size_hint().map(|sz2| *sz1+*sz2));
    do build_sized_opt(size_opt) |push| {
        for lhs.each |x| { push(*x); }
        for rhs.each |x| { push(*x); }
    }
}

/// Copies a generic sequence, possibly converting it to a different
/// type of sequence.
#[inline(always)]
pub pure fn copy_seq<T: Copy,IT: BaseIter<T>,BT: Buildable<T>>(
    v: &IT) -> BT {
    do build_sized_opt(v.size_hint()) |push| {
        for v.each |x| { push(*x); }
    }
}
<|endoftext|>


<commit_before>use compile::Compile;
use context::Context;
use function::{CDECL, Function};
use label::Label;
use std::default::Default;
use std::io::stdio::println;
use test::Bencher;
use types::*;
use get_type = types::get;
static BENCH_SIZE: uint = 200000;
fn with_empty_func(cb:|&Context, &Function| -> ()) -> () {
    let ctx = Context::new();
    ctx.build(|| {
        let sig = Type::create_signature(CDECL, get::<()>(), &mut[]);
        let func = Function::new(&ctx, sig);
        cb(&ctx, &func)
    })
}
fn test_compile<T:Compile+Default>(kind:TypeKind) {
    with_empty_func(|_, func| {
        let pval:T = Default::default();
        let val = pval.compile(func);
        assert!(val.get_type().get_kind().contains(kind));
    })
}
#[test]
fn test_sqrt() {
    let sig = get::<fn(uint) -> uint>();
    let context = Context::new();
    let func = Function::new(&context, sig);
    let arg = func.get_param(0);
    let sqrt_arg = func.insn_sqrt(&arg);
    let sqrt_arg_ui = func.insn_convert(&sqrt_arg, get::<uint>(), false);
    func.insn_return(&sqrt_arg_ui);
    func.compile();
    func.with_closure1(|sqrt:fn(uint) -> uint| {
        assert_eq!(sqrt(64), 8);
        assert_eq!(sqrt(16), 4);
        assert_eq!(sqrt(9), 3);
        assert_eq!(sqrt(4), 2);
        assert_eq!(sqrt(1), 1);
    })
}
#[test]
fn test_struct() {
    ::init();
    let double_float_t = jit!(struct {
        "first": f64,
        "second": f64
    });
    assert_eq!(double_float_t.find_name("first"), 0);
    assert_eq!(double_float_t.find_name("second"), 1);
    let fields:Vec<String> = double_float_t.iter_fields().map(|field| field.get_name().unwrap()).collect();
    assert!(fields.as_slice() == [
        "first".into_string(),
        "second".into_string()
    ].as_slice())
    let mut iter = double_float_t.iter_fields();
    let (size, _) = iter.size_hint();
    assert_eq!(size, 2);
    assert!({
        let field:Option<String> = iter.nth(1).unwrap().get_name();
        field.unwrap().as_slice() == "second"
    });
    assert_eq!(iter.count(), 0);
}
#[test]
fn test_compiles() {
    test_compile::<()>(Void);
    test_compile::<f64>(Float64);
    test_compile::<f32>(Float32);
    test_compile::<int>(NInt);
    test_compile::<uint>(NUInt);
    test_compile::<i32>(Int);
    test_compile::<u32>(UInt);
    test_compile::<i16>(Short);
    test_compile::<u16>(UShort);
    test_compile::<i8>(SByte);
    test_compile::<u8>(UByte);
    test_compile::<bool>(SysBool);
    test_compile::<char>(SysChar);
}
#[bench]
fn bench_native_fib(b: &mut Bencher) {
    fn fib(n: uint) -> uint {
        match n {
            0     => 0,
            1 | 2 => 1,
            3     => 2,
            _     => fib(n - 1) + fib(n - 2)
        }
    }
    b.iter(|| {
        fib(BENCH_SIZE);
    });
}
#[bench]
fn bench_jit_fib(b: &mut Bencher) {
    let context = Context::new();
    let sig = get::<fn(uint) -> uint>();
    let fib = Function::new(&context, sig.clone());
    let n = fib.get_param(0);
    println("Making jump table");
    jit!(&fib, jump_table(&n, zero, one, two, three));
    println("n - 1");
    let n_m1 = n - jit!(fib, 1u);
    println("fib_m1");
    let fib_m1 = jit!(fib, call(&fib, &n_m1));
    println("fib_m2");
    let n_m2 = n - jit!(fib, 2u);
    let fib_m2 = jit!(fib, call(&fib, &n_m2));
    println("Adding");
    let result = fib_m1 + fib_m2;
    println("Returning");
    jit!(fib, return &result);
    fib.compile();
    fib.with_closure1(|fib:fn(uint) -> uint| {
        b.iter(|| {
            fib(BENCH_SIZE);
        });
    });
}<commit_msg>Update tests<commit_after>use compile::Compile;
use context::Context;
use function::{CDECL, Function};
use std::default::Default;
use test::Bencher;
use types::*;
use get_type = types::get;
fn with_empty_func(cb:|&Context, &Function| -> ()) -> () {
    let ctx = Context::new();
    ctx.build(|| {
        let sig = Type::create_signature(CDECL, get::<()>(), &mut[]);
        let func = Function::new(&ctx, sig);
        cb(&ctx, &func)
    })
}
macro_rules! test_compile(
    ($ty:ty, $test_name:ident, $kind:expr) => (
        #[test]
        fn $test_name() {
            with_empty_func(|_, func| {
                let pval:$ty = Default::default();
                let val = pval.compile(func);
                assert_eq!(val.get_type().get_kind(), $kind);
            })
        }
    );
)
#[test]
fn test_sqrt() {
    let sig = get::<fn(uint) -> uint>();
    let context = Context::new();
    let func = Function::new(&context, sig);
    let arg = func.get_param(0);
    let sqrt_arg = func.insn_sqrt(&arg);
    let sqrt_arg_ui = func.insn_convert(&sqrt_arg, get::<uint>(), false);
    func.insn_return(&sqrt_arg_ui);
    func.compile();
    func.with_closure1(|sqrt:fn(uint) -> uint| {
        assert_eq!(sqrt(64), 8);
        assert_eq!(sqrt(16), 4);
        assert_eq!(sqrt(9), 3);
        assert_eq!(sqrt(4), 2);
        assert_eq!(sqrt(1), 1);
    });
    let result:uint = func.apply1(64u);
    assert_eq!(result, 8u);
}
#[test]
fn test_struct() {
    ::init();
    let double_float_t = jit!(struct {
        "first": f64,
        "second": f64
    });
    assert_eq!(double_float_t.find_name("first").index, 0);
    assert_eq!(double_float_t.find_name("second").index, 1);
    let fields:Vec<String> = double_float_t.fields().map(|field| field.get_name().unwrap()).collect();
    assert!(fields.as_slice() == [
        "first".into_string(),
        "second".into_string()
    ].as_slice())
    let mut iter = double_float_t.fields();
    let (size, _) = iter.size_hint();
    assert_eq!(size, 2);
    assert!({
        let field:Option<String> = iter.nth(1).unwrap().get_name();
        field.unwrap().as_slice() == "second"
    });
    assert_eq!(iter.count(), 0);
}
test_compile!((), test_compile_void, Void)
test_compile!(f64, test_compile_f64, Float64)
test_compile!(f32, test_compile_f32, Float32)
test_compile!(int, test_compile_int, NInt)
test_compile!(uint, test_compile_uint, NUInt)
test_compile!(i32, test_compile_i32, Int)
test_compile!(u32, test_compile_u32, UInt)
test_compile!(i16, test_compile_i16, Short)
test_compile!(u16, test_compile_u16, UShort)
test_compile!(i8, test_compile_i8, SByte)
test_compile!(u8, test_compile_u8, UByte)
test_compile!(bool, test_compile_bool, SysBool)
test_compile!(char, test_compile_char, SysChar)<|endoftext|>