Skip to content

DataProtocol and new inline Data #20225

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 13, 2018

Conversation

phausler
Copy link
Contributor

@phausler phausler commented Nov 1, 2018

This is an implementation of DataProtocol and a new smaller and leaner struct Data. The major change here is that we now promise that all Data's are contiguous. In order to enforce this requisite we added a new protocol to define contiguous collections (aptly named ContiguousCollection). This protocol is a draft of the work in progress proposed API for the standard library. Additionally it offers a direct byte accessor if safe on sequence to unify the sequence initialization to allow for fast paths.

Data itself now is represented in 16 bytes(on 64 bit platforms). This allows it to be stored in existentials without needing to heap allocate. Additionally during this refactor to shrink the representation we were able to make similar wins to the small string optimization so that we can store Data's on the stack when under a platform limit. This makes small Data structures never have to heap allocate. For example: Data() has zero heap allocations and Data([0xd, 0xa]) wont heap allocate for the storage of the data either since small representations can be stored completely on the stack efficiently. Larger data or slices however will still have a reference type storing the backing allocation as they did before. Our hope is that this will reduce the traffic on malloc which will reduce memory fragmentation and be considerably more efficient for small buffers.

//
//===----------------------------------------------------------------------===//


Copy link
Contributor Author

@phausler phausler Nov 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@airspeedswift this is what we are expecting for ContiguousCollection. Let me know if we need to adjust this. I presume our work will just be predicated on approval of your proposals for this. I just wanted to get this churning on CI first and iron out any performance issues before hand.

