From e866d07f55b1b3ed6e37625ef35f61ac5c10f40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 2 Feb 2017 13:57:08 +0100 Subject: [PATCH 01/11] lint/ctypes: Don't warn on non-unsized structs with PhantomData. Fixes #34798 --- src/librustc_lint/types.rs | 46 +++++++++++++++++++++++----- src/test/compile-fail/lint-ctypes.rs | 6 ++++ src/test/run-pass/issue-34798.rs | 34 ++++++++++++++++++++ 3 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 src/test/run-pass/issue-34798.rs diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 9669efa2d86b3..aff6de5a33d43 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -341,6 +341,7 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> { enum FfiResult { FfiSafe, + FfiPhantom, FfiUnsafe(&'static str), FfiBadStruct(DefId, &'static str), FfiBadUnion(DefId, &'static str), @@ -385,8 +386,11 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Check if the given type is "ffi-safe" (has a stable, well-defined /// representation which can be exported to C code). - fn check_type_for_ffi(&self, cache: &mut FxHashSet>, ty: Ty<'tcx>) -> FfiResult { + fn check_type_for_ffi(&self, + cache: &mut FxHashSet>, + ty: Ty<'tcx>) -> FfiResult { use self::FfiResult::*; + let cx = self.cx.tcx; // Protect against infinite recursion, for example @@ -399,6 +403,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match ty.sty { ty::TyAdt(def, substs) => { + if def.is_phantom_data() { + return FfiPhantom; + } match def.adt_kind() { AdtKind::Struct => { if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { @@ -407,18 +414,22 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { consider adding a #[repr(C)] attribute to the type"); } - // We can't completely trust repr(C) markings; make sure the - // fields are actually safe. if def.struct_variant().fields.is_empty() { return FfiUnsafe("found zero-size struct in foreign module, consider \ adding a member to this struct"); } + // We can't completely trust repr(C) markings; make sure the + // fields are actually safe. + let mut all_phantom = true; for field in &def.struct_variant().fields { let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); let r = self.check_type_for_ffi(cache, field_ty); match r { - FfiSafe => {} + FfiSafe => { + all_phantom = false; + } + FfiPhantom => {} FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } @@ -427,7 +438,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } } - FfiSafe + + if all_phantom { FfiPhantom } else { FfiSafe } } AdtKind::Union => { if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { @@ -436,11 +448,20 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { consider adding a #[repr(C)] attribute to the type"); } + if def.struct_variant().fields.is_empty() { + return FfiUnsafe("found zero-size union in foreign module, consider \ + adding a member to this union"); + } + + let mut all_phantom = true; for field in &def.struct_variant().fields { let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); let r = self.check_type_for_ffi(cache, field_ty); match r { - FfiSafe => {} + FfiSafe => { + all_phantom = false; + } + FfiPhantom => {} FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } @@ -449,7 +470,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } } - FfiSafe + + if all_phantom { FfiPhantom } else { FfiSafe } } AdtKind::Enum => { if def.variants.is_empty() { @@ -500,6 +522,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } + FfiPhantom => { + return FfiBadEnum(def.did, + "Found phantom data in enum variant"); + } FfiUnsafe(s) => { return FfiBadEnum(def.did, s); } @@ -593,6 +619,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match self.check_type_for_ffi(&mut FxHashSet(), ty) { FfiResult::FfiSafe => {} + FfiResult::FfiPhantom => { + self.cx.span_lint(IMPROPER_CTYPES, + sp, + &format!("found zero-sized type composed only \ + of phantom-data in a foreign-function.")); + } FfiResult::FfiUnsafe(s) => { self.cx.span_lint(IMPROPER_CTYPES, sp, s); } diff --git a/src/test/compile-fail/lint-ctypes.rs b/src/test/compile-fail/lint-ctypes.rs index ccc25b58228bd..608b1eb0872ad 100644 --- a/src/test/compile-fail/lint-ctypes.rs +++ b/src/test/compile-fail/lint-ctypes.rs @@ -29,6 +29,9 @@ pub type RustBadRet = extern fn() -> Box; pub type CVoidRet = (); pub struct Foo; +#[repr(C)] +pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData); + extern { pub fn ptr_type1(size: *const Foo); //~ ERROR: found struct without pub fn ptr_type2(size: *const Foo); //~ ERROR: found struct without @@ -40,6 +43,9 @@ extern { pub fn tuple_type(p: (i32, i32)); //~ ERROR found Rust tuple type pub fn tuple_type2(p: I32Pair); //~ ERROR found Rust tuple type pub fn zero_size(p: ZeroSize); //~ ERROR found zero-size struct + pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR found zero-sized type + pub fn zero_size_phantom_toplevel() + -> ::std::marker::PhantomData; //~ ERROR: found zero-sized type pub fn fn_type(p: RustFn); //~ ERROR found function pointer with Rust pub fn fn_type2(p: fn()); //~ ERROR found function pointer with Rust pub fn fn_contained(p: RustBadRet); //~ ERROR: found struct without diff --git a/src/test/run-pass/issue-34798.rs b/src/test/run-pass/issue-34798.rs new file mode 100644 index 0000000000000..e217d07ed725d --- /dev/null +++ b/src/test/run-pass/issue-34798.rs @@ -0,0 +1,34 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![forbid(improper_ctypes)] +#![allow(dead_code)] + +#[repr(C)] +pub struct Foo { + size: u8, + __value: ::std::marker::PhantomData, +} + +#[repr(C)] +pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData); + +#[repr(C)] +pub struct Bar { + size: u8, + baz: ZeroSizeWithPhantomData, +} + +extern "C" { + pub fn bar(_: *mut Foo, _: *mut Bar); +} + +fn main() { +} From b4e6f70edac44c87eb71903d96d47d7fe48c37d8 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Sat, 4 Feb 2017 23:51:10 +1300 Subject: [PATCH 02/11] [llvm] Use 32-bits for alignment LLVM 4.0 changes this. This change is fine to make for LLVM 3.9 as we won't have alignments greater than 2^32-1. --- src/librustc_llvm/ffi.rs | 20 ++++++++++---------- src/librustc_trans/debuginfo/metadata.rs | 18 +++++++++--------- src/librustc_trans/debuginfo/mod.rs | 2 +- src/rustllvm/RustWrapper.cpp | 20 ++++++++++---------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 58b2017ceb66e..a5eae96f133ea 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -1363,14 +1363,14 @@ extern "C" { pub fn LLVMRustDIBuilderCreateBasicType(Builder: DIBuilderRef, Name: *const c_char, SizeInBits: u64, - AlignInBits: u64, + AlignInBits: u32, Encoding: c_uint) -> DIBasicType; pub fn LLVMRustDIBuilderCreatePointerType(Builder: DIBuilderRef, PointeeTy: DIType, SizeInBits: u64, - AlignInBits: u64, + AlignInBits: u32, Name: *const c_char) -> DIDerivedType; @@ -1380,7 +1380,7 @@ extern "C" { File: DIFile, LineNumber: c_uint, SizeInBits: u64, - AlignInBits: u64, + AlignInBits: u32, Flags: DIFlags, DerivedFrom: DIType, Elements: DIArray, @@ -1395,7 +1395,7 @@ extern "C" { File: DIFile, LineNo: c_uint, SizeInBits: u64, - AlignInBits: u64, + AlignInBits: u32, OffsetInBits: u64, Flags: DIFlags, Ty: DIType) @@ -1423,7 +1423,7 @@ extern "C" { isLocalToUnit: bool, Val: ValueRef, Decl: DIDescriptor, - AlignInBits: u64) + AlignInBits: u32) -> DIGlobalVariable; pub fn LLVMRustDIBuilderCreateVariable(Builder: DIBuilderRef, @@ -1436,19 +1436,19 @@ extern "C" { AlwaysPreserve: bool, Flags: DIFlags, ArgNo: c_uint, - AlignInBits: u64) + AlignInBits: u32) -> DIVariable; pub fn LLVMRustDIBuilderCreateArrayType(Builder: DIBuilderRef, Size: u64, - AlignInBits: u64, + AlignInBits: u32, Ty: DIType, Subscripts: DIArray) -> DIType; pub fn LLVMRustDIBuilderCreateVectorType(Builder: DIBuilderRef, Size: u64, - AlignInBits: u64, + AlignInBits: u32, Ty: DIType, Subscripts: DIArray) -> DIType; @@ -1483,7 +1483,7 @@ extern "C" { File: DIFile, LineNumber: c_uint, SizeInBits: u64, - AlignInBits: u64, + AlignInBits: u32, Elements: DIArray, ClassType: DIType) -> DIType; @@ -1494,7 +1494,7 @@ extern "C" { File: DIFile, LineNumber: c_uint, SizeInBits: u64, - AlignInBits: u64, + AlignInBits: u32, Flags: DIFlags, Elements: DIArray, RunTimeLang: c_uint, diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index b7e319f2de434..69a2e67366c13 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -299,7 +299,7 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, llvm::LLVMRustDIBuilderCreateArrayType( DIB(cx), bytes_to_bits(array_size_in_bytes), - bytes_to_bits(element_type_align), + bytes_to_bits(element_type_align) as u32, element_type_metadata, subscripts) }; @@ -730,7 +730,7 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, DIB(cx), name.as_ptr(), bytes_to_bits(size), - bytes_to_bits(align), + bytes_to_bits(align) as u32, encoding) }; @@ -750,7 +750,7 @@ fn pointer_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, DIB(cx), pointee_type_metadata, bytes_to_bits(pointer_size), - bytes_to_bits(pointer_align), + bytes_to_bits(pointer_align) as u32, name.as_ptr()) }; return ptr_metadata; @@ -1504,7 +1504,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, file_metadata, UNKNOWN_LINE_NUMBER, bytes_to_bits(discriminant_size), - bytes_to_bits(discriminant_align), + bytes_to_bits(discriminant_align) as u32, create_DIArray(DIB(cx), &enumerators_metadata), discriminant_base_type_metadata) }; @@ -1546,7 +1546,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, file_metadata, UNKNOWN_LINE_NUMBER, bytes_to_bits(enum_type_size), - bytes_to_bits(enum_type_align), + bytes_to_bits(enum_type_align) as u32, DIFlags::FlagZero, ptr::null_mut(), 0, // RuntimeLang @@ -1648,7 +1648,7 @@ fn set_members_of_composite_type(cx: &CrateContext, unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, bytes_to_bits(member_size), - bytes_to_bits(member_align), + bytes_to_bits(member_align) as u32, bytes_to_bits(member_offset), member_description.flags, member_description.type_metadata) @@ -1691,7 +1691,7 @@ fn create_struct_stub(cx: &CrateContext, unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, bytes_to_bits(struct_size), - bytes_to_bits(struct_align), + bytes_to_bits(struct_align) as u32, DIFlags::FlagZero, ptr::null_mut(), empty_array, @@ -1728,7 +1728,7 @@ fn create_union_stub(cx: &CrateContext, unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, bytes_to_bits(union_size), - bytes_to_bits(union_align), + bytes_to_bits(union_align) as u32, DIFlags::FlagZero, empty_array, 0, // RuntimeLang @@ -1783,7 +1783,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, is_local_to_unit, global, ptr::null_mut(), - global_align as u64, + global_align as u32, ); } } diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index e9468e56637d2..6765cf0377639 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -464,7 +464,7 @@ pub fn declare_local<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, cx.sess().opts.optimize != config::OptLevel::No, DIFlags::FlagZero, argument_index, - align as u64, + align as u32, ) }; source_loc::set_debug_location(bcx, diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 34ee7d552f346..56f18ec5a0dbd 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -513,7 +513,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateFunction( extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateBasicType(LLVMRustDIBuilderRef Builder, const char *Name, - uint64_t SizeInBits, uint64_t AlignInBits, + uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding) { return wrap(Builder->createBasicType(Name, SizeInBits, #if LLVM_VERSION_LE(3, 9) @@ -524,7 +524,7 @@ LLVMRustDIBuilderCreateBasicType(LLVMRustDIBuilderRef Builder, const char *Name, extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreatePointerType( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef PointeeTy, - uint64_t SizeInBits, uint64_t AlignInBits, const char *Name) { + uint64_t SizeInBits, uint32_t AlignInBits, const char *Name) { return wrap(Builder->createPointerType(unwrapDI(PointeeTy), SizeInBits, AlignInBits, Name)); } @@ -532,7 +532,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreatePointerType( extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStructType( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, const char *Name, LLVMRustMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, - uint64_t AlignInBits, LLVMRustDIFlags Flags, + uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMRustMetadataRef DerivedFrom, LLVMRustMetadataRef Elements, unsigned RunTimeLang, LLVMRustMetadataRef VTableHolder, const char *UniqueId) { @@ -546,7 +546,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStructType( extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateMemberType( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, const char *Name, LLVMRustMetadataRef File, unsigned LineNo, uint64_t SizeInBits, - uint64_t AlignInBits, uint64_t OffsetInBits, LLVMRustDIFlags Flags, + uint32_t AlignInBits, uint64_t OffsetInBits, LLVMRustDIFlags Flags, LLVMRustMetadataRef Ty) { return wrap(Builder->createMemberType(unwrapDI(Scope), Name, unwrapDI(File), LineNo, @@ -573,7 +573,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Context, const char *Name, const char *LinkageName, LLVMRustMetadataRef File, unsigned LineNo, LLVMRustMetadataRef Ty, bool IsLocalToUnit, LLVMValueRef V, - LLVMRustMetadataRef Decl = nullptr, uint64_t AlignInBits = 0) { + LLVMRustMetadataRef Decl = nullptr, uint32_t AlignInBits = 0) { Constant *InitVal = cast(unwrap(V)); #if LLVM_VERSION_GE(4, 0) @@ -608,7 +608,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable( LLVMRustDIBuilderRef Builder, unsigned Tag, LLVMRustMetadataRef Scope, const char *Name, LLVMRustMetadataRef File, unsigned LineNo, LLVMRustMetadataRef Ty, bool AlwaysPreserve, LLVMRustDIFlags Flags, - unsigned ArgNo, uint64_t AlignInBits) { + unsigned ArgNo, uint32_t AlignInBits) { #if LLVM_VERSION_GE(3, 8) if (Tag == 0x100) { // DW_TAG_auto_variable return wrap(Builder->createAutoVariable( @@ -633,7 +633,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable( extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateArrayType(LLVMRustDIBuilderRef Builder, uint64_t Size, - uint64_t AlignInBits, LLVMRustMetadataRef Ty, + uint32_t AlignInBits, LLVMRustMetadataRef Ty, LLVMRustMetadataRef Subscripts) { return wrap( Builder->createArrayType(Size, AlignInBits, unwrapDI(Ty), @@ -642,7 +642,7 @@ LLVMRustDIBuilderCreateArrayType(LLVMRustDIBuilderRef Builder, uint64_t Size, extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVectorType(LLVMRustDIBuilderRef Builder, uint64_t Size, - uint64_t AlignInBits, LLVMRustMetadataRef Ty, + uint32_t AlignInBits, LLVMRustMetadataRef Ty, LLVMRustMetadataRef Subscripts) { return wrap( Builder->createVectorType(Size, AlignInBits, unwrapDI(Ty), @@ -683,7 +683,7 @@ LLVMRustDIBuilderCreateEnumerator(LLVMRustDIBuilderRef Builder, extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateEnumerationType( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, const char *Name, LLVMRustMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, - uint64_t AlignInBits, LLVMRustMetadataRef Elements, + uint32_t AlignInBits, LLVMRustMetadataRef Elements, LLVMRustMetadataRef ClassTy) { return wrap(Builder->createEnumerationType( unwrapDI(Scope), Name, unwrapDI(File), LineNumber, @@ -694,7 +694,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateEnumerationType( extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateUnionType( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Scope, const char *Name, LLVMRustMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, - uint64_t AlignInBits, LLVMRustDIFlags Flags, LLVMRustMetadataRef Elements, + uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMRustMetadataRef Elements, unsigned RunTimeLang, const char *UniqueId) { return wrap(Builder->createUnionType( unwrapDI(Scope), Name, unwrapDI(File), LineNumber, From c7bea760917dcbff5025ac7b5dc62f54308c5530 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Sun, 5 Feb 2017 20:19:27 +1300 Subject: [PATCH 03/11] Use u32 for alignments instead of u64 --- src/librustc_trans/debuginfo/metadata.rs | 18 +++++++++--------- src/librustc_trans/debuginfo/mod.rs | 2 +- src/librustc_trans/debuginfo/utils.rs | 11 +++++++---- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 69a2e67366c13..29d04785d6fe1 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -299,7 +299,7 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, llvm::LLVMRustDIBuilderCreateArrayType( DIB(cx), bytes_to_bits(array_size_in_bytes), - bytes_to_bits(element_type_align) as u32, + bytes_to_bits(element_type_align), element_type_metadata, subscripts) }; @@ -730,7 +730,7 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, DIB(cx), name.as_ptr(), bytes_to_bits(size), - bytes_to_bits(align) as u32, + bytes_to_bits(align), encoding) }; @@ -750,7 +750,7 @@ fn pointer_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, DIB(cx), pointee_type_metadata, bytes_to_bits(pointer_size), - bytes_to_bits(pointer_align) as u32, + bytes_to_bits(pointer_align), name.as_ptr()) }; return ptr_metadata; @@ -1504,7 +1504,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, file_metadata, UNKNOWN_LINE_NUMBER, bytes_to_bits(discriminant_size), - bytes_to_bits(discriminant_align) as u32, + bytes_to_bits(discriminant_align), create_DIArray(DIB(cx), &enumerators_metadata), discriminant_base_type_metadata) }; @@ -1546,7 +1546,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, file_metadata, UNKNOWN_LINE_NUMBER, bytes_to_bits(enum_type_size), - bytes_to_bits(enum_type_align) as u32, + bytes_to_bits(enum_type_align), DIFlags::FlagZero, ptr::null_mut(), 0, // RuntimeLang @@ -1648,7 +1648,7 @@ fn set_members_of_composite_type(cx: &CrateContext, unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, bytes_to_bits(member_size), - bytes_to_bits(member_align) as u32, + bytes_to_bits(member_align), bytes_to_bits(member_offset), member_description.flags, member_description.type_metadata) @@ -1691,7 +1691,7 @@ fn create_struct_stub(cx: &CrateContext, unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, bytes_to_bits(struct_size), - bytes_to_bits(struct_align) as u32, + bytes_to_bits(struct_align), DIFlags::FlagZero, ptr::null_mut(), empty_array, @@ -1728,7 +1728,7 @@ fn create_union_stub(cx: &CrateContext, unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, bytes_to_bits(union_size), - bytes_to_bits(union_align) as u32, + bytes_to_bits(union_align), DIFlags::FlagZero, empty_array, 0, // RuntimeLang @@ -1783,7 +1783,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, is_local_to_unit, global, ptr::null_mut(), - global_align as u32, + global_align, ); } } diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 6765cf0377639..6a8fc904366dc 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -464,7 +464,7 @@ pub fn declare_local<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, cx.sess().opts.optimize != config::OptLevel::No, DIFlags::FlagZero, argument_index, - align as u32, + align, ) }; source_loc::set_debug_location(bcx, diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index 8d634c0e292ad..15a1c990aadc6 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -24,6 +24,8 @@ use type_::Type; use syntax_pos::{self, Span}; use syntax::ast; +use std::ops; + pub fn is_node_local_to_unit(cx: &CrateContext, node_id: ast::NodeId) -> bool { // The is_local_to_unit flag indicates whether a function is local to the @@ -49,12 +51,13 @@ pub fn span_start(cx: &CrateContext, span: Span) -> syntax_pos::Loc { cx.sess().codemap().lookup_char_pos(span.lo) } -pub fn size_and_align_of(cx: &CrateContext, llvm_type: Type) -> (u64, u64) { - (machine::llsize_of_alloc(cx, llvm_type), machine::llalign_of_min(cx, llvm_type) as u64) +pub fn size_and_align_of(cx: &CrateContext, llvm_type: Type) -> (u64, u32) { + (machine::llsize_of_alloc(cx, llvm_type), machine::llalign_of_min(cx, llvm_type)) } -pub fn bytes_to_bits(bytes: u64) -> u64 { - bytes * 8 +pub fn bytes_to_bits(bytes: T) -> T + where T: ops::Mul + From { + bytes * 8u8.into() } #[inline] From 7c8c45e76225ecf0a219e994a9a10d71d0b9a4e4 Mon Sep 17 00:00:00 2001 From: Son Date: Mon, 6 Feb 2017 21:38:47 +1100 Subject: [PATCH 04/11] Extract collections benchmarks to libcollections/benches And libcore/benches --- src/libcollections/Cargo.toml | 7 +- .../benches/btree/map.rs} | 71 ++- src/libcollections/benches/btree/mod.rs | 11 + src/libcollections/benches/lib.rs | 24 + src/libcollections/benches/linked_list.rs | 87 ++++ src/libcollections/benches/slice.rs | 280 ++++++++++ src/libcollections/benches/str.rs | 298 +++++++++++ src/libcollections/benches/string.rs | 134 +++++ src/libcollections/benches/vec.rs | 492 ++++++++++++++++++ src/libcollections/benches/vec_deque.rs | 57 ++ src/libcollectionstest/btree/map.rs | 49 -- src/libcollectionstest/lib.rs | 4 - src/libcollectionstest/linked_list.rs | 77 --- src/libcollectionstest/slice.rs | 273 ---------- src/libcollectionstest/str.rs | 291 ----------- src/libcollectionstest/string.rs | 125 ----- src/libcollectionstest/vec.rs | 483 ----------------- src/libcollectionstest/vec_deque.rs | 47 -- src/libcore/Cargo.toml | 4 +- src/libcore/{bench => benches}/any.rs | 0 src/libcore/{bench => benches}/hash/mod.rs | 0 src/libcore/{bench => benches}/hash/sip.rs | 0 src/libcore/{bench => benches}/iter.rs | 0 src/libcore/{bench => benches}/lib.rs | 0 src/libcore/{bench => benches}/mem.rs | 0 .../{bench => benches}/num/dec2flt/mod.rs | 0 .../{bench => benches}/num/flt2dec/mod.rs | 0 .../num/flt2dec/strategy/dragon.rs | 0 .../num/flt2dec/strategy/grisu.rs | 0 src/libcore/{bench => benches}/num/mod.rs | 0 src/libcore/{bench => benches}/ops.rs | 0 31 files changed, 1442 insertions(+), 1372 deletions(-) rename src/{libcollectionstest/bench.rs => libcollections/benches/btree/map.rs} (66%) create mode 100644 src/libcollections/benches/btree/mod.rs create mode 100644 src/libcollections/benches/lib.rs create mode 100644 src/libcollections/benches/linked_list.rs create mode 100644 src/libcollections/benches/slice.rs create mode 100644 src/libcollections/benches/str.rs create mode 100644 src/libcollections/benches/string.rs create mode 100644 src/libcollections/benches/vec.rs create mode 100644 src/libcollections/benches/vec_deque.rs rename src/libcore/{bench => benches}/any.rs (100%) rename src/libcore/{bench => benches}/hash/mod.rs (100%) rename src/libcore/{bench => benches}/hash/sip.rs (100%) rename src/libcore/{bench => benches}/iter.rs (100%) rename src/libcore/{bench => benches}/lib.rs (100%) rename src/libcore/{bench => benches}/mem.rs (100%) rename src/libcore/{bench => benches}/num/dec2flt/mod.rs (100%) rename src/libcore/{bench => benches}/num/flt2dec/mod.rs (100%) rename src/libcore/{bench => benches}/num/flt2dec/strategy/dragon.rs (100%) rename src/libcore/{bench => benches}/num/flt2dec/strategy/grisu.rs (100%) rename src/libcore/{bench => benches}/num/mod.rs (100%) rename src/libcore/{bench => benches}/ops.rs (100%) diff --git a/src/libcollections/Cargo.toml b/src/libcollections/Cargo.toml index 186ba6e8f2112..02b2171a224d0 100644 --- a/src/libcollections/Cargo.toml +++ b/src/libcollections/Cargo.toml @@ -16,7 +16,6 @@ std_unicode = { path = "../libstd_unicode" } name = "collectionstest" path = "../libcollectionstest/lib.rs" -# FIXME: need to extract benchmarks to separate crate -#[[bench]] -#name = "collectionstest" -#path = "../libcollectionstest/lib.rs" +[[bench]] +name = "collectionsbenches" +path = "../libcollections/benches/lib.rs" diff --git a/src/libcollectionstest/bench.rs b/src/libcollections/benches/btree/map.rs similarity index 66% rename from src/libcollectionstest/bench.rs rename to src/libcollections/benches/btree/map.rs index 4e150d4a22234..744afb991b00e 100644 --- a/src/libcollectionstest/bench.rs +++ b/src/libcollections/benches/btree/map.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,13 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. + +use std::iter::Iterator; +use std::vec::Vec; +use std::collections::BTreeMap; +use std::__rand::{Rng, thread_rng}; +use test::{Bencher, black_box}; + macro_rules! map_insert_rand_bench { ($name: ident, $n: expr, $map: ident) => ( #[bench] - pub fn $name(b: &mut ::test::Bencher) { - use std::__rand::{thread_rng, Rng}; - use test::black_box; - + pub fn $name(b: &mut Bencher) { let n: usize = $n; let mut map = $map::new(); // setup @@ -39,9 +43,7 @@ macro_rules! map_insert_rand_bench { macro_rules! map_insert_seq_bench { ($name: ident, $n: expr, $map: ident) => ( #[bench] - pub fn $name(b: &mut ::test::Bencher) { - use test::black_box; - + pub fn $name(b: &mut Bencher) { let mut map = $map::new(); let n: usize = $n; // setup @@ -64,12 +66,7 @@ macro_rules! map_insert_seq_bench { macro_rules! map_find_rand_bench { ($name: ident, $n: expr, $map: ident) => ( #[bench] - pub fn $name(b: &mut ::test::Bencher) { - use std::iter::Iterator; - use std::__rand::{thread_rng, Rng}; - use std::vec::Vec; - use test::black_box; - + pub fn $name(b: &mut Bencher) { let mut map = $map::new(); let n: usize = $n; @@ -97,9 +94,7 @@ macro_rules! map_find_rand_bench { macro_rules! map_find_seq_bench { ($name: ident, $n: expr, $map: ident) => ( #[bench] - pub fn $name(b: &mut ::test::Bencher) { - use test::black_box; - + pub fn $name(b: &mut Bencher) { let mut map = $map::new(); let n: usize = $n; @@ -118,3 +113,45 @@ macro_rules! map_find_seq_bench { } ) } + +map_insert_rand_bench!{insert_rand_100, 100, BTreeMap} +map_insert_rand_bench!{insert_rand_10_000, 10_000, BTreeMap} + +map_insert_seq_bench!{insert_seq_100, 100, BTreeMap} +map_insert_seq_bench!{insert_seq_10_000, 10_000, BTreeMap} + +map_find_rand_bench!{find_rand_100, 100, BTreeMap} +map_find_rand_bench!{find_rand_10_000, 10_000, BTreeMap} + +map_find_seq_bench!{find_seq_100, 100, BTreeMap} +map_find_seq_bench!{find_seq_10_000, 10_000, BTreeMap} + +fn bench_iter(b: &mut Bencher, size: i32) { + let mut map = BTreeMap::::new(); + let mut rng = thread_rng(); + + for _ in 0..size { + map.insert(rng.gen(), rng.gen()); + } + + b.iter(|| { + for entry in &map { + black_box(entry); + } + }); +} + +#[bench] +pub fn iter_20(b: &mut Bencher) { + bench_iter(b, 20); +} + +#[bench] +pub fn iter_1000(b: &mut Bencher) { + bench_iter(b, 1000); +} + +#[bench] +pub fn iter_100000(b: &mut Bencher) { + bench_iter(b, 100000); +} diff --git a/src/libcollections/benches/btree/mod.rs b/src/libcollections/benches/btree/mod.rs new file mode 100644 index 0000000000000..f436b0ac0c037 --- /dev/null +++ b/src/libcollections/benches/btree/mod.rs @@ -0,0 +1,11 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod map; diff --git a/src/libcollections/benches/lib.rs b/src/libcollections/benches/lib.rs new file mode 100644 index 0000000000000..1a21db5e344e3 --- /dev/null +++ b/src/libcollections/benches/lib.rs @@ -0,0 +1,24 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(warnings)] + +#![feature(rand)] +#![feature(test)] + +extern crate test; + +mod btree; +mod linked_list; +mod string; +mod str; +mod slice; +mod vec; +mod vec_deque; diff --git a/src/libcollections/benches/linked_list.rs b/src/libcollections/benches/linked_list.rs new file mode 100644 index 0000000000000..bbac44553f18a --- /dev/null +++ b/src/libcollections/benches/linked_list.rs @@ -0,0 +1,87 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::LinkedList; +use test::Bencher; + +#[bench] +fn bench_collect_into(b: &mut Bencher) { + let v = &[0; 64]; + b.iter(|| { + let _: LinkedList<_> = v.iter().cloned().collect(); + }) +} + +#[bench] +fn bench_push_front(b: &mut Bencher) { + let mut m: LinkedList<_> = LinkedList::new(); + b.iter(|| { + m.push_front(0); + }) +} + +#[bench] +fn bench_push_back(b: &mut Bencher) { + let mut m: LinkedList<_> = LinkedList::new(); + b.iter(|| { + m.push_back(0); + }) +} + +#[bench] +fn bench_push_back_pop_back(b: &mut Bencher) { + let mut m: LinkedList<_> = LinkedList::new(); + b.iter(|| { + m.push_back(0); + m.pop_back(); + }) +} + +#[bench] +fn bench_push_front_pop_front(b: &mut Bencher) { + let mut m: LinkedList<_> = LinkedList::new(); + b.iter(|| { + m.push_front(0); + m.pop_front(); + }) +} + +#[bench] +fn bench_iter(b: &mut Bencher) { + let v = &[0; 128]; + let m: LinkedList<_> = v.iter().cloned().collect(); + b.iter(|| { + assert!(m.iter().count() == 128); + }) +} +#[bench] +fn bench_iter_mut(b: &mut Bencher) { + let v = &[0; 128]; + let mut m: LinkedList<_> = v.iter().cloned().collect(); + b.iter(|| { + assert!(m.iter_mut().count() == 128); + }) +} +#[bench] +fn bench_iter_rev(b: &mut Bencher) { + let v = &[0; 128]; + let m: LinkedList<_> = v.iter().cloned().collect(); + b.iter(|| { + assert!(m.iter().rev().count() == 128); + }) +} +#[bench] +fn bench_iter_mut_rev(b: &mut Bencher) { + let v = &[0; 128]; + let mut m: LinkedList<_> = v.iter().cloned().collect(); + b.iter(|| { + assert!(m.iter_mut().rev().count() == 128); + }) +} diff --git a/src/libcollections/benches/slice.rs b/src/libcollections/benches/slice.rs new file mode 100644 index 0000000000000..eb4b76509f913 --- /dev/null +++ b/src/libcollections/benches/slice.rs @@ -0,0 +1,280 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::{mem, ptr}; +use std::__rand::{Rng, thread_rng}; + +use test::{Bencher, black_box}; + +#[bench] +fn iterator(b: &mut Bencher) { + // peculiar numbers to stop LLVM from optimising the summation + // out. + let v: Vec<_> = (0..100).map(|i| i ^ (i << 1) ^ (i >> 1)).collect(); + + b.iter(|| { + let mut sum = 0; + for x in &v { + sum += *x; + } + // sum == 11806, to stop dead code elimination. + if sum == 0 { + panic!() + } + }) +} + +#[bench] +fn mut_iterator(b: &mut Bencher) { + let mut v = vec![0; 100]; + + b.iter(|| { + let mut i = 0; + for x in &mut v { + *x = i; + i += 1; + } + }) +} + +#[bench] +fn concat(b: &mut Bencher) { + let xss: Vec> = (0..100).map(|i| (0..i).collect()).collect(); + b.iter(|| { + xss.concat(); + }); +} + +#[bench] +fn join(b: &mut Bencher) { + let xss: Vec> = (0..100).map(|i| (0..i).collect()).collect(); + b.iter(|| xss.join(&0)); +} + +#[bench] +fn push(b: &mut Bencher) { + let mut vec = Vec::::new(); + b.iter(|| { + vec.push(0); + black_box(&vec); + }); +} + +#[bench] +fn starts_with_same_vector(b: &mut Bencher) { + let vec: Vec<_> = (0..100).collect(); + b.iter(|| vec.starts_with(&vec)) +} + +#[bench] +fn starts_with_single_element(b: &mut Bencher) { + let vec: Vec<_> = vec![0]; + b.iter(|| vec.starts_with(&vec)) +} + +#[bench] +fn starts_with_diff_one_element_at_end(b: &mut Bencher) { + let vec: Vec<_> = (0..100).collect(); + let mut match_vec: Vec<_> = (0..99).collect(); + match_vec.push(0); + b.iter(|| vec.starts_with(&match_vec)) +} + +#[bench] +fn ends_with_same_vector(b: &mut Bencher) { + let vec: Vec<_> = (0..100).collect(); + b.iter(|| vec.ends_with(&vec)) +} + +#[bench] +fn ends_with_single_element(b: &mut Bencher) { + let vec: Vec<_> = vec![0]; + b.iter(|| vec.ends_with(&vec)) +} + +#[bench] +fn ends_with_diff_one_element_at_beginning(b: &mut Bencher) { + let vec: Vec<_> = (0..100).collect(); + let mut match_vec: Vec<_> = (0..100).collect(); + match_vec[0] = 200; + b.iter(|| vec.starts_with(&match_vec)) +} + +#[bench] +fn contains_last_element(b: &mut Bencher) { + let vec: Vec<_> = (0..100).collect(); + b.iter(|| vec.contains(&99)) +} + +#[bench] +fn zero_1kb_from_elem(b: &mut Bencher) { + b.iter(|| vec![0u8; 1024]); +} + +#[bench] +fn zero_1kb_set_memory(b: &mut Bencher) { + b.iter(|| { + let mut v = Vec::::with_capacity(1024); + unsafe { + let vp = v.as_mut_ptr(); + ptr::write_bytes(vp, 0, 1024); + v.set_len(1024); + } + v + }); +} + +#[bench] +fn zero_1kb_loop_set(b: &mut Bencher) { + b.iter(|| { + let mut v = Vec::::with_capacity(1024); + unsafe { + v.set_len(1024); + } + for i in 0..1024 { + v[i] = 0; + } + }); +} + +#[bench] +fn zero_1kb_mut_iter(b: &mut Bencher) { + b.iter(|| { + let mut v = Vec::::with_capacity(1024); + unsafe { + v.set_len(1024); + } + for x in &mut v { + *x = 0; + } + v + }); +} + +#[bench] +fn random_inserts(b: &mut Bencher) { + let mut rng = thread_rng(); + b.iter(|| { + let mut v = vec![(0, 0); 30]; + for _ in 0..100 { + let l = v.len(); + v.insert(rng.gen::() % (l + 1), (1, 1)); + } + }) +} +#[bench] +fn random_removes(b: &mut Bencher) { + let mut rng = thread_rng(); + b.iter(|| { + let mut v = vec![(0, 0); 130]; + for _ in 0..100 { + let l = v.len(); + v.remove(rng.gen::() % l); + } + }) +} + +fn gen_ascending(len: usize) -> Vec { + (0..len as u64).collect() +} + +fn gen_descending(len: usize) -> Vec { + (0..len as u64).rev().collect() +} + +fn gen_random(len: usize) -> Vec { + let mut rng = thread_rng(); + rng.gen_iter::().take(len).collect() +} + +fn gen_mostly_ascending(len: usize) -> Vec { + let mut rng = thread_rng(); + let mut v = gen_ascending(len); + for _ in (0usize..).take_while(|x| x * x <= len) { + let x = rng.gen::() % len; + let y = rng.gen::() % len; + v.swap(x, y); + } + v +} + +fn gen_mostly_descending(len: usize) -> Vec { + let mut rng = thread_rng(); + let mut v = gen_descending(len); + for _ in (0usize..).take_while(|x| x * x <= len) { + let x = rng.gen::() % len; + let y = rng.gen::() % len; + v.swap(x, y); + } + v +} + +fn gen_big_random(len: usize) -> Vec<[u64; 16]> { + let mut rng = thread_rng(); + rng.gen_iter().map(|x| [x; 16]).take(len).collect() +} + +fn gen_big_ascending(len: usize) -> Vec<[u64; 16]> { + (0..len as u64).map(|x| [x; 16]).take(len).collect() +} + +fn gen_big_descending(len: usize) -> Vec<[u64; 16]> { + (0..len as u64).rev().map(|x| [x; 16]).take(len).collect() +} + +macro_rules! sort_bench { + ($name:ident, $gen:expr, $len:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + b.iter(|| $gen($len).sort()); + b.bytes = $len * mem::size_of_val(&$gen(1)[0]) as u64; + } + } +} + +sort_bench!(sort_small_random, gen_random, 10); +sort_bench!(sort_small_ascending, gen_ascending, 10); +sort_bench!(sort_small_descending, gen_descending, 10); + +sort_bench!(sort_small_big_random, gen_big_random, 10); +sort_bench!(sort_small_big_ascending, gen_big_ascending, 10); +sort_bench!(sort_small_big_descending, gen_big_descending, 10); + +sort_bench!(sort_medium_random, gen_random, 100); +sort_bench!(sort_medium_ascending, gen_ascending, 100); +sort_bench!(sort_medium_descending, gen_descending, 100); + +sort_bench!(sort_large_random, gen_random, 10000); +sort_bench!(sort_large_ascending, gen_ascending, 10000); +sort_bench!(sort_large_descending, gen_descending, 10000); +sort_bench!(sort_large_mostly_ascending, gen_mostly_ascending, 10000); +sort_bench!(sort_large_mostly_descending, gen_mostly_descending, 10000); + +sort_bench!(sort_large_big_random, gen_big_random, 10000); +sort_bench!(sort_large_big_ascending, gen_big_ascending, 10000); +sort_bench!(sort_large_big_descending, gen_big_descending, 10000); + +#[bench] +fn sort_large_random_expensive(b: &mut Bencher) { + let len = 10000; + b.iter(|| { + let mut v = gen_random(len); + let mut count = 0; + v.sort_by(|a: &u64, b: &u64| { + count += 1; + if count % 1_000_000_000 == 0 { + panic!("should not happen"); + } + (*a as f64).cos().partial_cmp(&(*b as f64).cos()).unwrap() + }); + black_box(count); + }); + b.bytes = len as u64 * mem::size_of::() as u64; +} \ No newline at end of file diff --git a/src/libcollections/benches/str.rs b/src/libcollections/benches/str.rs new file mode 100644 index 0000000000000..7f727078101c4 --- /dev/null +++ b/src/libcollections/benches/str.rs @@ -0,0 +1,298 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use test::{Bencher, black_box}; + +#[bench] +fn char_iterator(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + + b.iter(|| s.chars().count()); +} + +#[bench] +fn char_iterator_for(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + + b.iter(|| { + for ch in s.chars() { black_box(ch); } + }); +} + +#[bench] +fn char_iterator_ascii(b: &mut Bencher) { + let s = "Mary had a little lamb, Little lamb + Mary had a little lamb, Little lamb + Mary had a little lamb, Little lamb + Mary had a little lamb, Little lamb + Mary had a little lamb, Little lamb + Mary had a little lamb, Little lamb"; + + b.iter(|| s.chars().count()); +} + +#[bench] +fn char_iterator_rev(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + + b.iter(|| s.chars().rev().count()); +} + +#[bench] +fn char_iterator_rev_for(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + + b.iter(|| { + for ch in s.chars().rev() { black_box(ch); } + }); +} + +#[bench] +fn char_indicesator(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + let len = s.chars().count(); + + b.iter(|| assert_eq!(s.char_indices().count(), len)); +} + +#[bench] +fn char_indicesator_rev(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + let len = s.chars().count(); + + b.iter(|| assert_eq!(s.char_indices().rev().count(), len)); +} + +#[bench] +fn split_unicode_ascii(b: &mut Bencher) { + let s = "ประเทศไทย中华Việt Namประเทศไทย中华Việt Nam"; + + b.iter(|| assert_eq!(s.split('V').count(), 3)); +} + +#[bench] +fn split_ascii(b: &mut Bencher) { + let s = "Mary had a little lamb, Little lamb, little-lamb."; + let len = s.split(' ').count(); + + b.iter(|| assert_eq!(s.split(' ').count(), len)); +} + +#[bench] +fn split_extern_fn(b: &mut Bencher) { + let s = "Mary had a little lamb, Little lamb, little-lamb."; + let len = s.split(' ').count(); + fn pred(c: char) -> bool { c == ' ' } + + b.iter(|| assert_eq!(s.split(pred).count(), len)); +} + +#[bench] +fn split_closure(b: &mut Bencher) { + let s = "Mary had a little lamb, Little lamb, little-lamb."; + let len = s.split(' ').count(); + + b.iter(|| assert_eq!(s.split(|c: char| c == ' ').count(), len)); +} + +#[bench] +fn split_slice(b: &mut Bencher) { + let s = "Mary had a little lamb, Little lamb, little-lamb."; + let len = s.split(' ').count(); + + let c: &[char] = &[' ']; + b.iter(|| assert_eq!(s.split(c).count(), len)); +} + +#[bench] +fn bench_join(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + let sep = "→"; + let v = vec![s, s, s, s, s, s, s, s, s, s]; + b.iter(|| { + assert_eq!(v.join(sep).len(), s.len() * 10 + sep.len() * 9); + }) +} + +#[bench] +fn bench_contains_short_short(b: &mut Bencher) { + let haystack = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; + let needle = "sit"; + + b.iter(|| { + assert!(haystack.contains(needle)); + }) +} + +#[bench] +fn bench_contains_short_long(b: &mut Bencher) { + let haystack = "\ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \ +ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \ +eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \ +sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \ +tempus vel, gravida nec quam. + +In est dui, tincidunt sed tempus interdum, adipiscing laoreet ante. Etiam tempor, tellus quis \ +sagittis interdum, nulla purus mattis sem, quis auctor erat odio ac tellus. In nec nunc sit amet \ +diam volutpat molestie at sed ipsum. Vestibulum laoreet consequat vulputate. Integer accumsan \ +lorem ac dignissim placerat. Suspendisse convallis faucibus lorem. Aliquam erat volutpat. In vel \ +eleifend felis. Sed suscipit nulla lorem, sed mollis est sollicitudin et. Nam fermentum egestas \ +interdum. Curabitur ut nisi justo. + +Sed sollicitudin ipsum tellus, ut condimentum leo eleifend nec. Cras ut velit ante. Phasellus nec \ +mollis odio. Mauris molestie erat in arcu mattis, at aliquet dolor vehicula. Quisque malesuada \ +lectus sit amet nisi pretium, a condimentum ipsum porta. Morbi at dapibus diam. Praesent egestas \ +est sed risus elementum, eu rutrum metus ultrices. Etiam fermentum consectetur magna, id rutrum \ +felis accumsan a. Aliquam ut pellentesque libero. Sed mi nulla, lobortis eu tortor id, suscipit \ +ultricies neque. Morbi iaculis sit amet risus at iaculis. Praesent eget ligula quis turpis \ +feugiat suscipit vel non arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. \ +Aliquam sit amet placerat lorem. + +Cras a lacus vel ante posuere elementum. Nunc est leo, bibendum ut facilisis vel, bibendum at \ +mauris. Nullam adipiscing diam vel odio ornare, luctus adipiscing mi luctus. Nulla facilisi. \ +Mauris adipiscing bibendum neque, quis adipiscing lectus tempus et. Sed feugiat erat et nisl \ +lobortis pharetra. Donec vitae erat enim. Nullam sit amet felis et quam lacinia tincidunt. Aliquam \ +suscipit dapibus urna. Sed volutpat urna in magna pulvinar volutpat. Phasellus nec tellus ac diam \ +cursus accumsan. + +Nam lectus enim, dapibus non nisi tempor, consectetur convallis massa. Maecenas eleifend dictum \ +feugiat. Etiam quis mauris vel risus luctus mattis a a nunc. Nullam orci quam, imperdiet id \ +vehicula in, porttitor ut nibh. Duis sagittis adipiscing nisl vitae congue. Donec mollis risus eu \ +leo suscipit, varius porttitor nulla porta. Pellentesque ut sem nec nisi euismod vehicula. Nulla \ +malesuada sollicitudin quam eu fermentum."; + let needle = "english"; + + b.iter(|| { + assert!(!haystack.contains(needle)); + }) +} + +#[bench] +fn bench_contains_bad_naive(b: &mut Bencher) { + let haystack = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + let needle = "aaaaaaaab"; + + b.iter(|| { + assert!(!haystack.contains(needle)); + }) +} + +#[bench] +fn bench_contains_equal(b: &mut Bencher) { + let haystack = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; + let needle = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; + + b.iter(|| { + assert!(haystack.contains(needle)); + }) +} + +macro_rules! make_test_inner { + ($s:ident, $code:expr, $name:ident, $str:expr) => { + #[bench] + fn $name(bencher: &mut Bencher) { + let mut $s = $str; + black_box(&mut $s); + bencher.iter(|| $code); + } + } +} + +macro_rules! make_test { + ($name:ident, $s:ident, $code:expr) => { + mod $name { + use test::Bencher; + use test::black_box; + + // Short strings: 65 bytes each + make_test_inner!($s, $code, short_ascii, + "Mary had a little lamb, Little lamb Mary had a littl lamb, lamb!"); + make_test_inner!($s, $code, short_mixed, + "ศไทย中华Việt Nam; Mary had a little lamb, Little lam!"); + make_test_inner!($s, $code, short_pile_of_poo, + "💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩!"); + make_test_inner!($s, $code, long_lorem_ipsum,"\ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \ +ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \ +eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \ +sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \ +tempus vel, gravida nec quam. + +In est dui, tincidunt sed tempus interdum, adipiscing laoreet ante. Etiam tempor, tellus quis \ +sagittis interdum, nulla purus mattis sem, quis auctor erat odio ac tellus. In nec nunc sit amet \ +diam volutpat molestie at sed ipsum. Vestibulum laoreet consequat vulputate. Integer accumsan \ +lorem ac dignissim placerat. Suspendisse convallis faucibus lorem. Aliquam erat volutpat. In vel \ +eleifend felis. Sed suscipit nulla lorem, sed mollis est sollicitudin et. Nam fermentum egestas \ +interdum. Curabitur ut nisi justo. + +Sed sollicitudin ipsum tellus, ut condimentum leo eleifend nec. Cras ut velit ante. Phasellus nec \ +mollis odio. Mauris molestie erat in arcu mattis, at aliquet dolor vehicula. Quisque malesuada \ +lectus sit amet nisi pretium, a condimentum ipsum porta. Morbi at dapibus diam. Praesent egestas \ +est sed risus elementum, eu rutrum metus ultrices. Etiam fermentum consectetur magna, id rutrum \ +felis accumsan a. Aliquam ut pellentesque libero. Sed mi nulla, lobortis eu tortor id, suscipit \ +ultricies neque. Morbi iaculis sit amet risus at iaculis. Praesent eget ligula quis turpis \ +feugiat suscipit vel non arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. \ +Aliquam sit amet placerat lorem. + +Cras a lacus vel ante posuere elementum. Nunc est leo, bibendum ut facilisis vel, bibendum at \ +mauris. Nullam adipiscing diam vel odio ornare, luctus adipiscing mi luctus. Nulla facilisi. \ +Mauris adipiscing bibendum neque, quis adipiscing lectus tempus et. Sed feugiat erat et nisl \ +lobortis pharetra. Donec vitae erat enim. Nullam sit amet felis et quam lacinia tincidunt. Aliquam \ +suscipit dapibus urna. Sed volutpat urna in magna pulvinar volutpat. Phasellus nec tellus ac diam \ +cursus accumsan. + +Nam lectus enim, dapibus non nisi tempor, consectetur convallis massa. Maecenas eleifend dictum \ +feugiat. Etiam quis mauris vel risus luctus mattis a a nunc. Nullam orci quam, imperdiet id \ +vehicula in, porttitor ut nibh. Duis sagittis adipiscing nisl vitae congue. Donec mollis risus eu \ +leo suscipit, varius porttitor nulla porta. Pellentesque ut sem nec nisi euismod vehicula. Nulla \ +malesuada sollicitudin quam eu fermentum!"); + } + } +} + +make_test!(chars_count, s, s.chars().count()); + +make_test!(contains_bang_str, s, s.contains("!")); +make_test!(contains_bang_char, s, s.contains('!')); + +make_test!(match_indices_a_str, s, s.match_indices("a").count()); + +make_test!(split_a_str, s, s.split("a").count()); + +make_test!(trim_ascii_char, s, { + use std::ascii::AsciiExt; + s.trim_matches(|c: char| c.is_ascii()) +}); +make_test!(trim_left_ascii_char, s, { + use std::ascii::AsciiExt; + s.trim_left_matches(|c: char| c.is_ascii()) +}); +make_test!(trim_right_ascii_char, s, { + use std::ascii::AsciiExt; + s.trim_right_matches(|c: char| c.is_ascii()) +}); + +make_test!(find_underscore_char, s, s.find('_')); +make_test!(rfind_underscore_char, s, s.rfind('_')); +make_test!(find_underscore_str, s, s.find("_")); + +make_test!(find_zzz_char, s, s.find('\u{1F4A4}')); +make_test!(rfind_zzz_char, s, s.rfind('\u{1F4A4}')); +make_test!(find_zzz_str, s, s.find("\u{1F4A4}")); + +make_test!(split_space_char, s, s.split(' ').count()); +make_test!(split_terminator_space_char, s, s.split_terminator(' ').count()); + +make_test!(splitn_space_char, s, s.splitn(10, ' ').count()); +make_test!(rsplitn_space_char, s, s.rsplitn(10, ' ').count()); + +make_test!(split_space_str, s, s.split(" ").count()); +make_test!(split_ad_str, s, s.split("ad").count()); diff --git a/src/libcollections/benches/string.rs b/src/libcollections/benches/string.rs new file mode 100644 index 0000000000000..36be21d978e1f --- /dev/null +++ b/src/libcollections/benches/string.rs @@ -0,0 +1,134 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::iter::repeat; +use test::Bencher; + +#[bench] +fn bench_with_capacity(b: &mut Bencher) { + b.iter(|| String::with_capacity(100)); +} + +#[bench] +fn bench_push_str(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + b.iter(|| { + let mut r = String::new(); + r.push_str(s); + }); +} + +const REPETITIONS: u64 = 10_000; + +#[bench] +fn bench_push_str_one_byte(b: &mut Bencher) { + b.bytes = REPETITIONS; + b.iter(|| { + let mut r = String::new(); + for _ in 0..REPETITIONS { + r.push_str("a") + } + }); +} + +#[bench] +fn bench_push_char_one_byte(b: &mut Bencher) { + b.bytes = REPETITIONS; + b.iter(|| { + let mut r = String::new(); + for _ in 0..REPETITIONS { + r.push('a') + } + }); +} + +#[bench] +fn bench_push_char_two_bytes(b: &mut Bencher) { + b.bytes = REPETITIONS * 2; + b.iter(|| { + let mut r = String::new(); + for _ in 0..REPETITIONS { + r.push('â') + } + }); +} + +#[bench] +fn from_utf8_lossy_100_ascii(b: &mut Bencher) { + let s = b"Hello there, the quick brown fox jumped over the lazy dog! \ + Lorem ipsum dolor sit amet, consectetur. "; + + assert_eq!(100, s.len()); + b.iter(|| { + let _ = String::from_utf8_lossy(s); + }); +} + +#[bench] +fn from_utf8_lossy_100_multibyte(b: &mut Bencher) { + let s = "𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰".as_bytes(); + assert_eq!(100, s.len()); + b.iter(|| { + let _ = String::from_utf8_lossy(s); + }); +} + +#[bench] +fn from_utf8_lossy_invalid(b: &mut Bencher) { + let s = b"Hello\xC0\x80 There\xE6\x83 Goodbye"; + b.iter(|| { + let _ = String::from_utf8_lossy(s); + }); +} + +#[bench] +fn from_utf8_lossy_100_invalid(b: &mut Bencher) { + let s = repeat(0xf5).take(100).collect::>(); + b.iter(|| { + let _ = String::from_utf8_lossy(&s); + }); +} + +#[bench] +fn bench_exact_size_shrink_to_fit(b: &mut Bencher) { + let s = "Hello there, the quick brown fox jumped over the lazy dog! \ + Lorem ipsum dolor sit amet, consectetur. "; + // ensure our operation produces an exact-size string before we benchmark it + let mut r = String::with_capacity(s.len()); + r.push_str(s); + assert_eq!(r.len(), r.capacity()); + b.iter(|| { + let mut r = String::with_capacity(s.len()); + r.push_str(s); + r.shrink_to_fit(); + r + }); +} + +#[bench] +fn bench_from_str(b: &mut Bencher) { + let s = "Hello there, the quick brown fox jumped over the lazy dog! \ + Lorem ipsum dolor sit amet, consectetur. "; + b.iter(|| String::from(s)) +} + +#[bench] +fn bench_from(b: &mut Bencher) { + let s = "Hello there, the quick brown fox jumped over the lazy dog! \ + Lorem ipsum dolor sit amet, consectetur. "; + b.iter(|| String::from(s)) +} + +#[bench] +fn bench_to_string(b: &mut Bencher) { + let s = "Hello there, the quick brown fox jumped over the lazy dog! \ + Lorem ipsum dolor sit amet, consectetur. "; + b.iter(|| s.to_string()) +} diff --git a/src/libcollections/benches/vec.rs b/src/libcollections/benches/vec.rs new file mode 100644 index 0000000000000..414901170683e --- /dev/null +++ b/src/libcollections/benches/vec.rs @@ -0,0 +1,492 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use test::Bencher; +use std::iter::{FromIterator, repeat}; + +#[bench] +fn bench_new(b: &mut Bencher) { + b.iter(|| { + let v: Vec = Vec::new(); + assert_eq!(v.len(), 0); + assert_eq!(v.capacity(), 0); + }) +} + +fn do_bench_with_capacity(b: &mut Bencher, src_len: usize) { + b.bytes = src_len as u64; + + b.iter(|| { + let v: Vec = Vec::with_capacity(src_len); + assert_eq!(v.len(), 0); + assert_eq!(v.capacity(), src_len); + }) +} + +#[bench] +fn bench_with_capacity_0000(b: &mut Bencher) { + do_bench_with_capacity(b, 0) +} + +#[bench] +fn bench_with_capacity_0010(b: &mut Bencher) { + do_bench_with_capacity(b, 10) +} + +#[bench] +fn bench_with_capacity_0100(b: &mut Bencher) { + do_bench_with_capacity(b, 100) +} + +#[bench] +fn bench_with_capacity_1000(b: &mut Bencher) { + do_bench_with_capacity(b, 1000) +} + +fn do_bench_from_fn(b: &mut Bencher, src_len: usize) { + b.bytes = src_len as u64; + + b.iter(|| { + let dst = (0..src_len).collect::>(); + assert_eq!(dst.len(), src_len); + assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + }) +} + +#[bench] +fn bench_from_fn_0000(b: &mut Bencher) { + do_bench_from_fn(b, 0) +} + +#[bench] +fn bench_from_fn_0010(b: &mut Bencher) { + do_bench_from_fn(b, 10) +} + +#[bench] +fn bench_from_fn_0100(b: &mut Bencher) { + do_bench_from_fn(b, 100) +} + +#[bench] +fn bench_from_fn_1000(b: &mut Bencher) { + do_bench_from_fn(b, 1000) +} + +fn do_bench_from_elem(b: &mut Bencher, src_len: usize) { + b.bytes = src_len as u64; + + b.iter(|| { + let dst: Vec = repeat(5).take(src_len).collect(); + assert_eq!(dst.len(), src_len); + assert!(dst.iter().all(|x| *x == 5)); + }) +} + +#[bench] +fn bench_from_elem_0000(b: &mut Bencher) { + do_bench_from_elem(b, 0) +} + +#[bench] +fn bench_from_elem_0010(b: &mut Bencher) { + do_bench_from_elem(b, 10) +} + +#[bench] +fn bench_from_elem_0100(b: &mut Bencher) { + do_bench_from_elem(b, 100) +} + +#[bench] +fn bench_from_elem_1000(b: &mut Bencher) { + do_bench_from_elem(b, 1000) +} + +fn do_bench_from_slice(b: &mut Bencher, src_len: usize) { + let src: Vec<_> = FromIterator::from_iter(0..src_len); + + b.bytes = src_len as u64; + + b.iter(|| { + let dst = src.clone()[..].to_vec(); + assert_eq!(dst.len(), src_len); + assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + }); +} + +#[bench] +fn bench_from_slice_0000(b: &mut Bencher) { + do_bench_from_slice(b, 0) +} + +#[bench] +fn bench_from_slice_0010(b: &mut Bencher) { + do_bench_from_slice(b, 10) +} + +#[bench] +fn bench_from_slice_0100(b: &mut Bencher) { + do_bench_from_slice(b, 100) +} + +#[bench] +fn bench_from_slice_1000(b: &mut Bencher) { + do_bench_from_slice(b, 1000) +} + +fn do_bench_from_iter(b: &mut Bencher, src_len: usize) { + let src: Vec<_> = FromIterator::from_iter(0..src_len); + + b.bytes = src_len as u64; + + b.iter(|| { + let dst: Vec<_> = FromIterator::from_iter(src.clone()); + assert_eq!(dst.len(), src_len); + assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + }); +} + +#[bench] +fn bench_from_iter_0000(b: &mut Bencher) { + do_bench_from_iter(b, 0) +} + +#[bench] +fn bench_from_iter_0010(b: &mut Bencher) { + do_bench_from_iter(b, 10) +} + +#[bench] +fn bench_from_iter_0100(b: &mut Bencher) { + do_bench_from_iter(b, 100) +} + +#[bench] +fn bench_from_iter_1000(b: &mut Bencher) { + do_bench_from_iter(b, 1000) +} + +fn do_bench_extend(b: &mut Bencher, dst_len: usize, src_len: usize) { + let dst: Vec<_> = FromIterator::from_iter(0..dst_len); + let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len); + + b.bytes = src_len as u64; + + b.iter(|| { + let mut dst = dst.clone(); + dst.extend(src.clone()); + assert_eq!(dst.len(), dst_len + src_len); + assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + }); +} + +#[bench] +fn bench_extend_0000_0000(b: &mut Bencher) { + do_bench_extend(b, 0, 0) +} + +#[bench] +fn bench_extend_0000_0010(b: &mut Bencher) { + do_bench_extend(b, 0, 10) +} + +#[bench] +fn bench_extend_0000_0100(b: &mut Bencher) { + do_bench_extend(b, 0, 100) +} + +#[bench] +fn bench_extend_0000_1000(b: &mut Bencher) { + do_bench_extend(b, 0, 1000) +} + +#[bench] +fn bench_extend_0010_0010(b: &mut Bencher) { + do_bench_extend(b, 10, 10) +} + +#[bench] +fn bench_extend_0100_0100(b: &mut Bencher) { + do_bench_extend(b, 100, 100) +} + +#[bench] +fn bench_extend_1000_1000(b: &mut Bencher) { + do_bench_extend(b, 1000, 1000) +} + +fn do_bench_push_all(b: &mut Bencher, dst_len: usize, src_len: usize) { + let dst: Vec<_> = FromIterator::from_iter(0..dst_len); + let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len); + + b.bytes = src_len as u64; + + b.iter(|| { + let mut dst = dst.clone(); + dst.extend_from_slice(&src); + assert_eq!(dst.len(), dst_len + src_len); + assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + }); +} + +#[bench] +fn bench_push_all_0000_0000(b: &mut Bencher) { + do_bench_push_all(b, 0, 0) +} + +#[bench] +fn bench_push_all_0000_0010(b: &mut Bencher) { + do_bench_push_all(b, 0, 10) +} + +#[bench] +fn bench_push_all_0000_0100(b: &mut Bencher) { + do_bench_push_all(b, 0, 100) +} + +#[bench] +fn bench_push_all_0000_1000(b: &mut Bencher) { + do_bench_push_all(b, 0, 1000) +} + +#[bench] +fn bench_push_all_0010_0010(b: &mut Bencher) { + do_bench_push_all(b, 10, 10) +} + +#[bench] +fn bench_push_all_0100_0100(b: &mut Bencher) { + do_bench_push_all(b, 100, 100) +} + +#[bench] +fn bench_push_all_1000_1000(b: &mut Bencher) { + do_bench_push_all(b, 1000, 1000) +} + +fn do_bench_push_all_move(b: &mut Bencher, dst_len: usize, src_len: usize) { + let dst: Vec<_> = FromIterator::from_iter(0..dst_len); + let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len); + + b.bytes = src_len as u64; + + b.iter(|| { + let mut dst = dst.clone(); + dst.extend(src.clone()); + assert_eq!(dst.len(), dst_len + src_len); + assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + }); +} + +#[bench] +fn bench_push_all_move_0000_0000(b: &mut Bencher) { + do_bench_push_all_move(b, 0, 0) +} + +#[bench] +fn bench_push_all_move_0000_0010(b: &mut Bencher) { + do_bench_push_all_move(b, 0, 10) +} + +#[bench] +fn bench_push_all_move_0000_0100(b: &mut Bencher) { + do_bench_push_all_move(b, 0, 100) +} + +#[bench] +fn bench_push_all_move_0000_1000(b: &mut Bencher) { + do_bench_push_all_move(b, 0, 1000) +} + +#[bench] +fn bench_push_all_move_0010_0010(b: &mut Bencher) { + do_bench_push_all_move(b, 10, 10) +} + +#[bench] +fn bench_push_all_move_0100_0100(b: &mut Bencher) { + do_bench_push_all_move(b, 100, 100) +} + +#[bench] +fn bench_push_all_move_1000_1000(b: &mut Bencher) { + do_bench_push_all_move(b, 1000, 1000) +} + +fn do_bench_clone(b: &mut Bencher, src_len: usize) { + let src: Vec = FromIterator::from_iter(0..src_len); + + b.bytes = src_len as u64; + + b.iter(|| { + let dst = src.clone(); + assert_eq!(dst.len(), src_len); + assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + }); +} + +#[bench] +fn bench_clone_0000(b: &mut Bencher) { + do_bench_clone(b, 0) +} + +#[bench] +fn bench_clone_0010(b: &mut Bencher) { + do_bench_clone(b, 10) +} + +#[bench] +fn bench_clone_0100(b: &mut Bencher) { + do_bench_clone(b, 100) +} + +#[bench] +fn bench_clone_1000(b: &mut Bencher) { + do_bench_clone(b, 1000) +} + +fn do_bench_clone_from(b: &mut Bencher, times: usize, dst_len: usize, src_len: usize) { + let dst: Vec<_> = FromIterator::from_iter(0..src_len); + let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len); + + b.bytes = (times * src_len) as u64; + + b.iter(|| { + let mut dst = dst.clone(); + + for _ in 0..times { + dst.clone_from(&src); + + assert_eq!(dst.len(), src_len); + assert!(dst.iter().enumerate().all(|(i, x)| dst_len + i == *x)); + } + }); +} + +#[bench] +fn bench_clone_from_01_0000_0000(b: &mut Bencher) { + do_bench_clone_from(b, 1, 0, 0) +} + +#[bench] +fn bench_clone_from_01_0000_0010(b: &mut Bencher) { + do_bench_clone_from(b, 1, 0, 10) +} + +#[bench] +fn bench_clone_from_01_0000_0100(b: &mut Bencher) { + do_bench_clone_from(b, 1, 0, 100) +} + +#[bench] +fn bench_clone_from_01_0000_1000(b: &mut Bencher) { + do_bench_clone_from(b, 1, 0, 1000) +} + +#[bench] +fn bench_clone_from_01_0010_0010(b: &mut Bencher) { + do_bench_clone_from(b, 1, 10, 10) +} + +#[bench] +fn bench_clone_from_01_0100_0100(b: &mut Bencher) { + do_bench_clone_from(b, 1, 100, 100) +} + +#[bench] +fn bench_clone_from_01_1000_1000(b: &mut Bencher) { + do_bench_clone_from(b, 1, 1000, 1000) +} + +#[bench] +fn bench_clone_from_01_0010_0100(b: &mut Bencher) { + do_bench_clone_from(b, 1, 10, 100) +} + +#[bench] +fn bench_clone_from_01_0100_1000(b: &mut Bencher) { + do_bench_clone_from(b, 1, 100, 1000) +} + +#[bench] +fn bench_clone_from_01_0010_0000(b: &mut Bencher) { + do_bench_clone_from(b, 1, 10, 0) +} + +#[bench] +fn bench_clone_from_01_0100_0010(b: &mut Bencher) { + do_bench_clone_from(b, 1, 100, 10) +} + +#[bench] +fn bench_clone_from_01_1000_0100(b: &mut Bencher) { + do_bench_clone_from(b, 1, 1000, 100) +} + +#[bench] +fn bench_clone_from_10_0000_0000(b: &mut Bencher) { + do_bench_clone_from(b, 10, 0, 0) +} + +#[bench] +fn bench_clone_from_10_0000_0010(b: &mut Bencher) { + do_bench_clone_from(b, 10, 0, 10) +} + +#[bench] +fn bench_clone_from_10_0000_0100(b: &mut Bencher) { + do_bench_clone_from(b, 10, 0, 100) +} + +#[bench] +fn bench_clone_from_10_0000_1000(b: &mut Bencher) { + do_bench_clone_from(b, 10, 0, 1000) +} + +#[bench] +fn bench_clone_from_10_0010_0010(b: &mut Bencher) { + do_bench_clone_from(b, 10, 10, 10) +} + +#[bench] +fn bench_clone_from_10_0100_0100(b: &mut Bencher) { + do_bench_clone_from(b, 10, 100, 100) +} + +#[bench] +fn bench_clone_from_10_1000_1000(b: &mut Bencher) { + do_bench_clone_from(b, 10, 1000, 1000) +} + +#[bench] +fn bench_clone_from_10_0010_0100(b: &mut Bencher) { + do_bench_clone_from(b, 10, 10, 100) +} + +#[bench] +fn bench_clone_from_10_0100_1000(b: &mut Bencher) { + do_bench_clone_from(b, 10, 100, 1000) +} + +#[bench] +fn bench_clone_from_10_0010_0000(b: &mut Bencher) { + do_bench_clone_from(b, 10, 10, 0) +} + +#[bench] +fn bench_clone_from_10_0100_0010(b: &mut Bencher) { + do_bench_clone_from(b, 10, 100, 10) +} + +#[bench] +fn bench_clone_from_10_1000_0100(b: &mut Bencher) { + do_bench_clone_from(b, 10, 1000, 100) +} diff --git a/src/libcollections/benches/vec_deque.rs b/src/libcollections/benches/vec_deque.rs new file mode 100644 index 0000000000000..380645e7cd03a --- /dev/null +++ b/src/libcollections/benches/vec_deque.rs @@ -0,0 +1,57 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::VecDeque; +use test::{Bencher, black_box}; + +#[bench] +fn bench_new(b: &mut Bencher) { + b.iter(|| { + let ring: VecDeque = VecDeque::new(); + black_box(ring); + }) +} + +#[bench] +fn bench_grow_1025(b: &mut Bencher) { + b.iter(|| { + let mut deq = VecDeque::new(); + for i in 0..1025 { + deq.push_front(i); + } + black_box(deq); + }) +} + +#[bench] +fn bench_iter_1000(b: &mut Bencher) { + let ring: VecDeque<_> = (0..1000).collect(); + + b.iter(|| { + let mut sum = 0; + for &i in &ring { + sum += i; + } + black_box(sum); + }) +} + +#[bench] +fn bench_mut_iter_1000(b: &mut Bencher) { + let mut ring: VecDeque<_> = (0..1000).collect(); + + b.iter(|| { + let mut sum = 0; + for i in &mut ring { + sum += *i; + } + black_box(sum); + }) +} diff --git a/src/libcollectionstest/btree/map.rs b/src/libcollectionstest/btree/map.rs index c84753415a258..11be13426e49c 100644 --- a/src/libcollectionstest/btree/map.rs +++ b/src/libcollectionstest/btree/map.rs @@ -606,52 +606,3 @@ fn test_split_off_large_random_sorted() { assert!(map.into_iter().eq(data.clone().into_iter().filter(|x| x.0 < key))); assert!(right.into_iter().eq(data.into_iter().filter(|x| x.0 >= key))); } - -mod bench { - use std::collections::BTreeMap; - use std::__rand::{Rng, thread_rng}; - - use test::{Bencher, black_box}; - - map_insert_rand_bench!{insert_rand_100, 100, BTreeMap} - map_insert_rand_bench!{insert_rand_10_000, 10_000, BTreeMap} - - map_insert_seq_bench!{insert_seq_100, 100, BTreeMap} - map_insert_seq_bench!{insert_seq_10_000, 10_000, BTreeMap} - - map_find_rand_bench!{find_rand_100, 100, BTreeMap} - map_find_rand_bench!{find_rand_10_000, 10_000, BTreeMap} - - map_find_seq_bench!{find_seq_100, 100, BTreeMap} - map_find_seq_bench!{find_seq_10_000, 10_000, BTreeMap} - - fn bench_iter(b: &mut Bencher, size: i32) { - let mut map = BTreeMap::::new(); - let mut rng = thread_rng(); - - for _ in 0..size { - map.insert(rng.gen(), rng.gen()); - } - - b.iter(|| { - for entry in &map { - black_box(entry); - } - }); - } - - #[bench] - pub fn iter_20(b: &mut Bencher) { - bench_iter(b, 20); - } - - #[bench] - pub fn iter_1000(b: &mut Bencher) { - bench_iter(b, 1000); - } - - #[bench] - pub fn iter_100000(b: &mut Bencher) { - bench_iter(b, 100000); - } -} diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index b146672893f8d..57e3c2df059e1 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -35,10 +35,6 @@ extern crate std_unicode; use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; -#[cfg(test)] -#[macro_use] -mod bench; - mod binary_heap; mod btree; mod cow_str; diff --git a/src/libcollectionstest/linked_list.rs b/src/libcollectionstest/linked_list.rs index 956d75a95a58e..a59724a017b12 100644 --- a/src/libcollectionstest/linked_list.rs +++ b/src/libcollectionstest/linked_list.rs @@ -10,8 +10,6 @@ use std::collections::LinkedList; -use test; - #[test] fn test_basic() { let mut m = LinkedList::>::new(); @@ -356,81 +354,6 @@ fn test_extend() { assert!(a.iter().eq(&[1, 2, 3, 4, 5, 6, 7])); } -#[bench] -fn bench_collect_into(b: &mut test::Bencher) { - let v = &[0; 64]; - b.iter(|| { - let _: LinkedList<_> = v.iter().cloned().collect(); - }) -} - -#[bench] -fn bench_push_front(b: &mut test::Bencher) { - let mut m: LinkedList<_> = LinkedList::new(); - b.iter(|| { - m.push_front(0); - }) -} - -#[bench] -fn bench_push_back(b: &mut test::Bencher) { - let mut m: LinkedList<_> = LinkedList::new(); - b.iter(|| { - m.push_back(0); - }) -} - -#[bench] -fn bench_push_back_pop_back(b: &mut test::Bencher) { - let mut m: LinkedList<_> = LinkedList::new(); - b.iter(|| { - m.push_back(0); - m.pop_back(); - }) -} - -#[bench] -fn bench_push_front_pop_front(b: &mut test::Bencher) { - let mut m: LinkedList<_> = LinkedList::new(); - b.iter(|| { - m.push_front(0); - m.pop_front(); - }) -} - -#[bench] -fn bench_iter(b: &mut test::Bencher) { - let v = &[0; 128]; - let m: LinkedList<_> = v.iter().cloned().collect(); - b.iter(|| { - assert!(m.iter().count() == 128); - }) -} -#[bench] -fn bench_iter_mut(b: &mut test::Bencher) { - let v = &[0; 128]; - let mut m: LinkedList<_> = v.iter().cloned().collect(); - b.iter(|| { - assert!(m.iter_mut().count() == 128); - }) -} -#[bench] -fn bench_iter_rev(b: &mut test::Bencher) { - let v = &[0; 128]; - let m: LinkedList<_> = v.iter().cloned().collect(); - b.iter(|| { - assert!(m.iter().rev().count() == 128); - }) -} -#[bench] -fn bench_iter_mut_rev(b: &mut test::Bencher) { - let v = &[0; 128]; - let mut m: LinkedList<_> = v.iter().cloned().collect(); - b.iter(|| { - assert!(m.iter_mut().rev().count() == 128); - }) -} - #[test] fn test_contains() { let mut l = LinkedList::new(); diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index b9dec6be7b885..a7f7baf38518c 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -1170,276 +1170,3 @@ fn test_copy_from_slice_dst_shorter() { let mut dst = [0; 3]; dst.copy_from_slice(&src); } - -mod bench { - use std::{mem, ptr}; - use std::__rand::{Rng, thread_rng}; - - use test::{Bencher, black_box}; - - #[bench] - fn iterator(b: &mut Bencher) { - // peculiar numbers to stop LLVM from optimising the summation - // out. - let v: Vec<_> = (0..100).map(|i| i ^ (i << 1) ^ (i >> 1)).collect(); - - b.iter(|| { - let mut sum = 0; - for x in &v { - sum += *x; - } - // sum == 11806, to stop dead code elimination. - if sum == 0 { - panic!() - } - }) - } - - #[bench] - fn mut_iterator(b: &mut Bencher) { - let mut v = vec![0; 100]; - - b.iter(|| { - let mut i = 0; - for x in &mut v { - *x = i; - i += 1; - } - }) - } - - #[bench] - fn concat(b: &mut Bencher) { - let xss: Vec> = (0..100).map(|i| (0..i).collect()).collect(); - b.iter(|| { - xss.concat(); - }); - } - - #[bench] - fn join(b: &mut Bencher) { - let xss: Vec> = (0..100).map(|i| (0..i).collect()).collect(); - b.iter(|| xss.join(&0)); - } - - #[bench] - fn push(b: &mut Bencher) { - let mut vec = Vec::::new(); - b.iter(|| { - vec.push(0); - black_box(&vec); - }); - } - - #[bench] - fn starts_with_same_vector(b: &mut Bencher) { - let vec: Vec<_> = (0..100).collect(); - b.iter(|| vec.starts_with(&vec)) - } - - #[bench] - fn starts_with_single_element(b: &mut Bencher) { - let vec: Vec<_> = vec![0]; - b.iter(|| vec.starts_with(&vec)) - } - - #[bench] - fn starts_with_diff_one_element_at_end(b: &mut Bencher) { - let vec: Vec<_> = (0..100).collect(); - let mut match_vec: Vec<_> = (0..99).collect(); - match_vec.push(0); - b.iter(|| vec.starts_with(&match_vec)) - } - - #[bench] - fn ends_with_same_vector(b: &mut Bencher) { - let vec: Vec<_> = (0..100).collect(); - b.iter(|| vec.ends_with(&vec)) - } - - #[bench] - fn ends_with_single_element(b: &mut Bencher) { - let vec: Vec<_> = vec![0]; - b.iter(|| vec.ends_with(&vec)) - } - - #[bench] - fn ends_with_diff_one_element_at_beginning(b: &mut Bencher) { - let vec: Vec<_> = (0..100).collect(); - let mut match_vec: Vec<_> = (0..100).collect(); - match_vec[0] = 200; - b.iter(|| vec.starts_with(&match_vec)) - } - - #[bench] - fn contains_last_element(b: &mut Bencher) { - let vec: Vec<_> = (0..100).collect(); - b.iter(|| vec.contains(&99)) - } - - #[bench] - fn zero_1kb_from_elem(b: &mut Bencher) { - b.iter(|| vec![0u8; 1024]); - } - - #[bench] - fn zero_1kb_set_memory(b: &mut Bencher) { - b.iter(|| { - let mut v = Vec::::with_capacity(1024); - unsafe { - let vp = v.as_mut_ptr(); - ptr::write_bytes(vp, 0, 1024); - v.set_len(1024); - } - v - }); - } - - #[bench] - fn zero_1kb_loop_set(b: &mut Bencher) { - b.iter(|| { - let mut v = Vec::::with_capacity(1024); - unsafe { - v.set_len(1024); - } - for i in 0..1024 { - v[i] = 0; - } - }); - } - - #[bench] - fn zero_1kb_mut_iter(b: &mut Bencher) { - b.iter(|| { - let mut v = Vec::::with_capacity(1024); - unsafe { - v.set_len(1024); - } - for x in &mut v { - *x = 0; - } - v - }); - } - - #[bench] - fn random_inserts(b: &mut Bencher) { - let mut rng = thread_rng(); - b.iter(|| { - let mut v = vec![(0, 0); 30]; - for _ in 0..100 { - let l = v.len(); - v.insert(rng.gen::() % (l + 1), (1, 1)); - } - }) - } - #[bench] - fn random_removes(b: &mut Bencher) { - let mut rng = thread_rng(); - b.iter(|| { - let mut v = vec![(0, 0); 130]; - for _ in 0..100 { - let l = v.len(); - v.remove(rng.gen::() % l); - } - }) - } - - fn gen_ascending(len: usize) -> Vec { - (0..len as u64).collect() - } - - fn gen_descending(len: usize) -> Vec { - (0..len as u64).rev().collect() - } - - fn gen_random(len: usize) -> Vec { - let mut rng = thread_rng(); - rng.gen_iter::().take(len).collect() - } - - fn gen_mostly_ascending(len: usize) -> Vec { - let mut rng = thread_rng(); - let mut v = gen_ascending(len); - for _ in (0usize..).take_while(|x| x * x <= len) { - let x = rng.gen::() % len; - let y = rng.gen::() % len; - v.swap(x, y); - } - v - } - - fn gen_mostly_descending(len: usize) -> Vec { - let mut rng = thread_rng(); - let mut v = gen_descending(len); - for _ in (0usize..).take_while(|x| x * x <= len) { - let x = rng.gen::() % len; - let y = rng.gen::() % len; - v.swap(x, y); - } - v - } - - fn gen_big_random(len: usize) -> Vec<[u64; 16]> { - let mut rng = thread_rng(); - rng.gen_iter().map(|x| [x; 16]).take(len).collect() - } - - fn gen_big_ascending(len: usize) -> Vec<[u64; 16]> { - (0..len as u64).map(|x| [x; 16]).take(len).collect() - } - - fn gen_big_descending(len: usize) -> Vec<[u64; 16]> { - (0..len as u64).rev().map(|x| [x; 16]).take(len).collect() - } - - macro_rules! sort_bench { - ($name:ident, $gen:expr, $len:expr) => { - #[bench] - fn $name(b: &mut Bencher) { - b.iter(|| $gen($len).sort()); - b.bytes = $len * mem::size_of_val(&$gen(1)[0]) as u64; - } - } - } - - sort_bench!(sort_small_random, gen_random, 10); - sort_bench!(sort_small_ascending, gen_ascending, 10); - sort_bench!(sort_small_descending, gen_descending, 10); - - sort_bench!(sort_small_big_random, gen_big_random, 10); - sort_bench!(sort_small_big_ascending, gen_big_ascending, 10); - sort_bench!(sort_small_big_descending, gen_big_descending, 10); - - sort_bench!(sort_medium_random, gen_random, 100); - sort_bench!(sort_medium_ascending, gen_ascending, 100); - sort_bench!(sort_medium_descending, gen_descending, 100); - - sort_bench!(sort_large_random, gen_random, 10000); - sort_bench!(sort_large_ascending, gen_ascending, 10000); - sort_bench!(sort_large_descending, gen_descending, 10000); - sort_bench!(sort_large_mostly_ascending, gen_mostly_ascending, 10000); - sort_bench!(sort_large_mostly_descending, gen_mostly_descending, 10000); - - sort_bench!(sort_large_big_random, gen_big_random, 10000); - sort_bench!(sort_large_big_ascending, gen_big_ascending, 10000); - sort_bench!(sort_large_big_descending, gen_big_descending, 10000); - - #[bench] - fn sort_large_random_expensive(b: &mut Bencher) { - let len = 10000; - b.iter(|| { - let mut v = gen_random(len); - let mut count = 0; - v.sort_by(|a: &u64, b: &u64| { - count += 1; - if count % 1_000_000_000 == 0 { - panic!("should not happen"); - } - (*a as f64).cos().partial_cmp(&(*b as f64).cos()).unwrap() - }); - black_box(count); - }); - b.bytes = len as u64 * mem::size_of::() as u64; - } -} diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 5e685847e3c81..6221888f5e55e 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -1564,294 +1564,3 @@ fn different_str_pattern_forwarding_lifetimes() { foo::<&str>("x"); } - -mod bench { - use test::{Bencher, black_box}; - - #[bench] - fn char_iterator(b: &mut Bencher) { - let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; - - b.iter(|| s.chars().count()); - } - - #[bench] - fn char_iterator_for(b: &mut Bencher) { - let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; - - b.iter(|| { - for ch in s.chars() { black_box(ch); } - }); - } - - #[bench] - fn char_iterator_ascii(b: &mut Bencher) { - let s = "Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb"; - - b.iter(|| s.chars().count()); - } - - #[bench] - fn char_iterator_rev(b: &mut Bencher) { - let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; - - b.iter(|| s.chars().rev().count()); - } - - #[bench] - fn char_iterator_rev_for(b: &mut Bencher) { - let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; - - b.iter(|| { - for ch in s.chars().rev() { black_box(ch); } - }); - } - - #[bench] - fn char_indicesator(b: &mut Bencher) { - let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; - let len = s.chars().count(); - - b.iter(|| assert_eq!(s.char_indices().count(), len)); - } - - #[bench] - fn char_indicesator_rev(b: &mut Bencher) { - let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; - let len = s.chars().count(); - - b.iter(|| assert_eq!(s.char_indices().rev().count(), len)); - } - - #[bench] - fn split_unicode_ascii(b: &mut Bencher) { - let s = "ประเทศไทย中华Việt Namประเทศไทย中华Việt Nam"; - - b.iter(|| assert_eq!(s.split('V').count(), 3)); - } - - #[bench] - fn split_ascii(b: &mut Bencher) { - let s = "Mary had a little lamb, Little lamb, little-lamb."; - let len = s.split(' ').count(); - - b.iter(|| assert_eq!(s.split(' ').count(), len)); - } - - #[bench] - fn split_extern_fn(b: &mut Bencher) { - let s = "Mary had a little lamb, Little lamb, little-lamb."; - let len = s.split(' ').count(); - fn pred(c: char) -> bool { c == ' ' } - - b.iter(|| assert_eq!(s.split(pred).count(), len)); - } - - #[bench] - fn split_closure(b: &mut Bencher) { - let s = "Mary had a little lamb, Little lamb, little-lamb."; - let len = s.split(' ').count(); - - b.iter(|| assert_eq!(s.split(|c: char| c == ' ').count(), len)); - } - - #[bench] - fn split_slice(b: &mut Bencher) { - let s = "Mary had a little lamb, Little lamb, little-lamb."; - let len = s.split(' ').count(); - - let c: &[char] = &[' ']; - b.iter(|| assert_eq!(s.split(c).count(), len)); - } - - #[bench] - fn bench_join(b: &mut Bencher) { - let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; - let sep = "→"; - let v = vec![s, s, s, s, s, s, s, s, s, s]; - b.iter(|| { - assert_eq!(v.join(sep).len(), s.len() * 10 + sep.len() * 9); - }) - } - - #[bench] - fn bench_contains_short_short(b: &mut Bencher) { - let haystack = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; - let needle = "sit"; - - b.iter(|| { - assert!(haystack.contains(needle)); - }) - } - - #[bench] - fn bench_contains_short_long(b: &mut Bencher) { - let haystack = "\ -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \ -ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \ -eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \ -sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \ -tempus vel, gravida nec quam. - -In est dui, tincidunt sed tempus interdum, adipiscing laoreet ante. Etiam tempor, tellus quis \ -sagittis interdum, nulla purus mattis sem, quis auctor erat odio ac tellus. In nec nunc sit amet \ -diam volutpat molestie at sed ipsum. Vestibulum laoreet consequat vulputate. Integer accumsan \ -lorem ac dignissim placerat. Suspendisse convallis faucibus lorem. Aliquam erat volutpat. In vel \ -eleifend felis. Sed suscipit nulla lorem, sed mollis est sollicitudin et. Nam fermentum egestas \ -interdum. Curabitur ut nisi justo. - -Sed sollicitudin ipsum tellus, ut condimentum leo eleifend nec. Cras ut velit ante. Phasellus nec \ -mollis odio. Mauris molestie erat in arcu mattis, at aliquet dolor vehicula. Quisque malesuada \ -lectus sit amet nisi pretium, a condimentum ipsum porta. Morbi at dapibus diam. Praesent egestas \ -est sed risus elementum, eu rutrum metus ultrices. Etiam fermentum consectetur magna, id rutrum \ -felis accumsan a. Aliquam ut pellentesque libero. Sed mi nulla, lobortis eu tortor id, suscipit \ -ultricies neque. Morbi iaculis sit amet risus at iaculis. Praesent eget ligula quis turpis \ -feugiat suscipit vel non arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. \ -Aliquam sit amet placerat lorem. - -Cras a lacus vel ante posuere elementum. Nunc est leo, bibendum ut facilisis vel, bibendum at \ -mauris. Nullam adipiscing diam vel odio ornare, luctus adipiscing mi luctus. Nulla facilisi. \ -Mauris adipiscing bibendum neque, quis adipiscing lectus tempus et. Sed feugiat erat et nisl \ -lobortis pharetra. Donec vitae erat enim. Nullam sit amet felis et quam lacinia tincidunt. Aliquam \ -suscipit dapibus urna. Sed volutpat urna in magna pulvinar volutpat. Phasellus nec tellus ac diam \ -cursus accumsan. - -Nam lectus enim, dapibus non nisi tempor, consectetur convallis massa. Maecenas eleifend dictum \ -feugiat. Etiam quis mauris vel risus luctus mattis a a nunc. Nullam orci quam, imperdiet id \ -vehicula in, porttitor ut nibh. Duis sagittis adipiscing nisl vitae congue. Donec mollis risus eu \ -leo suscipit, varius porttitor nulla porta. Pellentesque ut sem nec nisi euismod vehicula. Nulla \ -malesuada sollicitudin quam eu fermentum."; - let needle = "english"; - - b.iter(|| { - assert!(!haystack.contains(needle)); - }) - } - - #[bench] - fn bench_contains_bad_naive(b: &mut Bencher) { - let haystack = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let needle = "aaaaaaaab"; - - b.iter(|| { - assert!(!haystack.contains(needle)); - }) - } - - #[bench] - fn bench_contains_equal(b: &mut Bencher) { - let haystack = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; - let needle = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; - - b.iter(|| { - assert!(haystack.contains(needle)); - }) - } - - macro_rules! make_test_inner { - ($s:ident, $code:expr, $name:ident, $str:expr) => { - #[bench] - fn $name(bencher: &mut Bencher) { - let mut $s = $str; - black_box(&mut $s); - bencher.iter(|| $code); - } - } - } - - macro_rules! make_test { - ($name:ident, $s:ident, $code:expr) => { - mod $name { - use test::Bencher; - use test::black_box; - - // Short strings: 65 bytes each - make_test_inner!($s, $code, short_ascii, - "Mary had a little lamb, Little lamb Mary had a littl lamb, lamb!"); - make_test_inner!($s, $code, short_mixed, - "ศไทย中华Việt Nam; Mary had a little lamb, Little lam!"); - make_test_inner!($s, $code, short_pile_of_poo, - "💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩!"); - make_test_inner!($s, $code, long_lorem_ipsum,"\ -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \ -ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \ -eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \ -sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \ -tempus vel, gravida nec quam. - -In est dui, tincidunt sed tempus interdum, adipiscing laoreet ante. Etiam tempor, tellus quis \ -sagittis interdum, nulla purus mattis sem, quis auctor erat odio ac tellus. In nec nunc sit amet \ -diam volutpat molestie at sed ipsum. Vestibulum laoreet consequat vulputate. Integer accumsan \ -lorem ac dignissim placerat. Suspendisse convallis faucibus lorem. Aliquam erat volutpat. In vel \ -eleifend felis. Sed suscipit nulla lorem, sed mollis est sollicitudin et. Nam fermentum egestas \ -interdum. Curabitur ut nisi justo. - -Sed sollicitudin ipsum tellus, ut condimentum leo eleifend nec. Cras ut velit ante. Phasellus nec \ -mollis odio. Mauris molestie erat in arcu mattis, at aliquet dolor vehicula. Quisque malesuada \ -lectus sit amet nisi pretium, a condimentum ipsum porta. Morbi at dapibus diam. Praesent egestas \ -est sed risus elementum, eu rutrum metus ultrices. Etiam fermentum consectetur magna, id rutrum \ -felis accumsan a. Aliquam ut pellentesque libero. Sed mi nulla, lobortis eu tortor id, suscipit \ -ultricies neque. Morbi iaculis sit amet risus at iaculis. Praesent eget ligula quis turpis \ -feugiat suscipit vel non arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. \ -Aliquam sit amet placerat lorem. - -Cras a lacus vel ante posuere elementum. Nunc est leo, bibendum ut facilisis vel, bibendum at \ -mauris. Nullam adipiscing diam vel odio ornare, luctus adipiscing mi luctus. Nulla facilisi. \ -Mauris adipiscing bibendum neque, quis adipiscing lectus tempus et. Sed feugiat erat et nisl \ -lobortis pharetra. Donec vitae erat enim. Nullam sit amet felis et quam lacinia tincidunt. Aliquam \ -suscipit dapibus urna. Sed volutpat urna in magna pulvinar volutpat. Phasellus nec tellus ac diam \ -cursus accumsan. - -Nam lectus enim, dapibus non nisi tempor, consectetur convallis massa. Maecenas eleifend dictum \ -feugiat. Etiam quis mauris vel risus luctus mattis a a nunc. Nullam orci quam, imperdiet id \ -vehicula in, porttitor ut nibh. Duis sagittis adipiscing nisl vitae congue. Donec mollis risus eu \ -leo suscipit, varius porttitor nulla porta. Pellentesque ut sem nec nisi euismod vehicula. Nulla \ -malesuada sollicitudin quam eu fermentum!"); - } - } - } - - make_test!(chars_count, s, s.chars().count()); - - make_test!(contains_bang_str, s, s.contains("!")); - make_test!(contains_bang_char, s, s.contains('!')); - - make_test!(match_indices_a_str, s, s.match_indices("a").count()); - - make_test!(split_a_str, s, s.split("a").count()); - - make_test!(trim_ascii_char, s, { - use std::ascii::AsciiExt; - s.trim_matches(|c: char| c.is_ascii()) - }); - make_test!(trim_left_ascii_char, s, { - use std::ascii::AsciiExt; - s.trim_left_matches(|c: char| c.is_ascii()) - }); - make_test!(trim_right_ascii_char, s, { - use std::ascii::AsciiExt; - s.trim_right_matches(|c: char| c.is_ascii()) - }); - - make_test!(find_underscore_char, s, s.find('_')); - make_test!(rfind_underscore_char, s, s.rfind('_')); - make_test!(find_underscore_str, s, s.find("_")); - - make_test!(find_zzz_char, s, s.find('\u{1F4A4}')); - make_test!(rfind_zzz_char, s, s.rfind('\u{1F4A4}')); - make_test!(find_zzz_str, s, s.find("\u{1F4A4}")); - - make_test!(split_space_char, s, s.split(' ').count()); - make_test!(split_terminator_space_char, s, s.split_terminator(' ').count()); - - make_test!(splitn_space_char, s, s.splitn(10, ' ').count()); - make_test!(rsplitn_space_char, s, s.rsplitn(10, ' ').count()); - - make_test!(split_space_str, s, s.split(" ").count()); - make_test!(split_ad_str, s, s.split("ad").count()); -} diff --git a/src/libcollectionstest/string.rs b/src/libcollectionstest/string.rs index a7d85d0bea13a..f77dd510303c7 100644 --- a/src/libcollectionstest/string.rs +++ b/src/libcollectionstest/string.rs @@ -9,9 +9,6 @@ // except according to those terms. use std::borrow::Cow; -use std::iter::repeat; - -use test::Bencher; pub trait IntoCow<'a, B: ?Sized> where B: ToOwned { fn into_cow(self) -> Cow<'a, B>; @@ -436,125 +433,3 @@ fn test_into_boxed_str() { let ys = xs.into_boxed_str(); assert_eq!(&*ys, "hello my name is bob"); } - -#[bench] -fn bench_with_capacity(b: &mut Bencher) { - b.iter(|| String::with_capacity(100)); -} - -#[bench] -fn bench_push_str(b: &mut Bencher) { - let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; - b.iter(|| { - let mut r = String::new(); - r.push_str(s); - }); -} - -const REPETITIONS: u64 = 10_000; - -#[bench] -fn bench_push_str_one_byte(b: &mut Bencher) { - b.bytes = REPETITIONS; - b.iter(|| { - let mut r = String::new(); - for _ in 0..REPETITIONS { - r.push_str("a") - } - }); -} - -#[bench] -fn bench_push_char_one_byte(b: &mut Bencher) { - b.bytes = REPETITIONS; - b.iter(|| { - let mut r = String::new(); - for _ in 0..REPETITIONS { - r.push('a') - } - }); -} - -#[bench] -fn bench_push_char_two_bytes(b: &mut Bencher) { - b.bytes = REPETITIONS * 2; - b.iter(|| { - let mut r = String::new(); - for _ in 0..REPETITIONS { - r.push('â') - } - }); -} - -#[bench] -fn from_utf8_lossy_100_ascii(b: &mut Bencher) { - let s = b"Hello there, the quick brown fox jumped over the lazy dog! \ - Lorem ipsum dolor sit amet, consectetur. "; - - assert_eq!(100, s.len()); - b.iter(|| { - let _ = String::from_utf8_lossy(s); - }); -} - -#[bench] -fn from_utf8_lossy_100_multibyte(b: &mut Bencher) { - let s = "𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰".as_bytes(); - assert_eq!(100, s.len()); - b.iter(|| { - let _ = String::from_utf8_lossy(s); - }); -} - -#[bench] -fn from_utf8_lossy_invalid(b: &mut Bencher) { - let s = b"Hello\xC0\x80 There\xE6\x83 Goodbye"; - b.iter(|| { - let _ = String::from_utf8_lossy(s); - }); -} - -#[bench] -fn from_utf8_lossy_100_invalid(b: &mut Bencher) { - let s = repeat(0xf5).take(100).collect::>(); - b.iter(|| { - let _ = String::from_utf8_lossy(&s); - }); -} - -#[bench] -fn bench_exact_size_shrink_to_fit(b: &mut Bencher) { - let s = "Hello there, the quick brown fox jumped over the lazy dog! \ - Lorem ipsum dolor sit amet, consectetur. "; - // ensure our operation produces an exact-size string before we benchmark it - let mut r = String::with_capacity(s.len()); - r.push_str(s); - assert_eq!(r.len(), r.capacity()); - b.iter(|| { - let mut r = String::with_capacity(s.len()); - r.push_str(s); - r.shrink_to_fit(); - r - }); -} - -#[bench] -fn bench_from_str(b: &mut Bencher) { - let s = "Hello there, the quick brown fox jumped over the lazy dog! \ - Lorem ipsum dolor sit amet, consectetur. "; - b.iter(|| String::from(s)) -} - -#[bench] -fn bench_from(b: &mut Bencher) { - let s = "Hello there, the quick brown fox jumped over the lazy dog! \ - Lorem ipsum dolor sit amet, consectetur. "; - b.iter(|| String::from(s)) -} - -#[bench] -fn bench_to_string(b: &mut Bencher) { - let s = "Hello there, the quick brown fox jumped over the lazy dog! \ - Lorem ipsum dolor sit amet, consectetur. "; - b.iter(|| s.to_string()) -} diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index 6d0f1eaffaa7b..edeedf1d40baf 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -10,13 +10,10 @@ use std::ascii::AsciiExt; use std::borrow::Cow; -use std::iter::{FromIterator, repeat}; use std::mem::size_of; use std::panic; use std::vec::{Drain, IntoIter}; -use test::Bencher; - struct DropCounter<'a> { count: &'a mut u32, } @@ -633,483 +630,3 @@ fn test_placement_panic() { let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { vec.place_back() <- mkpanic(); })); assert_eq!(vec.len(), 3); } - -#[bench] -fn bench_new(b: &mut Bencher) { - b.iter(|| { - let v: Vec = Vec::new(); - assert_eq!(v.len(), 0); - assert_eq!(v.capacity(), 0); - }) -} - -fn do_bench_with_capacity(b: &mut Bencher, src_len: usize) { - b.bytes = src_len as u64; - - b.iter(|| { - let v: Vec = Vec::with_capacity(src_len); - assert_eq!(v.len(), 0); - assert_eq!(v.capacity(), src_len); - }) -} - -#[bench] -fn bench_with_capacity_0000(b: &mut Bencher) { - do_bench_with_capacity(b, 0) -} - -#[bench] -fn bench_with_capacity_0010(b: &mut Bencher) { - do_bench_with_capacity(b, 10) -} - -#[bench] -fn bench_with_capacity_0100(b: &mut Bencher) { - do_bench_with_capacity(b, 100) -} - -#[bench] -fn bench_with_capacity_1000(b: &mut Bencher) { - do_bench_with_capacity(b, 1000) -} - -fn do_bench_from_fn(b: &mut Bencher, src_len: usize) { - b.bytes = src_len as u64; - - b.iter(|| { - let dst = (0..src_len).collect::>(); - assert_eq!(dst.len(), src_len); - assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); - }) -} - -#[bench] -fn bench_from_fn_0000(b: &mut Bencher) { - do_bench_from_fn(b, 0) -} - -#[bench] -fn bench_from_fn_0010(b: &mut Bencher) { - do_bench_from_fn(b, 10) -} - -#[bench] -fn bench_from_fn_0100(b: &mut Bencher) { - do_bench_from_fn(b, 100) -} - -#[bench] -fn bench_from_fn_1000(b: &mut Bencher) { - do_bench_from_fn(b, 1000) -} - -fn do_bench_from_elem(b: &mut Bencher, src_len: usize) { - b.bytes = src_len as u64; - - b.iter(|| { - let dst: Vec = repeat(5).take(src_len).collect(); - assert_eq!(dst.len(), src_len); - assert!(dst.iter().all(|x| *x == 5)); - }) -} - -#[bench] -fn bench_from_elem_0000(b: &mut Bencher) { - do_bench_from_elem(b, 0) -} - -#[bench] -fn bench_from_elem_0010(b: &mut Bencher) { - do_bench_from_elem(b, 10) -} - -#[bench] -fn bench_from_elem_0100(b: &mut Bencher) { - do_bench_from_elem(b, 100) -} - -#[bench] -fn bench_from_elem_1000(b: &mut Bencher) { - do_bench_from_elem(b, 1000) -} - -fn do_bench_from_slice(b: &mut Bencher, src_len: usize) { - let src: Vec<_> = FromIterator::from_iter(0..src_len); - - b.bytes = src_len as u64; - - b.iter(|| { - let dst = src.clone()[..].to_vec(); - assert_eq!(dst.len(), src_len); - assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); - }); -} - -#[bench] -fn bench_from_slice_0000(b: &mut Bencher) { - do_bench_from_slice(b, 0) -} - -#[bench] -fn bench_from_slice_0010(b: &mut Bencher) { - do_bench_from_slice(b, 10) -} - -#[bench] -fn bench_from_slice_0100(b: &mut Bencher) { - do_bench_from_slice(b, 100) -} - -#[bench] -fn bench_from_slice_1000(b: &mut Bencher) { - do_bench_from_slice(b, 1000) -} - -fn do_bench_from_iter(b: &mut Bencher, src_len: usize) { - let src: Vec<_> = FromIterator::from_iter(0..src_len); - - b.bytes = src_len as u64; - - b.iter(|| { - let dst: Vec<_> = FromIterator::from_iter(src.clone()); - assert_eq!(dst.len(), src_len); - assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); - }); -} - -#[bench] -fn bench_from_iter_0000(b: &mut Bencher) { - do_bench_from_iter(b, 0) -} - -#[bench] -fn bench_from_iter_0010(b: &mut Bencher) { - do_bench_from_iter(b, 10) -} - -#[bench] -fn bench_from_iter_0100(b: &mut Bencher) { - do_bench_from_iter(b, 100) -} - -#[bench] -fn bench_from_iter_1000(b: &mut Bencher) { - do_bench_from_iter(b, 1000) -} - -fn do_bench_extend(b: &mut Bencher, dst_len: usize, src_len: usize) { - let dst: Vec<_> = FromIterator::from_iter(0..dst_len); - let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len); - - b.bytes = src_len as u64; - - b.iter(|| { - let mut dst = dst.clone(); - dst.extend(src.clone()); - assert_eq!(dst.len(), dst_len + src_len); - assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); - }); -} - -#[bench] -fn bench_extend_0000_0000(b: &mut Bencher) { - do_bench_extend(b, 0, 0) -} - -#[bench] -fn bench_extend_0000_0010(b: &mut Bencher) { - do_bench_extend(b, 0, 10) -} - -#[bench] -fn bench_extend_0000_0100(b: &mut Bencher) { - do_bench_extend(b, 0, 100) -} - -#[bench] -fn bench_extend_0000_1000(b: &mut Bencher) { - do_bench_extend(b, 0, 1000) -} - -#[bench] -fn bench_extend_0010_0010(b: &mut Bencher) { - do_bench_extend(b, 10, 10) -} - -#[bench] -fn bench_extend_0100_0100(b: &mut Bencher) { - do_bench_extend(b, 100, 100) -} - -#[bench] -fn bench_extend_1000_1000(b: &mut Bencher) { - do_bench_extend(b, 1000, 1000) -} - -fn do_bench_push_all(b: &mut Bencher, dst_len: usize, src_len: usize) { - let dst: Vec<_> = FromIterator::from_iter(0..dst_len); - let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len); - - b.bytes = src_len as u64; - - b.iter(|| { - let mut dst = dst.clone(); - dst.extend_from_slice(&src); - assert_eq!(dst.len(), dst_len + src_len); - assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); - }); -} - -#[bench] -fn bench_push_all_0000_0000(b: &mut Bencher) { - do_bench_push_all(b, 0, 0) -} - -#[bench] -fn bench_push_all_0000_0010(b: &mut Bencher) { - do_bench_push_all(b, 0, 10) -} - -#[bench] -fn bench_push_all_0000_0100(b: &mut Bencher) { - do_bench_push_all(b, 0, 100) -} - -#[bench] -fn bench_push_all_0000_1000(b: &mut Bencher) { - do_bench_push_all(b, 0, 1000) -} - -#[bench] -fn bench_push_all_0010_0010(b: &mut Bencher) { - do_bench_push_all(b, 10, 10) -} - -#[bench] -fn bench_push_all_0100_0100(b: &mut Bencher) { - do_bench_push_all(b, 100, 100) -} - -#[bench] -fn bench_push_all_1000_1000(b: &mut Bencher) { - do_bench_push_all(b, 1000, 1000) -} - -fn do_bench_push_all_move(b: &mut Bencher, dst_len: usize, src_len: usize) { - let dst: Vec<_> = FromIterator::from_iter(0..dst_len); - let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len); - - b.bytes = src_len as u64; - - b.iter(|| { - let mut dst = dst.clone(); - dst.extend(src.clone()); - assert_eq!(dst.len(), dst_len + src_len); - assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); - }); -} - -#[bench] -fn bench_push_all_move_0000_0000(b: &mut Bencher) { - do_bench_push_all_move(b, 0, 0) -} - -#[bench] -fn bench_push_all_move_0000_0010(b: &mut Bencher) { - do_bench_push_all_move(b, 0, 10) -} - -#[bench] -fn bench_push_all_move_0000_0100(b: &mut Bencher) { - do_bench_push_all_move(b, 0, 100) -} - -#[bench] -fn bench_push_all_move_0000_1000(b: &mut Bencher) { - do_bench_push_all_move(b, 0, 1000) -} - -#[bench] -fn bench_push_all_move_0010_0010(b: &mut Bencher) { - do_bench_push_all_move(b, 10, 10) -} - -#[bench] -fn bench_push_all_move_0100_0100(b: &mut Bencher) { - do_bench_push_all_move(b, 100, 100) -} - -#[bench] -fn bench_push_all_move_1000_1000(b: &mut Bencher) { - do_bench_push_all_move(b, 1000, 1000) -} - -fn do_bench_clone(b: &mut Bencher, src_len: usize) { - let src: Vec = FromIterator::from_iter(0..src_len); - - b.bytes = src_len as u64; - - b.iter(|| { - let dst = src.clone(); - assert_eq!(dst.len(), src_len); - assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); - }); -} - -#[bench] -fn bench_clone_0000(b: &mut Bencher) { - do_bench_clone(b, 0) -} - -#[bench] -fn bench_clone_0010(b: &mut Bencher) { - do_bench_clone(b, 10) -} - -#[bench] -fn bench_clone_0100(b: &mut Bencher) { - do_bench_clone(b, 100) -} - -#[bench] -fn bench_clone_1000(b: &mut Bencher) { - do_bench_clone(b, 1000) -} - -fn do_bench_clone_from(b: &mut Bencher, times: usize, dst_len: usize, src_len: usize) { - let dst: Vec<_> = FromIterator::from_iter(0..src_len); - let src: Vec<_> = FromIterator::from_iter(dst_len..dst_len + src_len); - - b.bytes = (times * src_len) as u64; - - b.iter(|| { - let mut dst = dst.clone(); - - for _ in 0..times { - dst.clone_from(&src); - - assert_eq!(dst.len(), src_len); - assert!(dst.iter().enumerate().all(|(i, x)| dst_len + i == *x)); - } - }); -} - -#[bench] -fn bench_clone_from_01_0000_0000(b: &mut Bencher) { - do_bench_clone_from(b, 1, 0, 0) -} - -#[bench] -fn bench_clone_from_01_0000_0010(b: &mut Bencher) { - do_bench_clone_from(b, 1, 0, 10) -} - -#[bench] -fn bench_clone_from_01_0000_0100(b: &mut Bencher) { - do_bench_clone_from(b, 1, 0, 100) -} - -#[bench] -fn bench_clone_from_01_0000_1000(b: &mut Bencher) { - do_bench_clone_from(b, 1, 0, 1000) -} - -#[bench] -fn bench_clone_from_01_0010_0010(b: &mut Bencher) { - do_bench_clone_from(b, 1, 10, 10) -} - -#[bench] -fn bench_clone_from_01_0100_0100(b: &mut Bencher) { - do_bench_clone_from(b, 1, 100, 100) -} - -#[bench] -fn bench_clone_from_01_1000_1000(b: &mut Bencher) { - do_bench_clone_from(b, 1, 1000, 1000) -} - -#[bench] -fn bench_clone_from_01_0010_0100(b: &mut Bencher) { - do_bench_clone_from(b, 1, 10, 100) -} - -#[bench] -fn bench_clone_from_01_0100_1000(b: &mut Bencher) { - do_bench_clone_from(b, 1, 100, 1000) -} - -#[bench] -fn bench_clone_from_01_0010_0000(b: &mut Bencher) { - do_bench_clone_from(b, 1, 10, 0) -} - -#[bench] -fn bench_clone_from_01_0100_0010(b: &mut Bencher) { - do_bench_clone_from(b, 1, 100, 10) -} - -#[bench] -fn bench_clone_from_01_1000_0100(b: &mut Bencher) { - do_bench_clone_from(b, 1, 1000, 100) -} - -#[bench] -fn bench_clone_from_10_0000_0000(b: &mut Bencher) { - do_bench_clone_from(b, 10, 0, 0) -} - -#[bench] -fn bench_clone_from_10_0000_0010(b: &mut Bencher) { - do_bench_clone_from(b, 10, 0, 10) -} - -#[bench] -fn bench_clone_from_10_0000_0100(b: &mut Bencher) { - do_bench_clone_from(b, 10, 0, 100) -} - -#[bench] -fn bench_clone_from_10_0000_1000(b: &mut Bencher) { - do_bench_clone_from(b, 10, 0, 1000) -} - -#[bench] -fn bench_clone_from_10_0010_0010(b: &mut Bencher) { - do_bench_clone_from(b, 10, 10, 10) -} - -#[bench] -fn bench_clone_from_10_0100_0100(b: &mut Bencher) { - do_bench_clone_from(b, 10, 100, 100) -} - -#[bench] -fn bench_clone_from_10_1000_1000(b: &mut Bencher) { - do_bench_clone_from(b, 10, 1000, 1000) -} - -#[bench] -fn bench_clone_from_10_0010_0100(b: &mut Bencher) { - do_bench_clone_from(b, 10, 10, 100) -} - -#[bench] -fn bench_clone_from_10_0100_1000(b: &mut Bencher) { - do_bench_clone_from(b, 10, 100, 1000) -} - -#[bench] -fn bench_clone_from_10_0010_0000(b: &mut Bencher) { - do_bench_clone_from(b, 10, 10, 0) -} - -#[bench] -fn bench_clone_from_10_0100_0010(b: &mut Bencher) { - do_bench_clone_from(b, 10, 100, 10) -} - -#[bench] -fn bench_clone_from_10_1000_0100(b: &mut Bencher) { - do_bench_clone_from(b, 10, 1000, 100) -} diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollectionstest/vec_deque.rs index bb60f888f8be6..1541061a19842 100644 --- a/src/libcollectionstest/vec_deque.rs +++ b/src/libcollectionstest/vec_deque.rs @@ -12,8 +12,6 @@ use std::collections::VecDeque; use std::fmt::Debug; use std::collections::vec_deque::Drain; -use test; - use self::Taggy::*; use self::Taggypar::*; @@ -124,51 +122,6 @@ fn test_index_out_of_bounds() { deq[3]; } -#[bench] -fn bench_new(b: &mut test::Bencher) { - b.iter(|| { - let ring: VecDeque = VecDeque::new(); - test::black_box(ring); - }) -} - -#[bench] -fn bench_grow_1025(b: &mut test::Bencher) { - b.iter(|| { - let mut deq = VecDeque::new(); - for i in 0..1025 { - deq.push_front(i); - } - test::black_box(deq); - }) -} - -#[bench] -fn bench_iter_1000(b: &mut test::Bencher) { - let ring: VecDeque<_> = (0..1000).collect(); - - b.iter(|| { - let mut sum = 0; - for &i in &ring { - sum += i; - } - test::black_box(sum); - }) -} - -#[bench] -fn bench_mut_iter_1000(b: &mut test::Bencher) { - let mut ring: VecDeque<_> = (0..1000).collect(); - - b.iter(|| { - let mut sum = 0; - for i in &mut ring { - sum += *i; - } - test::black_box(sum); - }) -} - #[derive(Clone, PartialEq, Debug)] enum Taggy { One(i32), diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index 4f7cd7b016d66..e847c7fa3a0ec 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -14,5 +14,5 @@ name = "coretest" path = "../libcoretest/lib.rs" [[bench]] -name = "corebench" -path = "../libcore/bench/lib.rs" +name = "corebenches" +path = "../libcore/benches/lib.rs" diff --git a/src/libcore/bench/any.rs b/src/libcore/benches/any.rs similarity index 100% rename from src/libcore/bench/any.rs rename to src/libcore/benches/any.rs diff --git a/src/libcore/bench/hash/mod.rs b/src/libcore/benches/hash/mod.rs similarity index 100% rename from src/libcore/bench/hash/mod.rs rename to src/libcore/benches/hash/mod.rs diff --git a/src/libcore/bench/hash/sip.rs b/src/libcore/benches/hash/sip.rs similarity index 100% rename from src/libcore/bench/hash/sip.rs rename to src/libcore/benches/hash/sip.rs diff --git a/src/libcore/bench/iter.rs b/src/libcore/benches/iter.rs similarity index 100% rename from src/libcore/bench/iter.rs rename to src/libcore/benches/iter.rs diff --git a/src/libcore/bench/lib.rs b/src/libcore/benches/lib.rs similarity index 100% rename from src/libcore/bench/lib.rs rename to src/libcore/benches/lib.rs diff --git a/src/libcore/bench/mem.rs b/src/libcore/benches/mem.rs similarity index 100% rename from src/libcore/bench/mem.rs rename to src/libcore/benches/mem.rs diff --git a/src/libcore/bench/num/dec2flt/mod.rs b/src/libcore/benches/num/dec2flt/mod.rs similarity index 100% rename from src/libcore/bench/num/dec2flt/mod.rs rename to src/libcore/benches/num/dec2flt/mod.rs diff --git a/src/libcore/bench/num/flt2dec/mod.rs b/src/libcore/benches/num/flt2dec/mod.rs similarity index 100% rename from src/libcore/bench/num/flt2dec/mod.rs rename to src/libcore/benches/num/flt2dec/mod.rs diff --git a/src/libcore/bench/num/flt2dec/strategy/dragon.rs b/src/libcore/benches/num/flt2dec/strategy/dragon.rs similarity index 100% rename from src/libcore/bench/num/flt2dec/strategy/dragon.rs rename to src/libcore/benches/num/flt2dec/strategy/dragon.rs diff --git a/src/libcore/bench/num/flt2dec/strategy/grisu.rs b/src/libcore/benches/num/flt2dec/strategy/grisu.rs similarity index 100% rename from src/libcore/bench/num/flt2dec/strategy/grisu.rs rename to src/libcore/benches/num/flt2dec/strategy/grisu.rs diff --git a/src/libcore/bench/num/mod.rs b/src/libcore/benches/num/mod.rs similarity index 100% rename from src/libcore/bench/num/mod.rs rename to src/libcore/benches/num/mod.rs diff --git a/src/libcore/bench/ops.rs b/src/libcore/benches/ops.rs similarity index 100% rename from src/libcore/bench/ops.rs rename to src/libcore/benches/ops.rs From b9757863df0c30fbff1a6b4c95c48342d25e9b4a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 6 Feb 2017 09:37:32 -0500 Subject: [PATCH 05/11] regr test --- src/test/incremental/issue-39569.rs | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/test/incremental/issue-39569.rs diff --git a/src/test/incremental/issue-39569.rs b/src/test/incremental/issue-39569.rs new file mode 100644 index 0000000000000..55e0436f0a80a --- /dev/null +++ b/src/test/incremental/issue-39569.rs @@ -0,0 +1,38 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for a weird corner case in our dep-graph reduction +// code. When we solve `CoerceUnsized`, we find no impls, so we +// don't end up with an edge to any HIR nodes, but it still gets +// preserved in the dep graph. + +// revisions:rpass1 rpass2 +// compile-flags: -Z query-dep-graph + +use std::sync::Arc; + +#[cfg(rpass1)] +struct Foo { x: usize } + +#[cfg(rpass1)] +fn main() { + let x: Arc = Arc::new(Foo { x: 22 }); + let y: Arc = x; +} + +#[cfg(rpass2)] +struct FooX { x: usize } + +#[cfg(rpass2)] +fn main() { + let x: Arc = Arc::new(Foo { x: 22 }); + let y: Arc = x; +} + From 4f5fc4e24219f64235f08ba91ccf4b447a8643ee Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 6 Feb 2017 10:20:23 -0500 Subject: [PATCH 06/11] fix case where some edges can't be recreated by expanding the graph cc #39569 -- almost certainly a fix for that --- src/librustc_incremental/persist/load.rs | 119 ++++++++++++++++------- src/test/incremental/issue-39569.rs | 2 +- 2 files changed, 85 insertions(+), 36 deletions(-) diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index b371ab6aa31bc..7724658a9d6fe 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -176,46 +176,32 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Recreate the edges in the graph that are still clean. let mut clean_work_products = FxHashSet(); let mut dirty_work_products = FxHashSet(); // incomplete; just used to suppress debug output + let mut extra_edges = vec![]; for (source, targets) in &edge_map { for target in targets { - // If the target is dirty, skip the edge. If this is an edge - // that targets a work-product, we can print the blame - // information now. - if let Some(blame) = dirty_raw_nodes.get(target) { - if let DepNode::WorkProduct(ref wp) = *target { - if tcx.sess.opts.debugging_opts.incremental_info { - if dirty_work_products.insert(wp.clone()) { - // It'd be nice to pretty-print these paths better than just - // using the `Debug` impls, but wev. - println!("incremental: module {:?} is dirty because {:?} \ - changed or was removed", - wp, - blame.map_def(|&index| { - Some(directory.def_path_string(tcx, index)) - }).unwrap()); - } - } - } - continue; - } - - // If the source is dirty, the target will be dirty. - assert!(!dirty_raw_nodes.contains_key(source)); - - // Retrace the source -> target edges to def-ids and then - // create an edge in the graph. Retracing may yield none if - // some of the data happens to have been removed; this ought - // to be impossible unless it is dirty, so we can unwrap. - let source_node = retraced.map(source).unwrap(); - let target_node = retraced.map(target).unwrap(); - let _task = tcx.dep_graph.in_task(target_node); - tcx.dep_graph.read(source_node); - if let DepNode::WorkProduct(ref wp) = *target { - clean_work_products.insert(wp.clone()); - } + process_edges(tcx, source, target, &edge_map, &directory, &retraced, &dirty_raw_nodes, + &mut clean_work_products, &mut dirty_work_products, &mut extra_edges); } } + // Subtle. Sometimes we have intermediate nodes that we can't recreate in the new graph. + // This is pretty unusual but it arises in a scenario like this: + // + // Hir(X) -> Foo(Y) -> Bar + // + // Note that the `Hir(Y)` is not an input to `Foo(Y)` -- this + // almost never happens, but can happen in some obscure + // scenarios. In that case, if `Y` is removed, then we can't + // recreate `Foo(Y)` (the def-id `Y` no longer exists); what we do + // then is to push the edge `Hir(X) -> Bar` onto `extra_edges` + // (along with any other targets of `Foo(Y)`). We will then add + // the edge from `Hir(X)` to `Bar` (or, if `Bar` itself cannot be + // recreated, to the targets of `Bar`). + while let Some((source, target)) = extra_edges.pop() { + process_edges(tcx, source, target, &edge_map, &directory, &retraced, &dirty_raw_nodes, + &mut clean_work_products, &mut dirty_work_products, &mut extra_edges); + } + // Add in work-products that are still clean, and delete those that are // dirty. reconcile_work_products(tcx, work_products, &clean_work_products); @@ -393,3 +379,66 @@ fn load_prev_metadata_hashes(tcx: TyCtxt, serialized_hashes.index_map.len()); } +fn process_edges<'a, 'tcx, 'edges>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + source: &'edges DepNode, + target: &'edges DepNode, + edges: &'edges FxHashMap, Vec>>, + directory: &DefIdDirectory, + retraced: &RetracedDefIdDirectory, + dirty_raw_nodes: &DirtyNodes, + clean_work_products: &mut FxHashSet>, + dirty_work_products: &mut FxHashSet>, + extra_edges: &mut Vec<(&'edges DepNode, &'edges DepNode)>) +{ + // If the target is dirty, skip the edge. If this is an edge + // that targets a work-product, we can print the blame + // information now. + if let Some(blame) = dirty_raw_nodes.get(target) { + if let DepNode::WorkProduct(ref wp) = *target { + if tcx.sess.opts.debugging_opts.incremental_info { + if dirty_work_products.insert(wp.clone()) { + // It'd be nice to pretty-print these paths better than just + // using the `Debug` impls, but wev. + println!("incremental: module {:?} is dirty because {:?} \ + changed or was removed", + wp, + blame.map_def(|&index| { + Some(directory.def_path_string(tcx, index)) + }).unwrap()); + } + } + } + return; + } + + // If the source is dirty, the target will be dirty. + assert!(!dirty_raw_nodes.contains_key(source)); + + // Retrace the source -> target edges to def-ids and then create + // an edge in the graph. Retracing may yield none if some of the + // data happens to have been removed. + if let Some(source_node) = retraced.map(source) { + if let Some(target_node) = retraced.map(target) { + let _task = tcx.dep_graph.in_task(target_node); + tcx.dep_graph.read(source_node); + if let DepNode::WorkProduct(ref wp) = *target { + clean_work_products.insert(wp.clone()); + } + } else { + // As discussed in `decode_dep_graph` above, sometimes the + // target cannot be recreated again, in which case we add + // edges to go from `source` to the targets of `target`. + extra_edges.extend( + edges[target].iter().map(|t| (source, t))); + } + } else { + // It's also possible that the source can't be created! But we + // can ignore such cases, because (a) if `source` is a HIR + // node, it would be considered dirty; and (b) in other cases, + // there must be some input to this node that is clean, and so + // we'll re-create the edges over in the case where target is + // undefined. + } +} + diff --git a/src/test/incremental/issue-39569.rs b/src/test/incremental/issue-39569.rs index 55e0436f0a80a..5b53e94825300 100644 --- a/src/test/incremental/issue-39569.rs +++ b/src/test/incremental/issue-39569.rs @@ -32,7 +32,7 @@ struct FooX { x: usize } #[cfg(rpass2)] fn main() { - let x: Arc = Arc::new(Foo { x: 22 }); + let x: Arc = Arc::new(FooX { x: 22 }); let y: Arc = x; } From 1ee88e516c367660f263f4db354602c5b848a2ca Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 5 Feb 2017 09:44:49 +0100 Subject: [PATCH 07/11] A few documentation improvements for `syntax::print::pp` * Moved algorithm explanation to module docs * Added ``` before and after the examples * Explanation of the `rbox`, `ibox` and `cbox` names * Added docs about the breaking types to `Breaks` --- src/libsyntax/print/pp.rs | 167 ++++++++++++++++++++------------------ 1 file changed, 89 insertions(+), 78 deletions(-) diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index 792239e721932..1d67c2a2c2b74 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -60,11 +60,95 @@ //! by two zero-length breaks. The algorithm will try its best to fit it on a //! line (which it can't) and so naturally place the content on its own line to //! avoid combining it with other lines and making matters even worse. +//! +//! # Explanation +//! +//! In case you do not have the paper, here is an explanation of what's going +//! on. +//! +//! There is a stream of input tokens flowing through this printer. +//! +//! The printer buffers up to 3N tokens inside itself, where N is linewidth. +//! Yes, linewidth is chars and tokens are multi-char, but in the worst +//! case every token worth buffering is 1 char long, so it's ok. +//! +//! Tokens are String, Break, and Begin/End to delimit blocks. +//! +//! Begin tokens can carry an offset, saying "how far to indent when you break +//! inside here", as well as a flag indicating "consistent" or "inconsistent" +//! breaking. Consistent breaking means that after the first break, no attempt +//! will be made to flow subsequent breaks together onto lines. Inconsistent +//! is the opposite. Inconsistent breaking example would be, say: +//! +//! ``` +//! foo(hello, there, good, friends) +//! ``` +//! +//! breaking inconsistently to become +//! +//! ``` +//! foo(hello, there +//! good, friends); +//! ``` +//! +//! whereas a consistent breaking would yield: +//! +//! ``` +//! foo(hello, +//! there +//! good, +//! friends); +//! ``` +//! +//! That is, in the consistent-break blocks we value vertical alignment +//! more than the ability to cram stuff onto a line. But in all cases if it +//! can make a block a one-liner, it'll do so. +//! +//! Carrying on with high-level logic: +//! +//! The buffered tokens go through a ring-buffer, 'tokens'. The 'left' and +//! 'right' indices denote the active portion of the ring buffer as well as +//! describing hypothetical points-in-the-infinite-stream at most 3N tokens +//! apart (i.e. "not wrapped to ring-buffer boundaries"). The paper will switch +//! between using 'left' and 'right' terms to denote the wrapped-to-ring-buffer +//! and point-in-infinite-stream senses freely. +//! +//! There is a parallel ring buffer, 'size', that holds the calculated size of +//! each token. Why calculated? Because for Begin/End pairs, the "size" +//! includes everything between the pair. That is, the "size" of Begin is +//! actually the sum of the sizes of everything between Begin and the paired +//! End that follows. Since that is arbitrarily far in the future, 'size' is +//! being rewritten regularly while the printer runs; in fact most of the +//! machinery is here to work out 'size' entries on the fly (and give up when +//! they're so obviously over-long that "infinity" is a good enough +//! approximation for purposes of line breaking). +//! +//! The "input side" of the printer is managed as an abstract process called +//! SCAN, which uses 'scan_stack', to manage calculating 'size'. SCAN is, in +//! other words, the process of calculating 'size' entries. +//! +//! The "output side" of the printer is managed by an abstract process called +//! PRINT, which uses 'print_stack', 'margin' and 'space' to figure out what to +//! do with each token/size pair it consumes as it goes. It's trying to consume +//! the entire buffered window, but can't output anything until the size is >= +//! 0 (sizes are set to negative while they're pending calculation). +//! +//! So SCAN takes input and buffers tokens and pending calculations, while +//! PRINT gobbles up completed calculations and tokens from the buffer. The +//! theory is that the two can never get more than 3N tokens apart, because +//! once there's "obviously" too much data to fit on a line, in a size +//! calculation, SCAN will write "infinity" to the size and let PRINT consume +//! it. +//! +//! In this implementation (following the paper, again) the SCAN process is +//! the method called `Printer::pretty_print`, and the 'PRINT' process is the method +//! called `Printer::print`. use std::collections::VecDeque; use std::fmt; use std::io; +/// How to break. Described in more detail in the module docs. #[derive(Clone, Copy, PartialEq)] pub enum Breaks { Consistent, @@ -177,81 +261,6 @@ pub fn mk_printer<'a>(out: Box, linewidth: usize) -> Printer<'a> { } } - -/// In case you do not have the paper, here is an explanation of what's going -/// on. -/// -/// There is a stream of input tokens flowing through this printer. -/// -/// The printer buffers up to 3N tokens inside itself, where N is linewidth. -/// Yes, linewidth is chars and tokens are multi-char, but in the worst -/// case every token worth buffering is 1 char long, so it's ok. -/// -/// Tokens are String, Break, and Begin/End to delimit blocks. -/// -/// Begin tokens can carry an offset, saying "how far to indent when you break -/// inside here", as well as a flag indicating "consistent" or "inconsistent" -/// breaking. Consistent breaking means that after the first break, no attempt -/// will be made to flow subsequent breaks together onto lines. Inconsistent -/// is the opposite. Inconsistent breaking example would be, say: -/// -/// foo(hello, there, good, friends) -/// -/// breaking inconsistently to become -/// -/// foo(hello, there -/// good, friends); -/// -/// whereas a consistent breaking would yield: -/// -/// foo(hello, -/// there -/// good, -/// friends); -/// -/// That is, in the consistent-break blocks we value vertical alignment -/// more than the ability to cram stuff onto a line. But in all cases if it -/// can make a block a one-liner, it'll do so. -/// -/// Carrying on with high-level logic: -/// -/// The buffered tokens go through a ring-buffer, 'tokens'. The 'left' and -/// 'right' indices denote the active portion of the ring buffer as well as -/// describing hypothetical points-in-the-infinite-stream at most 3N tokens -/// apart (i.e. "not wrapped to ring-buffer boundaries"). The paper will switch -/// between using 'left' and 'right' terms to denote the wrapped-to-ring-buffer -/// and point-in-infinite-stream senses freely. -/// -/// There is a parallel ring buffer, 'size', that holds the calculated size of -/// each token. Why calculated? Because for Begin/End pairs, the "size" -/// includes everything between the pair. That is, the "size" of Begin is -/// actually the sum of the sizes of everything between Begin and the paired -/// End that follows. Since that is arbitrarily far in the future, 'size' is -/// being rewritten regularly while the printer runs; in fact most of the -/// machinery is here to work out 'size' entries on the fly (and give up when -/// they're so obviously over-long that "infinity" is a good enough -/// approximation for purposes of line breaking). -/// -/// The "input side" of the printer is managed as an abstract process called -/// SCAN, which uses 'scan_stack', to manage calculating 'size'. SCAN is, in -/// other words, the process of calculating 'size' entries. -/// -/// The "output side" of the printer is managed by an abstract process called -/// PRINT, which uses 'print_stack', 'margin' and 'space' to figure out what to -/// do with each token/size pair it consumes as it goes. It's trying to consume -/// the entire buffered window, but can't output anything until the size is >= -/// 0 (sizes are set to negative while they're pending calculation). -/// -/// So SCAN takes input and buffers tokens and pending calculations, while -/// PRINT gobbles up completed calculations and tokens from the buffer. The -/// theory is that the two can never get more than 3N tokens apart, because -/// once there's "obviously" too much data to fit on a line, in a size -/// calculation, SCAN will write "infinity" to the size and let PRINT consume -/// it. -/// -/// In this implementation (following the paper, again) the SCAN process is -/// the method called 'pretty_print', and the 'PRINT' process is the method -/// called 'print'. pub struct Printer<'a> { pub out: Box, buf_len: usize, @@ -292,7 +301,7 @@ impl<'a> Printer<'a> { pub fn last_token(&mut self) -> Token { self.buf[self.right].token.clone() } - // be very careful with this! + /// be very careful with this! pub fn replace_last_token(&mut self, t: Token) { self.buf[self.right].token = t; } @@ -571,8 +580,8 @@ impl<'a> Printer<'a> { } // Convenience functions to talk to the printer. -// -// "raw box" + +/// "raw box" pub fn rbox(p: &mut Printer, indent: usize, b: Breaks) -> io::Result<()> { p.pretty_print(Token::Begin(BeginToken { offset: indent as isize, @@ -580,10 +589,12 @@ pub fn rbox(p: &mut Printer, indent: usize, b: Breaks) -> io::Result<()> { })) } +/// Inconsistent breaking box pub fn ibox(p: &mut Printer, indent: usize) -> io::Result<()> { rbox(p, indent, Breaks::Inconsistent) } +/// Consistent breaking box pub fn cbox(p: &mut Printer, indent: usize) -> io::Result<()> { rbox(p, indent, Breaks::Consistent) } From 2a345bbcc1e6332241883f784896ea93d2a7ccb3 Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Fri, 3 Feb 2017 17:39:41 -0500 Subject: [PATCH 08/11] make Child::try_wait return io::Result> This is much nicer for callers who want to short-circuit real I/O errors with `?`, because they can write this if let Some(status) = foo.try_wait()? { ... } else { ... } instead of this match foo.try_wait() { Ok(status) => { ... } Err(err) if err.kind() == io::ErrorKind::WouldBlock => { ... } Err(err) => return Err(err), } The original design of `try_wait` was patterned after the `Read` and `Write` traits, which support both blocking and non-blocking implementations in a single API. But since `try_wait` is never blocking, it makes sense to optimize for the non-blocking case. Tracking issue: https://github.com/rust-lang/rust/issues/38903 --- src/libstd/process.rs | 15 +++++++-------- src/libstd/sys/redox/process.rs | 8 ++++---- .../sys/unix/process/process_fuchsia.rs | 6 +++--- src/libstd/sys/unix/process/process_unix.rs | 8 ++++---- src/libstd/sys/windows/process.rs | 6 +++--- src/test/run-pass/try-wait.rs | 19 +++++++++---------- 6 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index c16b97ebda5e3..4ff35738b50fb 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -844,9 +844,9 @@ impl Child { /// guaranteed to repeatedly return a successful exit status so long as the /// child has already exited. /// - /// If the child has exited, then `Ok(status)` is returned. If the exit - /// status is not available at this time then an error is returned with the - /// error kind `WouldBlock`. If an error occurs, then that error is returned. + /// If the child has exited, then `Ok(Some(status))` is returned. If the + /// exit status is not available at this time then `Ok(None)` is returned. + /// If an error occurs, then that error is returned. /// /// Note that unlike `wait`, this function will not attempt to drop stdin. /// @@ -857,14 +857,13 @@ impl Child { /// ```no_run /// #![feature(process_try_wait)] /// - /// use std::io; /// use std::process::Command; /// /// let mut child = Command::new("ls").spawn().unwrap(); /// /// match child.try_wait() { - /// Ok(status) => println!("exited with: {}", status), - /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { + /// Ok(Some(status)) => println!("exited with: {}", status), + /// Ok(None) => { /// println!("status not ready yet, let's really wait"); /// let res = child.wait(); /// println!("result: {:?}", res); @@ -873,8 +872,8 @@ impl Child { /// } /// ``` #[unstable(feature = "process_try_wait", issue = "38903")] - pub fn try_wait(&mut self) -> io::Result { - self.handle.try_wait().map(ExitStatus) + pub fn try_wait(&mut self) -> io::Result> { + Ok(self.handle.try_wait()?.map(ExitStatus)) } /// Simultaneously waits for the child to exit and collect all remaining diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 50dcd44b42e92..60dc03fcf47e2 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -502,17 +502,17 @@ impl Process { Ok(ExitStatus(status as i32)) } - pub fn try_wait(&mut self) -> io::Result { + pub fn try_wait(&mut self) -> io::Result> { if let Some(status) = self.status { - return Ok(status) + return Ok(Some(status)) } let mut status = 0; let pid = cvt(syscall::waitpid(self.pid, &mut status, syscall::WNOHANG))?; if pid == 0 { - Err(io::Error::from_raw_os_error(syscall::EWOULDBLOCK)) + Ok(None) } else { self.status = Some(ExitStatus(status as i32)); - Ok(ExitStatus(status as i32)) + Ok(Some(ExitStatus(status as i32))) } } } diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs index 87acb0ed9b977..0bb2e0c1a83d4 100644 --- a/src/libstd/sys/unix/process/process_fuchsia.rs +++ b/src/libstd/sys/unix/process/process_fuchsia.rs @@ -165,7 +165,7 @@ impl Process { Ok(ExitStatus::new(proc_info.rec.return_code)) } - pub fn try_wait(&mut self) -> io::Result { + pub fn try_wait(&mut self) -> io::Result> { use default::Default; use sys::process::magenta::*; @@ -179,7 +179,7 @@ impl Process { match status { 0 => { }, // Success x if x == ERR_TIMED_OUT => { - return Err(io::Error::from(io::ErrorKind::WouldBlock)); + return Ok(None); }, _ => { panic!("Failed to wait on process handle: {}", status); }, } @@ -192,7 +192,7 @@ impl Process { return Err(io::Error::new(io::ErrorKind::InvalidData, "Failed to get exit status of process")); } - Ok(ExitStatus::new(proc_info.rec.return_code)) + Ok(Some(ExitStatus::new(proc_info.rec.return_code))) } } diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 0dc1739c1a15a..bbc987209e300 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -249,19 +249,19 @@ impl Process { Ok(ExitStatus::new(status)) } - pub fn try_wait(&mut self) -> io::Result { + pub fn try_wait(&mut self) -> io::Result> { if let Some(status) = self.status { - return Ok(status) + return Ok(Some(status)) } let mut status = 0 as c_int; let pid = cvt(unsafe { libc::waitpid(self.pid, &mut status, libc::WNOHANG) })?; if pid == 0 { - Err(io::Error::from_raw_os_error(libc::EWOULDBLOCK)) + Ok(None) } else { self.status = Some(ExitStatus::new(status)); - Ok(ExitStatus::new(status)) + Ok(Some(ExitStatus::new(status))) } } } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index d2ad81023e7fe..1afb3728c9d72 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -340,18 +340,18 @@ impl Process { } } - pub fn try_wait(&mut self) -> io::Result { + pub fn try_wait(&mut self) -> io::Result> { unsafe { match c::WaitForSingleObject(self.handle.raw(), 0) { c::WAIT_OBJECT_0 => {} c::WAIT_TIMEOUT => { - return Err(io::Error::from_raw_os_error(c::WSAEWOULDBLOCK)) + return Ok(None); } _ => return Err(io::Error::last_os_error()), } let mut status = 0; cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?; - Ok(ExitStatus(status)) + Ok(Some(ExitStatus(status))) } } diff --git a/src/test/run-pass/try-wait.rs b/src/test/run-pass/try-wait.rs index d9826373cceb0..be87b7b3c87e4 100644 --- a/src/test/run-pass/try-wait.rs +++ b/src/test/run-pass/try-wait.rs @@ -13,7 +13,6 @@ #![feature(process_try_wait)] use std::env; -use std::io; use std::process::Command; use std::thread; use std::time::Duration; @@ -32,17 +31,17 @@ fn main() { .arg("sleep") .spawn() .unwrap(); - let err = me.try_wait().unwrap_err(); - assert_eq!(err.kind(), io::ErrorKind::WouldBlock); - let err = me.try_wait().unwrap_err(); - assert_eq!(err.kind(), io::ErrorKind::WouldBlock); + let maybe_status = me.try_wait().unwrap(); + assert!(maybe_status.is_none()); + let maybe_status = me.try_wait().unwrap(); + assert!(maybe_status.is_none()); me.kill().unwrap(); me.wait().unwrap(); - let status = me.try_wait().unwrap(); + let status = me.try_wait().unwrap().unwrap(); assert!(!status.success()); - let status = me.try_wait().unwrap(); + let status = me.try_wait().unwrap().unwrap(); assert!(!status.success()); let mut me = Command::new(env::current_exe().unwrap()) @@ -51,17 +50,17 @@ fn main() { .unwrap(); loop { match me.try_wait() { - Ok(res) => { + Ok(Some(res)) => { assert!(res.success()); break } - Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { + Ok(None) => { thread::sleep(Duration::from_millis(1)); } Err(e) => panic!("error in try_wait: {}", e), } } - let status = me.try_wait().unwrap(); + let status = me.try_wait().unwrap().unwrap(); assert!(status.success()); } From 87b8c9eaf211e91ea1eef9427bd0b05fef5e58cf Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Fri, 3 Feb 2017 14:58:13 +0000 Subject: [PATCH 09/11] Add Emscripten-specific linker It claims to accept most GNU linker options, but in fact most of them have no effect and instead it requires some special options which are easier to handle in a separate trait. Currently added: - `export_symbols`: works on executables as special Emscripten case since staticlibs/dylibs aren't compiled to JS, while exports are required to be accessible from JS. Fixes #39171. - `optimize` - translates Rust's optimization level to Emscripten optimization level (whether passed via `-C opt-level=...` or `-O...`). Fixes #36899. - `debuginfo` - translates debug info; Emscripten has 5 debug levels while Rust has 3, so chose to translate `-C debuginfo=1` to `-g3` (preserves whitespace, variable and function names for easy debugging). Fixes #36901. - `no_default_libraries` - tells Emscripten to exlude `memcpy` and co. --- src/Cargo.lock | 1 + src/librustc_trans/Cargo.toml | 1 + src/librustc_trans/back/link.rs | 3 +- src/librustc_trans/back/linker.rs | 159 +++++++++++++++++++++++++++++- src/librustc_trans/lib.rs | 1 + 5 files changed, 162 insertions(+), 3 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 06cf32ad0f6b5..75ac4c2a3d69a 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -512,6 +512,7 @@ dependencies = [ "rustc_incremental 0.0.0", "rustc_llvm 0.0.0", "rustc_platform_intrinsics 0.0.0", + "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index fa48a63b6b8f5..b5c67ad998b69 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -22,5 +22,6 @@ rustc_errors = { path = "../librustc_errors" } rustc_incremental = { path = "../librustc_incremental" } rustc_llvm = { path = "../librustc_llvm" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } +serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 4ddf8a883bc48..696a8ea200a54 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -823,7 +823,8 @@ fn link_args(cmd: &mut Linker, // If we're building a dynamic library then some platforms need to make sure // that all symbols are exported correctly from the dynamic library. - if crate_type != config::CrateTypeExecutable { + if crate_type != config::CrateTypeExecutable || + sess.target.target.options.is_like_emscripten { cmd.export_symbols(tmpdir, crate_type); } diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 7f352f1da517d..29fba51e28b68 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -23,8 +23,8 @@ use back::symbol_export::{self, ExportedSymbols}; use middle::dependency_format::Linkage; use rustc::hir::def_id::{LOCAL_CRATE, CrateNum}; use session::Session; -use session::config::CrateType; -use session::config; +use session::config::{self, CrateType, OptLevel, DebugInfoLevel}; +use serialize::{json, Encoder}; /// For all the linkers we support, and information they might /// need out of the shared crate context before we get rid of it. @@ -51,6 +51,12 @@ impl<'a, 'tcx> LinkerInfo { sess: sess, info: self }) as Box + } else if sess.target.target.options.is_like_emscripten { + Box::new(EmLinker { + cmd: cmd, + sess: sess, + info: self + }) as Box } else { Box::new(GnuLinker { cmd: cmd, @@ -488,6 +494,155 @@ impl<'a> Linker for MsvcLinker<'a> { } } +pub struct EmLinker<'a> { + cmd: &'a mut Command, + sess: &'a Session, + info: &'a LinkerInfo +} + +impl<'a> Linker for EmLinker<'a> { + fn include_path(&mut self, path: &Path) { + self.cmd.arg("-L").arg(path); + } + + fn link_staticlib(&mut self, lib: &str) { + self.cmd.arg("-l").arg(lib); + } + + fn output_filename(&mut self, path: &Path) { + self.cmd.arg("-o").arg(path); + } + + fn add_object(&mut self, path: &Path) { + self.cmd.arg(path); + } + + fn link_dylib(&mut self, lib: &str) { + // Emscripten always links statically + self.link_staticlib(lib); + } + + fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) { + // not supported? + self.link_staticlib(lib); + } + + fn link_whole_rlib(&mut self, lib: &Path) { + // not supported? + self.link_rlib(lib); + } + + fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { + self.link_dylib(lib); + } + + fn link_rlib(&mut self, lib: &Path) { + self.add_object(lib); + } + + fn position_independent_executable(&mut self) { + // noop + } + + fn args(&mut self, args: &[String]) { + self.cmd.args(args); + } + + fn framework_path(&mut self, _path: &Path) { + bug!("frameworks are not supported on Emscripten") + } + + fn link_framework(&mut self, _framework: &str) { + bug!("frameworks are not supported on Emscripten") + } + + fn gc_sections(&mut self, _keep_metadata: bool) { + // noop + } + + fn optimize(&mut self) { + // Emscripten performs own optimizations + self.cmd.arg(match self.sess.opts.optimize { + OptLevel::No => "-O0", + OptLevel::Less => "-O1", + OptLevel::Default => "-O2", + OptLevel::Aggressive => "-O3", + OptLevel::Size => "-Os", + OptLevel::SizeMin => "-Oz" + }); + } + + fn debuginfo(&mut self) { + // Preserve names or generate source maps depending + // on debug info + self.cmd.arg(match self.sess.opts.debuginfo { + DebugInfoLevel::NoDebugInfo => "-g0", + DebugInfoLevel::LimitedDebugInfo => "-g3", + DebugInfoLevel::FullDebugInfo => "-g4" + }); + } + + fn no_default_libraries(&mut self) { + self.cmd.arg("-s"); + self.cmd.arg("DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"); + } + + fn build_dylib(&mut self, _out_filename: &Path) { + bug!("building dynamic library is unsupported on Emscripten") + } + + fn whole_archives(&mut self) { + // noop + } + + fn no_whole_archives(&mut self) { + // noop + } + + fn hint_static(&mut self) { + // noop + } + + fn hint_dynamic(&mut self) { + // noop + } + + fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) { + let mut arg = OsString::new(); + + let symbols = &self.info.exports[&crate_type]; + + debug!("EXPORTED SYMBOLS:"); + + self.cmd.arg("-s"); + arg.push("EXPORTED_FUNCTIONS="); + let mut encoded = String::new(); + + { + let mut encoder = json::Encoder::new(&mut encoded); + let res = encoder.emit_seq(symbols.len(), |encoder| { + for (i, sym) in symbols.iter().enumerate() { + encoder.emit_seq_elt(i, |encoder| { + encoder.emit_str(&("_".to_string() + sym)) + })?; + } + Ok(()) + }); + if let Err(e) = res { + self.sess.fatal(&format!("failed to encode exported symbols: {}", e)); + } + } + debug!("{}", encoded); + arg.push(encoded); + + self.cmd.arg(arg); + } + + fn subsystem(&mut self, _subsystem: &str) { + // noop + } +} + fn exported_symbols(scx: &SharedCrateContext, exported_symbols: &ExportedSymbols, crate_type: CrateType) diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 21c92cb4a4ad2..1530fcda3d3ea 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -59,6 +59,7 @@ extern crate rustc_bitflags; #[macro_use] extern crate syntax; extern crate syntax_pos; extern crate rustc_errors as errors; +extern crate serialize; pub use rustc::session; pub use rustc::middle; From 7916e00f2bc343baa665f380084f0b0d8792afa4 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 7 Feb 2017 19:48:16 +0000 Subject: [PATCH 10/11] Bump stable release date --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index f26c0b6b61161..2df1a83db81ff 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,4 +1,4 @@ -Version 1.15.1 (2017-02-07) +Version 1.15.1 (2017-02-08) =========================== * [Fix IntoIter::as_mut_slice's signature][39466] From e53eaa385ea3eb53d15711f9ce5914f0485a0ddf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 7 Feb 2017 15:47:03 -0800 Subject: [PATCH 11/11] Rename manifest_version to manifest-version The current manifests encode this with a dash in the name, so we should preserve that! --- src/tools/build-manifest/src/main.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 8c15a6630a33c..548a11439f5cc 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -11,7 +11,7 @@ extern crate toml; extern crate rustc_serialize; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::env; use std::fs::File; use std::io::{self, Read, Write}; @@ -95,7 +95,6 @@ static MINGW: &'static [&'static str] = &[ "x86_64-pc-windows-gnu", ]; -#[derive(RustcEncodable)] struct Manifest { manifest_version: String, date: String, @@ -171,8 +170,18 @@ impl Builder { self.cargo_version = self.version("cargo", "x86_64-unknown-linux-gnu"); self.digest_and_sign(); - let manifest = self.build_manifest(); - let manifest = toml::encode(&manifest).to_string(); + let Manifest { manifest_version, date, pkg } = self.build_manifest(); + + // Unfortunately we can't use derive(RustcEncodable) here because the + // version field is called `manifest-version`, not `manifest_version`. + // In lieu of that just create the table directly here with a `BTreeMap` + // and wrap it up in a `Value::Table`. + let mut manifest = BTreeMap::new(); + manifest.insert("manifest-version".to_string(), + toml::encode(&manifest_version)); + manifest.insert("date".to_string(), toml::encode(&date)); + manifest.insert("pkg".to_string(), toml::encode(&pkg)); + let manifest = toml::Value::Table(manifest).to_string(); let filename = format!("channel-rust-{}.toml", self.channel); self.write_manifest(&manifest, &filename);