Skip to content

Commit 4418a0c

Browse files
Jonathan Woollett-LightJonathanWoollett-Light
Jonathan Woollett-Light
authored andcommitted
CPUID benchmarks
Signed-off-by: Jonathan Woollett-Light <[email protected]>
1 parent 0020d91 commit 4418a0c

File tree

6 files changed

+116
-80
lines changed

6 files changed

+116
-80
lines changed

src/cpuid/Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ t2 = ["templates"]
3333

3434
[dev-dependencies]
3535
libc = "0.2.126"
36+
# Testing template formats
3637
serde_json = "1.0.83"
3738
bincode = "1.3.3"
38-
postcard = "1.0.1"
39+
# Benchmarking
40+
criterion = "0.3"
41+
42+
[[bench]]
43+
name = "benchmark"
44+
harness = false

src/cpuid/benches/benchmark.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use criterion::{black_box, criterion_group, criterion_main, Criterion,BenchmarkId};
2+
use cpuid::{RawCpuid,Cpuid,AmdCpuid,IntelCpuid};
3+
use std::convert::{From,TryFrom};
4+
5+
pub fn conversions(c: &mut Criterion) {
6+
let kvm = kvm_ioctls::Kvm::new().unwrap();
7+
let vm = kvm.create_vm().unwrap();
8+
let kvm_cpuid = kvm
9+
.get_supported_cpuid(kvm_bindings::KVM_MAX_CPUID_ENTRIES)
10+
.unwrap();
11+
let raw_cpuid = RawCpuid::from(kvm_cpuid.clone());
12+
let cpuid = Cpuid::try_from(raw_cpuid.clone()).unwrap();
13+
let amd_cpuid = AmdCpuid::from(raw_cpuid.clone());
14+
let intel_cpuid = IntelCpuid::from(raw_cpuid.clone());
15+
16+
c.bench_function("kvm.clone()", |b| b.iter(|| kvm_cpuid.clone()));
17+
c.bench_function("raw.clone()", |b| b.iter(|| raw_cpuid.clone()));
18+
c.bench_function("intel.clone()", |b| b.iter(|| intel_cpuid.clone()));
19+
c.bench_function("amd.clone()", |b| b.iter(|| amd_cpuid.clone()));
20+
c.bench_function("cpuid.clone()", |b| b.iter(|| cpuid.clone()));
21+
22+
c.bench_function("kvm->raw", |b| b.iter(|| RawCpuid::from(kvm_cpuid.clone())));
23+
c.bench_function("raw->kvm", |b| b.iter(|| kvm_bindings::CpuId::from(raw_cpuid.clone())));
24+
c.bench_function("raw->cpuid", |b| b.iter(|| Cpuid::try_from(raw_cpuid.clone())));
25+
c.bench_function("cpuid->raw", |b| b.iter(|| RawCpuid::from(cpuid.clone())));
26+
c.bench_function("amd->raw", |b| b.iter(|| RawCpuid::from(amd_cpuid.clone())));
27+
c.bench_function("raw->amd", |b| b.iter(|| AmdCpuid::from(raw_cpuid.clone())));
28+
c.bench_function("intel->raw", |b| b.iter(|| RawCpuid::from(intel_cpuid.clone())));
29+
c.bench_function("raw->intel", |b| b.iter(|| IntelCpuid::from(raw_cpuid.clone())));
30+
}
31+
32+
criterion_group!(benches, conversions);
33+
criterion_main!(benches);