return try body(UnsafeRawBufferPointer(start: ptr, count: len))
}
}
extension UnsafeBufferPointer: _HasContiguousBytes {}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@milseman I presume the _HasContiguousBytes needs to remain for ABI stability. But the functionality was moved to ContiguousCollection. Do you foresee any issue with this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(We discussed this a bit yesterday — the primary use here for _HasContiguousBytes is as an existential, so, ContiguousCollection can't be used directly. However, it might be possible to parent ContiguousCollection on something like this which exposes the functionality anyway.)

@@ -548,6 +548,10 @@ public protocol Sequence {
__consuming func _copyContents(
initializing ptr: UnsafeMutableBufferPointer<Element>
) -> (Iterator,UnsafeMutableBufferPointer<Element>.Index)

func withUnsafeBytesIfSupported<T>(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@airspeedswift Again this is our presumption of spelling for the Sequence methods

@@ -142,7 +163,7 @@ func sampleData(_ type: SampleKind) -> Data {
}

func benchmark_AccessBytes(_ N: Int, _ data: Data) {
for _ in 1...10000*N {
for _ in 0..<10000*N {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eeckstein another surprising performance hit, I noticed some really heavy traffic on ClosedRange<Int>.count (it seems O(N)?!) Changing to Range<Int> reduced the benchmark chatter.

return CollectionOfOne(self)
}

public var _borrowedBytes: (buffer: UnsafeRawBufferPointer, owner: Any)? {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@airspeedswift this is a potential optimization point we would really like to have but is currently completely removable.

}

public var _borrowedBytes: (buffer: UnsafeRawBufferPointer, owner: Any)? {
return withUnsafeBytes { (buffer) -> (buffer: UnsafeRawBufferPointer, owner: Any) in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This, of course, pending approval from the stdlib for pulling tricks like this. The alternative is to move _borrowedBytes down into Sequence or something, which would really give us what we want: a way to get partial ownership of the underlying buffer without copying.



extension Data : MutableDataProtocol, MutableContiguousCollection {
// -- ContiguousCollection -------------------------------------------------
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a style thing I think we can likely get rid of dividers like these from my initial revision

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok will do

public protocol DataProtocol : RandomAccessCollection where Element == UInt8, SubSequence : DataProtocol {
// -- Core Requirements ----------------------------------------------------
// FIXME: Remove in favor of opaque type on `regions`.
associatedtype RegionSequence: Sequence where RegionSequence.Element : DataProtocol & ContiguousCollection
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a pretty big FIXME that we're going to need to address. We might want to file a Radar to track this separately internally.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Filed 45739467)

func copyBytes<DestinationType, R: RangeExpression>(to: UnsafeMutableBufferPointer<DestinationType>, from: R) -> Int where R.Bound == Index


var _borrowedBytes: (buffer: UnsafeRawBufferPointer, owner: Any)? { get }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we end up with this here, we should add a reminder to actually document this and what it does.

@@ -932,6 +932,8 @@ extension ContiguousArray: RangeReplaceableCollection {
}
}

extension ContiguousArray : ContiguousCollection {}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should EmptyCollection be ContiguousCollection?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It likely can't hurt, especially if we're doing this for CollectionOfOne.

}
}

extension CollectionOfOne : DataProtocol where Element == UInt8 {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should EmptyCollection where Element == UInt8 be DataProtocol?

@itaiferber
Copy link
Contributor

@swift-ci Please test

@itaiferber
Copy link
Contributor

@swift-ci Please benchmark

@swift-ci
Copy link
Contributor

swift-ci commented Nov 1, 2018

Build comment file:

Build failed before running benchmark.


@swift-ci
Copy link
Contributor

swift-ci commented Nov 1, 2018

Build failed
Swift Test OS X Platform
Git Sha - d3c992d653dbc44989a9f16fe42123f382e67f1f

@phausler
Copy link
Contributor Author

phausler commented Nov 1, 2018

@swift-ci Please test

@phausler
Copy link
Contributor Author

phausler commented Nov 1, 2018

@swift-ci Please benchmark

@swift-ci
Copy link
Contributor

swift-ci commented Nov 1, 2018

Build failed
Swift Test Linux Platform
Git Sha - d3c992d653dbc44989a9f16fe42123f382e67f1f

@swift-ci
Copy link
Contributor

swift-ci commented Nov 1, 2018

Build failed
Swift Test OS X Platform
Git Sha - d3c992d653dbc44989a9f16fe42123f382e67f1f

@swift-ci
Copy link
Contributor

swift-ci commented Nov 1, 2018

Build comment file:

Build failed before running benchmark.


@phausler
Copy link
Contributor Author

phausler commented Nov 1, 2018

@swift-ci Please test

@swift-ci
Copy link
Contributor

swift-ci commented Nov 1, 2018

Build failed
Swift Test Linux Platform
Git Sha - 8c7776cde41c8033697d562a997b3713c53c0470

@swift-ci
Copy link
Contributor

swift-ci commented Nov 1, 2018

Build failed
Swift Test OS X Platform
Git Sha - 8c7776cde41c8033697d562a997b3713c53c0470

Copy link
Contributor

@atrick atrick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, I'm just focussing on whether the new API's are type safe.

let concreteRange = range.relative(to: self)
let slice = self[concreteRange]

return ptr.withMemoryRebound(to: UInt8.self) { buffer -> Int in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, binding or rebinding the memory type is a huge red flag--I
only expect to see it a workaround for some legacy API. In this case,
you want to view a typed buffer as a sequence of bytes, so
ptr.withUnsafeBytes() is what you want. Why won't that work?


@discardableResult
public func copyBytes<R: RangeExpression>(to ptr: UnsafeMutableRawBufferPointer, from range: R) -> Int where R.Bound == Index {
let bound = ptr.bindMemory(to: UInt8.self)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't figure out why you want to bind memory here, but I can assure
you that it leads to undefined behavior.

_ body: (UnsafeBufferPointer<UInt8>) throws -> R
) rethrows -> R {
% if mutable:
return try body(UnsafeBufferPointer<UInt8>(self.bindMemory(to: UInt8.self)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yikes! This API is outright incompatible with Swift's type safety. If it was legal to do this, then we would have no reason for UnsafeRawPointer.

@itaiferber
Copy link
Contributor

itaiferber commented Nov 2, 2018

@atrick Please ignore my comments above — I realize where the deficiency in my mental model is. I must have previously missed the following paragraphs on typed memory from https://developer.apple.com/documentation/swift/unsaferawpointer:

Memory that has been bound to a type, whether it is initialized or uninitialized, is typically accessed using typed pointers—instances of UnsafePointer and UnsafeMutablePointer. Initialization, assignment, and deinitialization can be performed using UnsafeMutablePointer methods.

Memory that has been bound to a type can be rebound to a different type only after it has been deinitialized or if the bound type is a trivial type. Deinitializing typed memory does not unbind that memory’s type. The deinitialized memory can be reinitialized with values of the same type, bound to a new type, or deallocated.

Specifically, the fact that binding is not temporary is our issue here. I'll push out fixes tomorrow, but we might have an issue with conforming some pointer types to ContiguousCollection if this is the case. (Note that in this case, we are just trying to get a sketch of the stdlib bits in place based on what we've discussed with @airspeedswift and are not proposing implementations necessarily; we defer to your judgement on those.)

@swift-ci
Copy link
Contributor

swift-ci commented Dec 7, 2018

Build comment file:

Performance: -O

TEST OLD NEW DELTA RATIO
Regression
DataCreateMediumArray 2794 69893 +2401.5% 0.04x
DataCreateSmallArray 27452 654693 +2284.9% 0.04x
DataCreateEmptyArray 27125 593750 +2088.9% 0.05x
DataSetCountMedium 574 7035 +1125.6% 0.08x
ObjectiveCBridgeStubDataAppend 6084 44217 +626.8% 0.14x
StringToDataMedium 2617 9171 +250.4% 0.29x
StringToDataSmall 2548 5712 +124.2% 0.45x
StringToDataEmpty 2538 5248 +106.8% 0.48x
DataCreateMedium 17059 21882 +28.3% 0.78x
Improvement
DataCreateEmpty 23578 200 -99.2% 117.89x
DataAppendBytesSmall 4803 275 -94.3% 17.47x
DataAccessBytesMedium 1140 74 -93.5% 15.41x
DataAccessBytesSmall 1148 90 -92.2% 12.76x
DataSubscriptSmall 220 31 -85.9% 7.10x
DataSetCountSmall 508 114 -77.6% 4.46x
DataMutateBytesSmall 4159 1088 -73.8% 3.82x
DataCopyBytesSmall 285 91 -68.1% 3.13x
DataSubscriptMedium 220 74 -66.4% 2.97x
DataReplaceSmall 5864 3404 -42.0% 1.72x
DataAppendDataLargeToMedium 35507 20934 -41.0% 1.70x
DataReplaceLarge 37325 22021 -41.0% 1.69x
DataCreateSmall 99383 59510 -40.1% 1.67x
DataAppendDataLargeToSmall 34412 20922 -39.2% 1.64x
DataCountSmall 37 25 -32.4% 1.48x
DataAppendDataMediumToSmall 6070 4255 -29.9% 1.43x
DataAppendDataMediumToMedium 6691 4830 -27.8% 1.39x
DataReplaceMedium 8119 6038 -25.6% 1.34x
DataAppendDataSmallToMedium 6158 4695 -23.8% 1.31x
DataAppendDataSmallToSmall 6120 4820 -21.2% 1.27x
DataReplaceSmallBuffer 10583 8442 -20.2% 1.25x
DataCopyBytesMedium 530 430 -18.9% 1.23x
DataToStringEmpty 3037 2594 -14.6% 1.17x
DataReplaceMediumBuffer 13257 11386 -14.1% 1.16x
CharacterLiteralsLarge 108 97 -10.2% 1.11x
CharacterLiteralsSmall 348 325 -6.6% 1.07x

Code size: -O

TEST OLD NEW DELTA RATIO
Regression
DataBenchmarks.o 55956 91023 +62.7% 0.61x
ObjectiveCBridgingStubs.o 19363 27763 +43.4% 0.70x
IterateData.o 1797 2119 +17.9% 0.85x
UTF8Decode.o 11514 12910 +12.1% 0.89x
Improvement
Codable.o 36479 27091 -25.7% 1.35x

Performance: -Osize

TEST OLD NEW DELTA RATIO
Regression
DataCreateSmallArray 27781 697260 +2409.8% 0.04x
DataCreateMediumArray 3112 74756 +2302.2% 0.04x
DataCreateEmptyArray 27042 636084 +2252.2% 0.04x
DataSetCountMedium 517 7695 +1388.4% 0.07x
ObjectiveCBridgeStubDataAppend 6047 41580 +587.6% 0.15x
StringToDataMedium 2978 9638 +223.6% 0.31x
StringToDataSmall 2610 6966 +166.9% 0.37x
StringToDataEmpty 2607 6911 +165.1% 0.38x
DataCreateMedium 16626 21663 +30.3% 0.77x
Improvement
DataCreateEmpty 23701 200 -99.2% 118.50x
DataAppendBytesSmall 4848 280 -94.2% 17.31x
DataAccessBytesMedium 1149 99 -91.4% 11.61x
DataAccessBytesSmall 1148 105 -90.9% 10.93x
DataSubscriptSmall 256 31 -87.9% 8.26x
DataSetCountSmall 508 114 -77.6% 4.46x
DataMutateBytesSmall 4269 1127 -73.6% 3.79x
DataSubscriptMedium 255 74 -71.0% 3.45x
DataCopyBytesSmall 291 91 -68.7% 3.20x
DataReplaceLarge 39322 21039 -46.5% 1.87x
DataAppendDataLargeToSmall 34320 20169 -41.2% 1.70x
DataAppendDataLargeToMedium 35743 21476 -39.9% 1.66x
DataReplaceSmall 5771 3542 -38.6% 1.63x
DataReplaceMedium 8203 5230 -36.2% 1.57x
DataAppendDataMediumToSmall 6252 4273 -31.7% 1.46x
DataCreateSmall 97446 66738 -31.5% 1.46x
DataAppendDataSmallToSmall 6194 4521 -27.0% 1.37x
DataAppendDataMediumToMedium 7146 5228 -26.8% 1.37x
DataAppendDataSmallToMedium 6356 4835 -23.9% 1.31x
DataReplaceMediumBuffer 14352 11586 -19.3% 1.24x
DataCountSmall 34 28 -17.6% 1.21x
DataReplaceSmallBuffer 11092 9183 -17.2% 1.21x
CharacterLiteralsLarge 111 100 -9.9% 1.11x
CharacterLiteralsSmall 345 322 -6.7% 1.07x

Code size: -Osize

TEST OLD NEW DELTA RATIO
Regression
IterateData.o 1989 2223 +11.8% 0.89x
UTF8Decode.o 11057 11318 +2.4% 0.98x
Improvement
DataBenchmarks.o 51029 37843 -25.8% 1.35x
Codable.o 34855 27339 -21.6% 1.27x

Performance: -Onone

TEST OLD NEW DELTA RATIO
Regression
DataCreateEmptyArray 44906 662464 +1375.2% 0.07x
DataSetCountMedium 535 7092 +1225.6% 0.08x
DataCreateMediumArray 7003 73091 +943.7% 0.10x
DataCreateSmallArray 70227 666382 +848.9% 0.11x
ObjectiveCBridgeStubDataAppend 6470 40024 +518.6% 0.16x
StringToDataMedium 3539 11999 +239.1% 0.29x
StringToDataSmall 3573 8133 +127.6% 0.44x
StringToDataEmpty 3569 7240 +102.9% 0.49x
DataCreateMedium 17590 21693 +23.3% 0.81x
Improvement
DataCreateEmpty 24134 1171 -95.1% 20.61x
DataAppendBytesSmall 4967 370 -92.6% 13.42x
DataSubscriptMedium 443 105 -76.3% 4.22x
DataSubscriptSmall 443 120 -72.9% 3.69x
DataSetCountSmall 524 174 -66.8% 3.01x
DataMutateBytesSmall 6048 2365 -60.9% 2.56x
DataCountSmall 223 94 -57.8% 2.37x
DataCountMedium 223 94 -57.8% 2.37x
DataAccessBytesMedium 2345 1010 -56.9% 2.32x
DataAccessBytesSmall 2324 1034 -55.5% 2.25x
DataAppendDataLargeToMedium 36271 21130 -41.7% 1.72x
DataReplaceSmall 5581 3263 -41.5% 1.71x
DataReplaceLarge 37085 22009 -40.7% 1.68x
DataAppendDataLargeToSmall 34885 21174 -39.3% 1.65x
DataCreateSmall 103117 65435 -36.5% 1.58x
DataCopyBytesSmall 334 223 -33.2% 1.50x
DataAppendDataMediumToSmall 6252 4621 -26.1% 1.35x
DataAppendDataSmallToMedium 6382 4832 -24.3% 1.32x
DataReplaceMedium 7869 5974 -24.1% 1.32x
DataAppendDataMediumToMedium 6699 5249 -21.6% 1.28x
DataAppendDataSmallToSmall 5786 4597 -20.5% 1.26x
DataToStringEmpty 3062 2770 -9.5% 1.11x

Code size: -swiftlibs

TEST OLD NEW DELTA RATIO
Regression
libswiftFoundation.dylib 1515520 1675264 +10.5% 0.90x
How to read the data The tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.

If you see any unexpected regressions, you should consider fixing the
regressions before you merge the PR.

Noise: Sometimes the performance results (not code size!) contain false
alarms. Unexpected regressions which are marked with '(?)' are probably noise.
If you see regressions which you cannot explain you can try to run the
benchmarks again. If regressions still show up, please consult with the
performance team (@eeckstein).

Hardware Overview
  Model Name: Mac Pro
  Model Identifier: MacPro6,1
  Processor Name: 12-Core Intel Xeon E5
  Processor Speed: 2.7 GHz
  Number of Processors: 1
  Total Number of Cores: 12
  L2 Cache (per Core): 256 KB
  L3 Cache: 30 MB
  Memory: 64 GB
--------------

@itaiferber
Copy link
Contributor

Looks like CI benchmarks are showing the same conditional conformance devirtualization issues we've been seeing locally. Good to have a baseline for Andy's fixes

@itaiferber
Copy link
Contributor

@atrick Thanks for all of your hard work on this stuff! Looks like we're hitting a lot of unfortunate edge cases.

@itaiferber
Copy link
Contributor

@swift-ci Please test macOS

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 8dd8dd9

@itaiferber
Copy link
Contributor

^That's an lldb test failure, expecting certain lldb output when breakpoints are set. Likely due to the fact that Data's layout has changed. Unfortunately, running those same commands segfaults lldb on my machine so I can't even tell what the output should be.

@jrose-apple Who might we be able to turn to to ask about this? Running through what lldb is doing in lldb/packages/Python/lldbsuite/test/lang/swift/foundation_value_types/data/main.swift segfaults on my machine with both the system lldb and the build lldb-with-tools.

@itaiferber
Copy link
Contributor

itaiferber commented Dec 10, 2018

Looks like we'll need to make Data_SummaryProvider match the layout of Data.

Not sure how possible this will be given that we no longer have a stored property for the length, and I'm not sure we can switch on Swift enums from C++.

@jrose-apple
Copy link
Contributor

@dcci, who owns the summary providers these days? And how is this supposed to work across OS releases?

(which I guess won't be a problem after Foundation lands this work, but…)

@itaiferber
Copy link
Contributor

For now the plan is to take out the data provider here and XFAIL the test if necessary so we're unblocked; we can figure out how to add this back in later (if at all) considering that the layout of Data has changed significantly and we no longer have a stored variable representing the length of the data and there are multiple layers' worth of enums and structs to unwrap — it would be less work to just call .count.

@phausler phausler force-pushed the inline_data_and_dataprotocol branch from 8dd8dd9 to d030354 Compare December 11, 2018 19:21
@phausler
Copy link
Contributor Author

@swift-ci please smoke test

@itaiferber
Copy link
Contributor

Please test with following pull request:
apple/swift-lldb#1134

@swift-ci Please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 8dd8dd9

@itaiferber
Copy link
Contributor

@swift-ci Please benchmark

@swift-ci
Copy link
Contributor

Build comment file:

Performance: -O

TEST OLD NEW DELTA RATIO
Regression
DataSetCountMedium 517 703 +36.0% 0.74x
StringToDataMedium 2676 3292 +23.0% 0.81x
ObjectiveCBridgeStubDataAppend 5869 6829 +16.4% 0.86x
Improvement
DataCreateEmpty 24710 200 -99.2% 123.55x
DataAppendBytesSmall 4791 260 -94.6% 18.43x
DataAccessBytesMedium 1138 80 -93.0% 14.22x
DataAccessBytesSmall 1138 91 -92.0% 12.51x
DataSubscriptSmall 214 31 -85.5% 6.90x
DataCreateEmptyArray 27212 4314 -84.1% 6.31x
DataCreateSmallArray 30635 5121 -83.3% 5.98x
DataMutateBytesSmall 4276 1091 -74.5% 3.92x
DataSetCountSmall 508 137 -73.0% 3.71x
StringToDataEmpty 2573 697 -72.9% 3.69x
DataSubscriptMedium 214 65 -69.6% 3.29x
StringToDataSmall 2583 800 -69.0% 3.23x
DataCopyBytesSmall 285 94 -67.0% 3.03x
DataReplaceSmall 6366 3251 -48.9% 1.96x
DataAppendDataLargeToMedium 35772 20442 -42.9% 1.75x
DataReplaceMedium 8783 5163 -41.2% 1.70x
DataReplaceLarge 38058 22404 -41.1% 1.70x
DataCountSmall 37 22 -40.5% 1.68x
DataAppendDataLargeToSmall 34475 20700 -40.0% 1.67x
DataCreateSmall 96257 62758 -34.8% 1.53x
DataAppendDataSmallToSmall 5740 3969 -30.9% 1.45x
DataAppendDataMediumToSmall 6336 4455 -29.7% 1.42x
DataAppendDataSmallToMedium 6374 4587 -28.0% 1.39x
DataAppendDataMediumToMedium 6721 4929 -26.7% 1.36x
DataCountMedium 34 28 -17.6% 1.21x
DataToStringEmpty 3033 2588 -14.7% 1.17x

Code size: -O

TEST OLD NEW DELTA RATIO
Regression
DataBenchmarks.o 55924 87615 +56.7% 0.64x
ObjectiveCBridgingStubs.o 19363 27427 +41.6% 0.71x
UTF8Decode.o 11586 12542 +8.3% 0.92x
IterateData.o 1797 1893 +5.3% 0.95x
Improvement
Codable.o 36031 26467 -26.5% 1.36x

Performance: -Osize

TEST OLD NEW DELTA RATIO
Regression
DataSetCountMedium 506 766 +51.4% 0.66x
StringToDataMedium 2685 3277 +22.0% 0.82x
ObjectiveCBridgeStubToNSStringRef 109 132 +21.1% 0.83x (?)
DataAppendBytesMedium 5139 5864 +14.1% 0.88x
Improvement
DataCreateEmpty 26826 200 -99.3% 134.13x
DataAppendBytesSmall 4224 271 -93.6% 15.59x
DataAccessBytesMedium 1155 91 -92.1% 12.69x
DataAccessBytesSmall 1156 100 -91.3% 11.56x
DataSubscriptSmall 214 28 -86.9% 7.64x
DataCreateEmptyArray 30282 4285 -85.8% 7.07x
DataCreateSmallArray 28113 5971 -78.8% 4.71x
DataMutateBytesSmall 4595 1115 -75.7% 4.12x
StringToDataEmpty 2617 708 -72.9% 3.70x
DataSetCountSmall 508 140 -72.4% 3.63x
DataSubscriptMedium 214 68 -68.2% 3.15x
StringToDataSmall 2608 832 -68.1% 3.13x
DataCopyBytesSmall 294 108 -63.3% 2.72x
DataReplaceLarge 37851 21680 -42.7% 1.75x
DataReplaceSmall 5613 3239 -42.3% 1.73x
DataAppendDataLargeToSmall 34806 20262 -41.8% 1.72x
DataAppendDataLargeToMedium 35133 21159 -39.8% 1.66x
DataCreateSmall 100136 63681 -36.4% 1.57x
DataReplaceMedium 8313 5391 -35.1% 1.54x
DataCountSmall 34 25 -26.5% 1.36x
DataAppendDataMediumToSmall 6175 4544 -26.4% 1.36x
DataCountMedium 37 28 -24.3% 1.32x
DataAppendDataSmallToSmall 6057 4800 -20.8% 1.26x
DataAppendDataMediumToMedium 6686 5367 -19.7% 1.25x
DataAppendDataSmallToMedium 6361 5148 -19.1% 1.24x
DataReplaceMediumBuffer 12381 10901 -12.0% 1.14x

Code size: -Osize

TEST OLD NEW DELTA RATIO
Improvement
DataBenchmarks.o 51013 36315 -28.8% 1.40x
Codable.o 34375 26795 -22.1% 1.28x
UTF8Decode.o 11161 10958 -1.8% 1.02x

Performance: -Onone

TEST OLD NEW DELTA RATIO
Regression
DataCreateEmptyArray 42009 604077 +1338.0% 0.07x
DataCreateMediumArray 6622 69551 +950.3% 0.10x
DataCreateSmallArray 61779 628548 +917.4% 0.10x
DataSetCountMedium 535 769 +43.7% 0.70x
Improvement
DataCreateEmpty 36300 1200 -96.7% 30.25x
DataAppendBytesSmall 4806 361 -92.5% 13.31x
DataSubscriptMedium 449 94 -79.1% 4.78x
DataSubscriptSmall 437 111 -74.6% 3.94x
StringToDataEmpty 3326 1067 -67.9% 3.12x
StringToDataSmall 3328 1183 -64.5% 2.81x
DataSetCountSmall 526 200 -62.0% 2.63x
DataCountSmall 223 91 -59.2% 2.45x
DataCountMedium 223 91 -59.2% 2.45x
DataAccessBytesMedium 2346 979 -58.3% 2.40x
DataMutateBytesSmall 5420 2330 -57.0% 2.33x
DataAccessBytesSmall 2335 1031 -55.8% 2.26x
DataReplaceSmall 5833 3097 -46.9% 1.88x
DataAppendDataLargeToSmall 34592 20127 -41.8% 1.72x
DataAppendDataLargeToMedium 35076 20707 -41.0% 1.69x
DataReplaceMedium 8590 5167 -39.8% 1.66x
DataReplaceLarge 39088 23934 -38.8% 1.63x
DataCopyBytesSmall 334 211 -36.8% 1.58x
DataAppendDataMediumToSmall 6291 4322 -31.3% 1.46x
DataCreateSmall 100913 71617 -29.0% 1.41x
DataToStringEmpty 3887 2787 -28.3% 1.39x

Code size: -swiftlibs

TEST OLD NEW DELTA RATIO
Regression
libswiftFoundation.dylib 1511424 1654784 +9.5% 0.91x
How to read the data The tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.

If you see any unexpected regressions, you should consider fixing the
regressions before you merge the PR.

Noise: Sometimes the performance results (not code size!) contain false
alarms. Unexpected regressions which are marked with '(?)' are probably noise.
If you see regressions which you cannot explain you can try to run the
benchmarks again. If regressions still show up, please consult with the
performance team (@eeckstein).

Hardware Overview
  Model Name: Mac Pro
  Model Identifier: MacPro6,1
  Processor Name: 12-Core Intel Xeon E5
  Processor Speed: 2.7 GHz
  Number of Processors: 1
  Total Number of Cores: 12
  L2 Cache (per Core): 256 KB
  L3 Cache: 30 MB
  Memory: 64 GB
--------------

@itaiferber
Copy link
Contributor

(Now that tests have passed on this and apple/swift-lldb#1134, I plan on merging them in parallel once we have approval.)

//===--- Collection Conformances ------------------------------------------===//

// FIXME: When possible, expand conformance to `where Element : Trivial`.
extension Array : ContiguousBytes where Element == UInt8 { }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

given this will become ABI and can't be loosened later, are you sure you want to add this? You can use withContiguousStorageIfAvailable instead in this case, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I don't mind adding it, just thinking you might want to reserve flexibility for yourself)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot use withContiguousStorageIfAvailable because this is being used as a protocol to identify it as a contiguous DataProtocol

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@airspeedswift Is this because the conditional conformance produces a symbol name based on the associated type?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@itaiferber Right. And you can only have one conditional conformance. I can envision ABI-stable ways to loosen conditional conformances in the future, but we don't have any right now. cc @DougGregor

@phausler but you have an init from a general sequence of UInt8, and so can have Array follow that path then fast-path into withContiguousStorageIfAvailable, no? Might amount to much the same thing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@airspeedswift Sure, the conditional conformance limitation I'm aware of. In the future, we're almost certainly going to need an ABI-stable way to loosen these anyway; even if not, we're willing to live with this for now.

We're also not using this just in init<S : Sequence> — it's important for general consumers of DataProtocol who rely on ContiguousBytes for the associatedtype requirement.

@benrimmington
Copy link
Contributor

@itaiferber Should the title and initial comment be updated?

(ContiguousCollection => ContiguousBytes, etc.)

@phausler
Copy link
Contributor Author

ContiguousCollection != ContiguousBytes

ContiguousBytes is the protocol for untyped bytes, ContiguousCollection is for typed things.

@itaiferber itaiferber changed the title Initial draft of DataProtocol ContiguousCollection and new inline Data Initial draft of DataProtocol and new inline Data Dec 12, 2018
@itaiferber itaiferber changed the title Initial draft of DataProtocol and new inline Data DataProtocol and new inline Data Dec 12, 2018
@itaiferber
Copy link
Contributor

@benrimmington I've updated the PR title and comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants