Skip to content
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

[SR-7139] Support enforcement of exclusive memory accesses in Release builds #49687

Closed
AnnaZaks mannequin opened this issue Mar 8, 2018 · 1 comment
Closed

[SR-7139] Support enforcement of exclusive memory accesses in Release builds #49687

AnnaZaks mannequin opened this issue Mar 8, 2018 · 1 comment
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@AnnaZaks
Copy link
Mannequin

AnnaZaks mannequin commented Mar 8, 2018

Previous ID SR-7139
Radar rdar://problem/37830912
Original Reporter @AnnaZaks
Type Bug
Status Closed
Resolution Done
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug
Assignee @atrick
Priority Medium

md5: afc211616daff96bb8fc13ffad465fe5

relates to:

  • SR-4355 Update standard library to use memory ownership features

Issue Description:

Exclusivity is currently supported in Debug builds but not in Release builds.

We need to make sure the optimizer works with access markers to support the mode. Further, we would need to evaluate performance impact and minimize it. For example, we will need to fix the optimization passes to handle access markers without missing optimization opportunities. We might also want to add new optimizations to merge and eliminate access scopes.

@atrick
Copy link
Member

atrick commented Nov 9, 2018

PR: #20302

Enabling run-time exclusivity checking in release mode

It's time to change the compiler default for run-time exclusivity
checks. This will expose the feature to more testing and allow the
compiler team to gather performance feedback from users. Until now,
I've been waiting until the most obvious bottlenecks are
resolved--there's no sense having a slew of performance bugs for
issues that are about to be fixed. Recent optimizations landed by Joe
Shajrawi have brought performance where I think it needs to be for
adoption. More optimizations are planned, and some benchmarks should
be further improved, but at this point we're ready to begin receiving
bug reports. That will help prioritize the remaining work for Swift 5.

What's changing in Swift 5

Exclusivity checking was introduced in Swift 4.0.
[SE-0176: Enforce Exclusive Access to Memory](https://github.com/apple/swift-evolution/blob/master/proposals/0176-enforce-exclusive-access-to-memory.md).

Compile-time (static) diagnostics catch many common exclusivity
violations, but run-time (dynamic) diagnostics are also required to
catch violations involving escaping closures, class properties, and
globals. Swift 4.0 provided both static and dynamic enforcement, but
dynamic enforcement was only enabled in debug builds.

In Swift 4.1 and 4.2, compiler diagnostics were gradually strengthened
to catch more and more of the cases in which programmers could skirt
exclusivity rules--most notably, by capturing variables in nonescaping
closures or by converting nonescaping closures to escaping closures.

Devin's Swift 4.2 announcement, [Upgrading exclusive access warning to
be an error in Swift
4.2](https://forums.swift.org/t/upgrading-exclusive-access-warning-to-be-an-error-in-swift-4-2/12704),
explains some of the common cases affected by the newly enforced
exclusivity diagnostics.

The goal for Swift 5 is to fix the remaining holes in the language
model and to fully enforce that model. All of the known language
deficiencies have been fixed, with the exception of [[SR-8546]: Enforce
@escaping for nested functions named inside conditional
expressions](https://bugs.swift.org/browse/SR-8546). Run-time enforcement will be enabled for release builds by
default in [PR 20302](#20302

This change could impact Swift programs that previously appeared
well-behaved, but weren't fully tested in debug mode. Now, when running
in release mode, they may trap with the message "error: overlapping
accesses...".

Why we need exclusivity checks.

A combination of static and dynamic checks are necessary to enforce
Swift's language rules for a particular aspect of [Memory
Safety](https://docs.swift.org/swift-book/LanguageGuide/MemorySafety.html). Enforcing the rules helps in at least four ways:

1. Adherence to exclusivity rules removes a common class of
programming bugs involving mutable state and action at a distance.

As programs scale in size, it becomes increasingly likely for routines
to interact in unexpected ways. Exclusivity rules eliminate dangerous
interactions involving mutable state. In this simple example, note
that exclusivity prevents the programmer from passing the same
instance of `Names` as `src` and `dest`, which would otherwise cause
an infinite loop:

func moveElements(from src: inout Set<String>, to dest: inout Set<String>) {
 while let e = src.popFirst() {
 dest.insert(e)
 }
}
class Names {
 var nameSet: Set<String> = []
}
func moveNames(from src: Names, to dest: Names) {
 moveElements(from: &src.nameSet, to: &dest.nameSet)
}

2. Enforcement eliminates an unspecified behavior rule from the language.

Prior to Swift 4, these memory rules were unenforced, making it the
programmer's responsibility to adhere to them. In practice, it was
easy for programmers to violate these rules in subtle ways, leaving
their programs vulnerable to unspecified behavior.

3. Enforcement legalizes performance optimization while protecting
memory safety.

A guarantee of exclusivity on `inout` parameters and `mutating`
methods provides important information to the compiler, which it can
use to optimize memory access and reference counting
operations. Declaring an unspecified behavior rule, as mentioned
above, does not provide this guarantee. An "undefined behavior" rule
is required to support optimization, but such a rule would, by
definition, compromise the memory safety of the language. Full
exclusivity enforcement allows the compiler to optimize based on
memory exclusivity without introducing undefined behavior.

4. Exclusivity rules are needed to give programmer control of
ownership and move-only types.

John McCall's Ownership Manifesto intoduces the [Law of
Exclusivity](https://github.com/apple/swift/blob/master/docs/OwnershipManifesto.md#the-law-of-exclusivity),
and explains how it provides the basis for adding ownership and move-only types
to the language.

Current performance impact

Of the 656 public microbenchmarks in the Swift repository, there are
still several regressions larger than 10%:

TEST                    OLD      NEW      DELTA      RATIO
ClassArrayGetter2       139      1307     +840.3%    **0.11x** 
HashTest                631      1233     +95.4%     **0.51x** 
NopDeinit               21269    32389    +52.3%     **0.66x** 
Hanoi                   1478     2166     +46.5%     **0.68x** 
Calculator              127      158      +24.4%     **0.80x** 
Dictionary3OfObjects    391      455      +16.4%     **0.86x** 
CSVParsingAltIndices2   526      604      +14.8%     **0.87x** 
Prims                   549      626      +14.0%     **0.88x** 
CSVParsingAlt2          1252     1411     +12.7%     **0.89x** 
Dictionary4OfObjects    206      232      +12.6%     **0.89x** 
ArrayInClass            46       51       +10.9%     **0.90x** 

The common pattern in these benchmarks is to define an array of data
as a class property and to repeatedly access that array through the
class reference. Each of those class property accesses now incurs a
runtime call. Naturally, introducing a runtime call in a loop that
otherwise does almost no work incurs substantial overhead. This is
similar to the issue caused by automatic reference counting. In some
cases, more sophistacated optimization will be able to determine the
same object is repeatedly accessed. Furthermore, the overhead of the
runtime call can be improved. But regardless of how well we optimize,
there will always a class of microbenchmarks in which the runtime
check has a noticeable impact.

As a general guideline, avoid performing class property access within
the most performance critical loops, particularly on different objects
in each loop iteration. If that isn't possible, it may help if the
visibility of those class properties is private or internal.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself
Projects
None yet
Development

No branches or pull requests

1 participant