src/cpuid/src/cpuid_ffi.rs

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use serde::{Deserialize, Serialize};
2323
/// the future it may replace [`kvm_bindings::CpuId`] fully.
2424
///
2525
/// For implementation details see <https://doc.rust-lang.org/nomicon/vec/vec.html>.
26-
#[derive(Debug, Clone)]
26+
#[derive(Debug)]
2727
#[repr(C)]
2828
pub struct RawCpuid {
2929
/// Number of entries.
@@ -35,6 +35,17 @@ pub struct RawCpuid {
3535
entries: NonNull<RawCpuidEntry>,
3636
_marker: PhantomData<RawCpuidEntry>,
3737
}
38+
// TODO Make this more efficient.
39+
impl Clone for RawCpuid {
40+
fn clone(&self) -> Self {
41+
let mut new_raw_cpuid = Self::new();
42+
new_raw_cpuid.resize(self.nent as usize);
43+
for i in 0..self.nent as usize {
44+
new_raw_cpuid[i] = self[i].clone();
45+
}
46+
new_raw_cpuid
47+
}
48+
}
3849
impl serde::Serialize for RawCpuid {
3950
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
4051
where
@@ -368,11 +379,11 @@ impl fmt::LowerHex for RawCpuidEntry {
368379
}
369380
}
370381

371-
#[cfg(tests)]
382+
#[cfg(test)]
372383
mod tests {
373-
#[cfg(target_os = "linux")]
384+
use super::*;
374385
#[test]
375-
fn testing() {
386+
fn kvm_set_cpuid() {
376387
use kvm_bindings::{kvm_cpuid_entry2, KVM_MAX_CPUID_ENTRIES};
377388

378389
let kvm = kvm_ioctls::Kvm::new().unwrap();
@@ -386,33 +397,58 @@ mod tests {
386397
println!("\t{:?}", x);
387398
}
388399

389-
let cpuid = RawCpuid::from(kvm_cpuid);
400+
let cpuid = RawCpuid::from(kvm_cpuid.clone());
390401
println!("cpuid:");
391402
for x in cpuid.iter() {
392403
println!("\t{:?}", x);
393404
}
394405

395-
let kvm_cpuid2: kvm_bindings::CpuId = cpuid.into();
396-
println!("kvm_cpuid2:");
397-
for x in kvm_cpuid2.clone().as_slice() {
406+
let kvm_cpuid_2 = kvm_bindings::CpuId::from(cpuid);
407+
println!("kvm_cpuid_2:");
408+
for x in kvm_cpuid_2.clone().as_slice() {
398409
println!("\t{:?}", x);
399410
}
411+
assert_eq!(kvm_cpuid.as_slice(),kvm_cpuid_2.as_slice());
400412

401-
vcpu.set_cpuid2(&kvm_cpuid2).unwrap();
413+
vcpu.set_cpuid2(&kvm_cpuid_2).unwrap();
402414
check_err();
403415

404-
let kvm_cpuid3 = vcpu.get_cpuid2(KVM_MAX_CPUID_ENTRIES).unwrap();
416+
let kvm_cpuid_3 = vcpu.get_cpuid2(KVM_MAX_CPUID_ENTRIES).unwrap();
405417
check_err();
406-
println!("kvm_cpuid 3:");
407-
for x in kvm_cpuid3.as_slice() {
418+
println!("kvm_cpuid_3:");
419+
for x in kvm_cpuid_3.as_slice() {
408420
println!("\t{:?}", x);
409421
}
410422

411423
fn check_err() {
412424
let errno = unsafe { libc::__errno_location() };
413-
println!("errno: {}", unsafe { *errno });
425+
assert_eq!(unsafe { *errno },0);
414426
let string = std::ffi::CString::new("get_supported_cpuid").unwrap();
415427
unsafe { libc::perror(string.as_ptr()) };
416428
}
417429
}
430+
#[test]
431+
fn between_kvm() {
432+
let kvm = kvm_ioctls::Kvm::new().unwrap();
433+
let vm = kvm.create_vm().unwrap();
434+
let kvm_cpuid = kvm
435+
.get_supported_cpuid(kvm_bindings::KVM_MAX_CPUID_ENTRIES)
436+
.unwrap();
437+
let raw_cpuid = RawCpuid::from(kvm_cpuid.clone());
438+
let kvm_cpuid_2 = kvm_bindings::CpuId::from(raw_cpuid.clone());
439+
440+
assert_eq!(kvm_cpuid.as_slice(),kvm_cpuid_2.as_slice());
441+
}
442+
#[test]
443+
fn clone() {
444+
let kvm = kvm_ioctls::Kvm::new().unwrap();
445+
let vm = kvm.create_vm().unwrap();
446+
let kvm_cpuid = kvm
447+
.get_supported_cpuid(kvm_bindings::KVM_MAX_CPUID_ENTRIES)
448+
.unwrap();
449+
let raw_cpuid = RawCpuid::from(kvm_cpuid.clone());
450+
let cloned = raw_cpuid.clone();
451+
452+
assert_eq!(raw_cpuid,cloned);
453+
}
418454
}

src/cpuid/src/lib.rs

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -393,16 +393,16 @@ mod tests {
393393
.unwrap();
394394
check_err();
395395

396-
let raw_cpuid = Rawtry_from(kvm_cpuid).unwrap();
396+
let raw_cpuid = RawCpuid::try_from(kvm_cpuid).unwrap();
397397
println!("raw_cpuid:");
398398
for x in raw_cpuid.iter() {
399399
println!("\t{:x}", x);
400400
}
401-
let kvm_cpuid = try_from(raw_cpuid).unwrap();
401+
let kvm_cpuid = Cpuid::try_from(raw_cpuid).unwrap();
402402

403403
// ---------------------------------------------------------------------------------------------
404404

405-
let native_cpuid = unsafe { new().unwrap() };
405+
let native_cpuid = unsafe { Cpuid::new().unwrap() };
406406

407407
let (kvm_intel, native_intel) = (kvm_cpuid.intel().unwrap(), native_cpuid.intel().unwrap());
408408

@@ -473,16 +473,16 @@ mod tests {
473473
.unwrap();
474474
check_err();
475475

476-
let raw_cpuid = Rawtry_from(kvm_cpuid).unwrap();
476+
let raw_cpuid = RawCpuid::try_from(kvm_cpuid).unwrap();
477477
println!("raw_cpuid:");
478478
for x in raw_cpuid.iter() {
479479
println!("\t{:x}", x);
480480
}
481-
let kvm_cpuid = try_from(raw_cpuid).unwrap();
481+
let kvm_cpuid = Cpuid::try_from(raw_cpuid).unwrap();
482482

483483
// Get native CPUID
484484
// ---------------------------------------------------------------------------------------------
485-
let native_cpuid = unsafe { new().unwrap() };
485+
let native_cpuid = unsafe { Cpuid::new().unwrap() };
486486

487487
// Test them against each other
488488
// ---------------------------------------------------------------------------------------------
@@ -542,33 +542,27 @@ mod tests {
542542

543543
// Serialize CPUID
544544
// ---------------------------------------------------------------------------------------------
545-
let mut file = std::fs::File::create("./c5.metal-template-pretty-full.json").unwrap();
545+
let mut file = std::fs::File::create("./templates/c5.metal-template-pretty-full.json").unwrap();
546546
let serialized = serde_json::to_string_pretty(&native_cpuid).unwrap();
547547
file.write_all(&serialized.as_bytes()).unwrap();
548548

549549
dbg!(std::mem::size_of::<Cpuid>());
550550
dbg!(std::mem::size_of_val::<Cpuid>(&native_cpuid));
551551
// -----
552-
let mut file = std::fs::File::create("./c5.metal-template.json").unwrap();
552+
let mut file = std::fs::File::create("./templates/c5.metal-template.json").unwrap();
553553
let now = std::time::Instant::now();
554554
let serialized = serde_json::to_vec(&native_cpuid).unwrap();
555555
file.write_all(&serialized).unwrap();
556556
dbg!(now.elapsed());
557557
// -----
558-
let mut file = std::fs::File::create("./c5.metal-template.bincode").unwrap();
558+
let mut file = std::fs::File::create("./templates/c5.metal-template.bincode").unwrap();
559559
let now = std::time::Instant::now();
560560
let serialized = bincode::serialize(&native_cpuid).unwrap();
561561
file.write_all(&serialized).unwrap();
562562
dbg!(now.elapsed());
563563
// -----
564-
let mut file = std::fs::File::create("./c5.metal-template.postcard").unwrap();
565-
let now = std::time::Instant::now();
566-
let serialized: Vec<u8> = postcard::to_allocvec(&native_cpuid).unwrap();
567-
file.write_all(&serialized).unwrap();
568-
dbg!(now.elapsed());
569-
// -----
570564
let native_cpuid_clone = native_cpuid.clone();
571-
let mut file = std::fs::File::create("./c5.metal-template.binary").unwrap();
565+
let mut file = std::fs::File::create("./templates/c5.metal-template.binary").unwrap();
572566
let now = std::time::Instant::now();
573567
let mut bytes = unsafe {
574568
std::mem::transmute::<Cpuid, [u8; std::mem::size_of::<Cpuid>()]>(native_cpuid_clone)
@@ -581,22 +575,17 @@ mod tests {
581575
println!("---------------------------------------------------------------");
582576
// -----
583577
let now = std::time::Instant::now();
584-
let bytes = include_bytes!("../c5.metal-template.json");
578+
let bytes = include_bytes!("./templates/c5.metal-template.json");
585579
let deserialized: Cpuid = serde_json::from_slice(bytes).unwrap();
586580
dbg!(now.elapsed());
587581
// -----
588582
let now = std::time::Instant::now();
589-
let bytes = include_bytes!("../c5.metal-template.bincode");
583+
let bytes = include_bytes!("./templates/c5.metal-template.bincode");
590584
let deserialized: Cpuid = bincode::deserialize(bytes).unwrap();
591585
dbg!(now.elapsed());
592586
// -----
593587
let now = std::time::Instant::now();
594-
let bytes = include_bytes!("../c5.metal-template.postcard");
595-
let deserialized: Cpuid = postcard::from_bytes(bytes).unwrap();
596-
dbg!(now.elapsed());
597-
// -----
598-
let now = std::time::Instant::now();
599-
let bytes = include_bytes!("../c5.metal-template.binary");
588+
let bytes = include_bytes!("./templates/c5.metal-template.binary");
600589
let deserialized: Cpuid =
601590
unsafe { std::mem::transmute::<[u8; std::mem::size_of::<Cpuid>()], Cpuid>(*bytes) };
602591
dbg!(now.elapsed());

src/cpuid/src/main.rs

Lines changed: 0 additions & 30 deletions
This file was deleted.

src/vmm/src/builder.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -456,9 +456,7 @@ pub fn build_microvm_from_snapshot(
456456
vm_resources: &mut VmResources,
457457
) -> std::result::Result<Arc<Mutex<Vmm>>, StartMicrovmError> {
458458
use self::StartMicrovmError::*;
459-
let vcpu_count = u8::try_from(microvm_state.vcpu_states.len())
460-
.map_err(|_| MicrovmStateError::InvalidInput)
461-
.map_err(RestoreMicrovmState)?;
459+
let vcpu_count = u8::try_from(microvm_state.vcpu_states.len())?;
462460

463461
// Build Vmm.
464462
let (mut vmm, vcpus) = create_vmm_and_vcpus(
@@ -473,20 +471,24 @@ pub fn build_microvm_from_snapshot(
473471
// CPUID is supported when:
474472
// - We are on an x86 archtecture with `see` enabled and `sgx disabled`.
475473
// - We are on an x86_64 architecture with `sgx` disabled
476-
#[cfg(any(
477-
all(target_arch = "x86", target_feature = "sse", not(target_env = "sgx")),
478-
all(target_arch = "x86_64", not(target_env = "sgx"))
479-
))]
474+
#[cfg(target_arch = "x86_64")]
480475
{
476+
// TODO Remove these unwraps
481477
// Convert CPUID to better format
482-
let raw_snapshot_cpuid = cpuid::RawCpuid::from(microvm_state.vcpu_states[0].cpuid.clone());
483-
let snapshot_cpuid = cpuid::Cpuid::try_from(raw_snapshot_cpuid).expect("TODO Remove this");
484-
// This is safe as we check for CPUID support.
485-
let host_cpuid = unsafe { cpuid::Cpuid::new().unwrap() };
478+
let snapshot_cpuid = {
479+
let raw_snapshot_cpuid = cpuid::RawCpuid::from(microvm_state.vcpu_states[0].cpuid.clone());
480+
cpuid::Cpuid::try_from(raw_snapshot_cpuid).unwrap()
481+
};
482+
483+
let supported_cpuid = {
484+
let supported_kvm_cpuid = kvm_ioctls::Kvm::new().unwrap().get_supported_cpuid(kvm_bindings::KVM_MAX_CPUID_ENTRIES).unwrap();
485+
let supported_raw_cpuid = cpuid::RawCpuid::from(supported_kvm_cpuid);
486+
cpuid::Cpuid::try_from(supported_raw_cpuid).unwrap()
487+
};
486488

487489
// Previously `is_same_model` checked a variety of CPUID infomation, here we check all CPUID
488490
// infomation.
489-
let cmp = snapshot_cpuid.partial_cmp(&host_cpuid);
491+
let cmp = snapshot_cpuid.partial_cmp(&supported_cpuid);
490492
// If the host supports the CPU model in the snapshot, but they are not the same
491493
if let Some(Ordering::Greater) = cmp {
492494
// In this case we need to scale TSC.

0 commit comments

Comments
 (0)