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/14] 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/14] [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/14] 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/14] 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/14] 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 fa0a728ed60586a9b5d3e7dc755c03c4424ea79b Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 6 Feb 2017 10:15:20 -0500 Subject: [PATCH 06/14] back: Limit the number of LLVM worker threads. --- src/librustc_trans/back/write.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index b3a2d66a07c11..9a761e17e75e8 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -27,6 +27,7 @@ use errors::emitter::Emitter; use syntax_pos::MultiSpan; use context::{is_pie_binary, get_reloc_model}; +use std::cmp; use std::ffi::CString; use std::fs; use std::path::{Path, PathBuf}; @@ -754,10 +755,13 @@ pub fn run_passes(sess: &Session, } // Process the work items, optionally using worker threads. - // NOTE: This code is not really adapted to incremental compilation where - // the compiler decides the number of codegen units (and will - // potentially create hundreds of them). - let num_workers = work_items.len() - 1; + // NOTE: We are hardcoding a limit of worker threads for now. With + // incremental compilation we can run into situations where we would + // open hundreds of threads otherwise -- which can make things slower + // if things don't fit into memory anymore, or can cause the compiler + // to crash because of too many open file handles. See #39280 for + // some discussion on how to improve this in the future. + let num_workers = cmp::min(work_items.len() - 1, 32); if num_workers <= 1 { run_work_singlethreaded(sess, &trans.exported_symbols, work_items); } else { From 4f5fc4e24219f64235f08ba91ccf4b447a8643ee Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 6 Feb 2017 10:20:23 -0500 Subject: [PATCH 07/14] 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 08/14] 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 b0803d4aedc06504cb4cb86f63beb6650ff67a8e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 6 Feb 2017 22:11:03 +0100 Subject: [PATCH 09/14] Display correct filename with --test option --- src/librustdoc/html/markdown.rs | 8 ++++--- src/librustdoc/markdown.rs | 6 +++--- src/librustdoc/test.rs | 37 +++++++++++++++++++-------------- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index e8ff8930bdd7d..e70030912db0e 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -35,6 +35,7 @@ use std::fmt::{self, Write}; use std::slice; use std::str; use syntax::feature_gate::UnstableFeatures; +use syntax::codemap::Span; use html::render::derive_id; use html::toc::TocBuilder; @@ -429,7 +430,7 @@ pub fn render(w: &mut fmt::Formatter, } } -pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, start_line: usize) { +pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { extern fn block(_ob: *mut hoedown_buffer, text: *const hoedown_buffer, lang: *const hoedown_buffer, @@ -454,11 +455,12 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, start_line: }); let text = lines.collect::>().join("\n"); let line = tests.get_line() + line; + let filename = tests.get_filename(); tests.add_test(text.to_owned(), block_info.should_panic, block_info.no_run, block_info.ignore, block_info.test_harness, block_info.compile_fail, block_info.error_codes, - line); + line, filename); } } @@ -479,7 +481,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, start_line: } } - tests.set_line(start_line); + tests.set_position(position); unsafe { let ob = hoedown_buffer_new(DEF_OUNIT); let renderer = hoedown_html_renderer_new(0, 0); diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 49497957be980..70ef7c597e4d7 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -18,6 +18,7 @@ use getopts; use testing; use rustc::session::search_paths::SearchPaths; use rustc::session::config::Externs; +use syntax::codemap::DUMMY_SP; use externalfiles::{ExternalHtml, LoadStringError, load_string}; @@ -154,9 +155,8 @@ pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, let mut opts = TestOptions::default(); opts.no_crate_inject = true; let mut collector = Collector::new(input.to_string(), cfgs, libs, externs, - true, opts, maybe_sysroot, "input".to_string(), - None); - find_testable_code(&input_str, &mut collector, 0); + true, opts, maybe_sysroot, None); + find_testable_code(&input_str, &mut collector, DUMMY_SP); test_args.insert(0, "rustdoctest".to_string()); testing::test_main(&test_args, collector.tests); 0 diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 6f38da4f24b0d..930cf401e7450 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -37,7 +37,7 @@ use rustc_trans::back::link; use syntax::ast; use syntax::codemap::CodeMap; use syntax::feature_gate::UnstableFeatures; -use syntax_pos::{BytePos, DUMMY_SP, Pos}; +use syntax_pos::{BytePos, DUMMY_SP, Pos, Span}; use errors; use errors::emitter::ColorConfig; @@ -97,7 +97,6 @@ pub fn run(input: &str, link::find_crate_name(None, &hir_forest.krate().attrs, &input) }); let opts = scrape_test_config(hir_forest.krate()); - let filename = input_path.to_str().unwrap_or("").to_owned(); let mut collector = Collector::new(crate_name, cfgs, libs, @@ -105,7 +104,6 @@ pub fn run(input: &str, false, opts, maybe_sysroot, - filename, Some(codemap)); { @@ -391,15 +389,14 @@ pub struct Collector { cratename: String, opts: TestOptions, maybe_sysroot: Option, - filename: String, - start_line: usize, + position: Span, codemap: Option>, } impl Collector { pub fn new(cratename: String, cfgs: Vec, libs: SearchPaths, externs: Externs, use_headers: bool, opts: TestOptions, maybe_sysroot: Option, - filename: String, codemap: Option>) -> Collector { + codemap: Option>) -> Collector { Collector { tests: Vec::new(), names: Vec::new(), @@ -412,8 +409,7 @@ impl Collector { cratename: cratename, opts: opts, maybe_sysroot: maybe_sysroot, - filename: filename, - start_line: 0, + position: DUMMY_SP, codemap: codemap, } } @@ -421,8 +417,8 @@ impl Collector { pub fn add_test(&mut self, test: String, should_panic: bool, no_run: bool, should_ignore: bool, as_test_harness: bool, compile_fail: bool, error_codes: Vec, - line: usize) { - let name = format!("{} - line {}", self.filename, line); + line: usize, filename: String) { + let name = format!("{} - line {}", filename, line); self.cnt += 1; let cfgs = self.cfgs.clone(); let libs = self.libs.clone(); @@ -467,16 +463,25 @@ impl Collector { } pub fn get_line(&self) -> usize { - if let Some(ref codemap) = self.codemap{ - let line = codemap.lookup_char_pos(BytePos(self.start_line as u32)).line; + if let Some(ref codemap) = self.codemap { + let line = self.position.lo.to_usize(); + let line = codemap.lookup_char_pos(BytePos(line as u32)).line; if line > 0 { line - 1 } else { line } } else { - self.start_line + 0 } } - pub fn set_line(&mut self, start_line: usize) { - self.start_line = start_line; + pub fn set_position(&mut self, position: Span) { + self.position = position; + } + + pub fn get_filename(&self) -> String { + if let Some(ref codemap) = self.codemap { + codemap.span_to_filename(self.position) + } else { + "".to_owned() + } } pub fn register_header(&mut self, name: &str, level: u32) { @@ -520,7 +525,7 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { if let Some(doc) = attrs.doc_value() { self.collector.cnt = 0; markdown::find_testable_code(doc, self.collector, - attrs.span.unwrap_or(DUMMY_SP).lo.to_usize()); + attrs.span.unwrap_or(DUMMY_SP)); } nested(self); From 2a345bbcc1e6332241883f784896ea93d2a7ccb3 Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Fri, 3 Feb 2017 17:39:41 -0500 Subject: [PATCH 10/14] 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 37887fce118cf568bb6d3956c76a868bdd098023 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 7 Feb 2017 11:39:42 -0800 Subject: [PATCH 11/14] rustbuild: Clean build/dist on `make clean` Prevents stale artifacts from sticking around by accident! --- src/bootstrap/clean.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index e7655458aed8a..a66ed46fe464f 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -24,6 +24,7 @@ use Build; pub fn clean(build: &Build) { rm_rf(build, "tmp".as_ref()); rm_rf(build, &build.out.join("tmp")); + rm_rf(build, &build.out.join("dist")); for host in build.config.host.iter() { let entries = match build.out.join(host).read_dir() { From 7916e00f2bc343baa665f380084f0b0d8792afa4 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 7 Feb 2017 19:48:16 +0000 Subject: [PATCH 12/14] 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 13/14] 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); From d2f8abf2549304b3b67ac6e837d046ddf02c2cd6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 6 Feb 2017 23:28:31 +0100 Subject: [PATCH 14/14] Add more test for rustdoc --test --- src/test/rustdoc/test_option_check/bar.rs | 19 +++++ src/test/rustdoc/test_option_check/test.rs | 2 + src/tools/compiletest/src/runtest.rs | 83 +++++++++++++++------- 3 files changed, 79 insertions(+), 25 deletions(-) create mode 100644 src/test/rustdoc/test_option_check/bar.rs diff --git a/src/test/rustdoc/test_option_check/bar.rs b/src/test/rustdoc/test_option_check/bar.rs new file mode 100644 index 0000000000000..51daa80752622 --- /dev/null +++ b/src/test/rustdoc/test_option_check/bar.rs @@ -0,0 +1,19 @@ +// 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. + +// compile-flags: --test +// check-test-line-numbers-match + +/// This looks like another awesome test! +/// +/// ``` +/// println!("foo?"); +/// ``` +pub fn foooo() {} diff --git a/src/test/rustdoc/test_option_check/test.rs b/src/test/rustdoc/test_option_check/test.rs index b2afe43204d41..a9578c5f434a2 100644 --- a/src/test/rustdoc/test_option_check/test.rs +++ b/src/test/rustdoc/test_option_check/test.rs @@ -11,6 +11,8 @@ // compile-flags: --test // check-test-line-numbers-match +pub mod bar; + /// This is a Foo; /// /// ``` diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index a8c46722e163b..4e527661df72e 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -30,6 +30,7 @@ use std::io::{self, BufReader}; use std::path::{Path, PathBuf}; use std::process::{Command, Output, ExitStatus}; use std::str; +use std::collections::HashMap; use extract_gdb_version; @@ -1902,17 +1903,28 @@ actual:\n\ } } - fn check_rustdoc_test_option(&self, res: ProcRes) { - let mut file = fs::File::open(&self.testpaths.file) + fn get_lines>(&self, path: &P, + mut other_files: Option<&mut Vec>) -> Vec { + let mut file = fs::File::open(path) .expect("markdown_test_output_check_entry File::open failed"); let mut content = String::new(); file.read_to_string(&mut content) .expect("markdown_test_output_check_entry read_to_string failed"); let mut ignore = false; - let mut v: Vec = - content.lines() - .enumerate() - .filter_map(|(line_nb, line)| { + content.lines() + .enumerate() + .filter_map(|(line_nb, line)| { + if (line.trim_left().starts_with("pub mod ") || + line.trim_left().starts_with("mod ")) && + line.ends_with(";") { + if let Some(ref mut other_files) = other_files { + other_files.push(line.rsplit("mod ") + .next() + .unwrap() + .replace(";", "")); + } + None + } else { let sline = line.split("///").last().unwrap_or(""); let line = sline.trim_left(); if line.starts_with("```") { @@ -1926,8 +1938,21 @@ actual:\n\ } else { None } - }) - .collect(); + } + }) + .collect() + } + + fn check_rustdoc_test_option(&self, res: ProcRes) { + let mut other_files = Vec::new(); + let mut files: HashMap> = HashMap::new(); + files.insert(self.testpaths.file.to_str().unwrap().to_owned(), + self.get_lines(&self.testpaths.file, Some(&mut other_files))); + for other_file in other_files { + let mut path = self.testpaths.file.clone(); + path.set_file_name(&format!("{}.rs", other_file)); + files.insert(path.to_str().unwrap().to_owned(), self.get_lines(&path, None)); + } let mut tested = 0; for _ in res.stdout.split("\n") @@ -1935,27 +1960,35 @@ actual:\n\ .inspect(|s| { let tmp: Vec<&str> = s.split(" - line ").collect(); if tmp.len() == 2 { - tested += 1; - let line = tmp[1].split(" ...") - .next() - .unwrap_or("0") - .parse() - .unwrap_or(0); - if let Ok(pos) = v.binary_search(&line) { - v.remove(pos); - } else { - self.fatal_proc_rec( - &format!("Not found doc test: \"{}\" in {:?}", s, v), - &res); + let path = tmp[0].rsplit("test ").next().unwrap(); + if let Some(ref mut v) = files.get_mut(path) { + tested += 1; + let line = tmp[1].split(" ...") + .next() + .unwrap_or("0") + .parse() + .unwrap_or(0); + if let Ok(pos) = v.binary_search(&line) { + v.remove(pos); + } else { + self.fatal_proc_rec( + &format!("Not found doc test: \"{}\" in \"{}\":{:?}", + s, path, v), + &res); + } } } }) {} if tested == 0 { - self.fatal_proc_rec("No test has been found", &res); - } else if v.len() != 0 { - self.fatal_proc_rec(&format!("Not found test at line{} {:?}", - if v.len() > 1 { "s" } else { "" }, v), - &res); + self.fatal_proc_rec(&format!("No test has been found... {:?}", files), &res); + } else { + for (entry, v) in &files { + if v.len() != 0 { + self.fatal_proc_rec(&format!("Not found test at line{} \"{}\":{:?}", + if v.len() > 1 { "s" } else { "" }, entry, v), + &res); + } + } } }