Skip to content

Commit 78f131b

Browse files
authored
Add a deviceScopes stack to CompilerRuntime to be consulted by the eager op dispatch. (#20897)
Unfortunately, this info gets ignored when any ops get extracted out into a graph, but hopefully static analysis of these calls could remove some of those differences.
1 parent c91a626 commit 78f131b

39 files changed

+169
-95
lines changed

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,6 +1505,9 @@ FUNCTION(TFC_OpSetAttrOptionalTensorShapeArray,
15051505
ARGS(Int8PtrTy, Int8PtrTy, Int8PtrTy, Int8PtrTy),
15061506
ATTRS(NoUnwind))
15071507

1508+
FUNCTION(TFC_OpSetDeviceFromScope, _swift_tfc_OpSetDeviceFromScope,
1509+
C_CC, RETURNS(VoidTy), ARGS(Int8PtrTy, Int8PtrTy), ATTRS(NoUnwind))
1510+
15081511
// The swift function signature is (CTFEOp, UnsafePointer<Int8>, String) -> ().
15091512
// In LLVM IR, the String gets exploded to (BridgeObjectPtrTy, Int64Ty), so
15101513
// IRGen passes those two values in place of the Swift String.

lib/IRGen/IRGenSIL.cpp

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2843,15 +2843,8 @@ void IRGenSILFunction::visitGraphOperationInst(GraphOperationInst *i) {
28432843
}
28442844

28452845
// Set the device.
2846-
opDevice = deviceInfo->handleDevicePlacement(opInfo.getOperationName(),
2847-
opDevice, i->getAttributes());
2848-
assert(!opDevice.empty());
2849-
if (opDevice != TF_ALL_DEVICES) {
2850-
auto *setDeviceFn = IGM.getTFE_OpSetDeviceFn();
2851-
auto device = IGM.getAddrOfGlobalString(opDevice);
2852-
Builder.CreateCall(setDeviceFn, {op, device, status});
2853-
checkOk(status);
2854-
}
2846+
Builder.CreateCall(IGM.getTFC_OpSetDeviceFromScopeFn(), {op, status});
2847+
checkOk(status);
28552848

28562849
// If we have any opaque TensorGroup results, then we need to do extra runtime
28572850
// work to determine the number of TensorFlow outputs and to allocate space

stdlib/private/TensorFlowUnittest/TensorFlowUnittest.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,13 @@ public func printT(_ message: String) {
5353
}
5454

5555
extension TestSuite {
56+
static let willTargetGPU: Bool =
57+
CommandLine.arguments.contains("--target=gpu")
5658
// If the macro TPU is not specified, run the tests with CPU or GPU. Otherwise
5759
// use TPU.
5860
// For GPU execution, TensorFlow must have been built with --config=cuda,
5961
// and a gpu device must be available.
62+
@inline(never)
6063
public func testAllBackends(_ name: String, _ body: @escaping () -> Void) {
6164
#if !TPU
6265
testCPUOrGPU(name, body)
@@ -66,12 +69,14 @@ extension TestSuite {
6669
}
6770
public func testCPUOrGPU(_ name: String, _ body: @escaping () -> Void) {
6871
#if !TPU
69-
test(name + "_CPU_OR_GPU") {
72+
test(name + (TestSuite.willTargetGPU ? "_GPU" : "_CPU")) {
7073
_RuntimeConfig.executionMode = .auto
7174
_RuntimeConfig.usesTFEagerAPI = true
7275
_RuntimeConfig.gpuMemoryAllowGrowth = true
7376
_RuntimeConfig.printsDebugLog = false
74-
body()
77+
withDevice(TestSuite.willTargetGPU ? .gpu : .cpu) {
78+
body()
79+
}
7580
}
7681
#endif // TPU
7782
}

stdlib/public/TensorFlow/CompilerRuntime.swift

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,10 @@ public final class _ExecutionContext {
261261
/// The mutex for preventing potential concurrent access.
262262
private var mutex: pthread_mutex_t = pthread_mutex_t()
263263

264+
/// The stack for holding the current device scoping information.
265+
@usableFromInline
266+
var deviceScopes: [DeviceKind] = [.`default`]
267+
264268
/// Initializes a new execution context by initializing available devices.
265269
@usableFromInline
266270
init() {
@@ -1507,6 +1511,67 @@ func _TFCOpSetAttrStringArray(_ op: CTFEOp,
15071511
}
15081512
}
15091513

1514+
/// A TensorFlow device kind.
1515+
public enum DeviceKind {
1516+
/// Default device.
1517+
case `default`
1518+
/// Central processing units.
1519+
case cpu
1520+
/// Graphics processing units.
1521+
case gpu
1522+
// TODO: TPU?
1523+
}
1524+
1525+
internal extension _ExecutionContext {
1526+
var currentDeviceKind: DeviceKind {
1527+
return sync {
1528+
deviceScopes.last ?? .default
1529+
}
1530+
}
1531+
1532+
@usableFromInline
1533+
func pushDeviceScope(_ kind: DeviceKind) {
1534+
sync {
1535+
deviceScopes.append(kind)
1536+
}
1537+
}
1538+
1539+
@usableFromInline
1540+
func popDeviceScope() {
1541+
sync {
1542+
internalConsistencyCheck(deviceScopes.popLast() != nil)
1543+
}
1544+
}
1545+
}
1546+
1547+
/// Executes a closure, making TensorFlow operations run on a specific kind of
1548+
/// device unless specified otherwise.
1549+
///
1550+
/// - Parameters:
1551+
/// - kind: A kind of device to run TensorFlow operations on.
1552+
/// - body: A closure whose TensorFlow operations are to be executed on the
1553+
/// specified kind of device.
1554+
@inlinable
1555+
public func withDevice<R>(_ kind: DeviceKind,
1556+
perform body: () throws -> R) rethrows -> R {
1557+
_ExecutionContext.global.pushDeviceScope(kind)
1558+
let result = try body()
1559+
_ExecutionContext.global.popDeviceScope()
1560+
return result
1561+
}
1562+
1563+
@usableFromInline
1564+
@_cdecl("_swift_tfc_OpSetDeviceFromScope")
1565+
func _TFCOpSetDeviceFromScope(_ op: CTFEOp, _ status: CTFStatus) {
1566+
let context = _ExecutionContext.global
1567+
let device = context.currentDeviceKind
1568+
switch device {
1569+
case .cpu: TFE_OpSetDevice(op, context.cpuDeviceName, status)
1570+
case .gpu: TFE_OpSetDevice(op, context.gpuDeviceName!, status)
1571+
default: break
1572+
}
1573+
}
1574+
15101575
@usableFromInline
15111576
@_cdecl("_swift_tfc_CheckOk")
15121577
func _TFCCheckOk(_ s: CTFStatus) {

test/TensorFlowRuntime/accelerator_only.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-run-dynamic-compilation-swift
1+
// RUN: %target-run-dynamic-compilation-swift %swift-tensorflow-test-run-extra-options
22
// RUN: %target-swift-frontend -emit-sil -O %s -verify | %FileCheck %s
33
// REQUIRES: executable_test
44
// REQUIRES: swift_test_mode_optimize

test/TensorFlowRuntime/codable.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-run-simple-swift
1+
// RUN: %target-run-simple-swift %swift-tensorflow-test-run-extra-options
22
// REQUIRES: executable_test
33
// REQUIRES: swift_test_mode_optimize
44
// REQUIRES: objc_interop

test/TensorFlowRuntime/conflicting_module.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// RUN: %target-build-swift %S/Inputs/ConflictingModule1.swift -emit-module -emit-library -module-name ConflictingModule1 -o %t/libConflictingModule1.%target-dylib-extension -emit-module-path %t/ConflictingModule1.swiftmodule
88
// RUN: %target-build-swift %S/Inputs/ConflictingModule2.swift -emit-module -emit-library -module-name ConflictingModule2 -o %t/libConflictingModule2.%target-dylib-extension -emit-module-path %t/ConflictingModule2.swiftmodule
99
// RUN: %target-build-swift %s -I %t -L %t -lConflictingModule1 -lConflictingModule2 -Xlinker -rpath -Xlinker %t -o %t/a.out
10-
// RUN: %target-run %t/a.out
10+
// RUN: %target-run %t/a.out %swift-tensorflow-test-run-extra-options
1111
// REQUIRES: executable_test
1212

1313
import StdlibUnittest

test/TensorFlowRuntime/control_flow_1.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %target-run-simple-swift
2-
// RUN: %target-run-dynamic-compilation-swift
1+
// RUN: %target-run-simple-swift %swift-tensorflow-test-run-extra-options
2+
// RUN: %target-run-dynamic-compilation-swift %swift-tensorflow-test-run-extra-options
33
// REQUIRES: executable_test
44
// REQUIRES: swift_test_mode_optimize
55
//

test/TensorFlowRuntime/control_flow_objc.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-run-simple-swift
1+
// RUN: %target-run-simple-swift %swift-tensorflow-test-run-extra-options
22
// REQUIRES: executable_test
33
// REQUIRES: swift_test_mode_optimize
44
// REQUIRES: OS=macosx

test/TensorFlowRuntime/dataset_1.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %target-run-simple-swift
2-
// RUN: %target-run-dynamic-compilation-swift
1+
// RUN: %target-run-simple-swift %swift-tensorflow-test-run-extra-options
2+
// RUN: %target-run-dynamic-compilation-swift %swift-tensorflow-test-run-extra-options
33
// REQUIRES: executable_test
44
// REQUIRES: swift_test_mode_optimize
55
//
@@ -100,7 +100,6 @@ DatasetTests.testAllBackends("Basic") {
100100
// OneShotIterator is not supported on GPU.
101101
model()
102102
}
103-
#endif
104103

105104
DatasetTests.testAllBackends("MultiValue") {
106105
enableCPU()
@@ -137,5 +136,6 @@ DatasetTests.testAllBackends("MultiValue") {
137136
expectEqual(2, Tensor(handle: next.0).scalarized())
138137
expectEqual(12, Tensor(handle: next.1).scalarized())
139138
}
139+
#endif
140140

141141
runAllTests()

test/TensorFlowRuntime/dataset_api.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %target-run-simple-swift
2-
// RUN: %target-run-dynamic-compilation-swift
1+
// RUN: %target-run-simple-swift %swift-tensorflow-test-run-extra-options
2+
// RUN: %target-run-dynamic-compilation-swift %swift-tensorflow-test-run-extra-options
33
// REQUIRES: executable_test
44
// REQUIRES: swift_test_mode_optimize
55
//

test/TensorFlowRuntime/dataset_global.swift

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// TODO: Revert to %target-run-simple-swift once we complete send/recv support for resource/variant tensors.
2-
// RUN: %target-run-send-recv-handle-swift
3-
// RUN: %target-run-dynamic-compilation-swift
2+
// RUN: %target-run-send-recv-handle-swift %swift-tensorflow-test-run-extra-options
3+
// RUN: %target-run-dynamic-compilation-swift %swift-tensorflow-test-run-extra-options
44
// REQUIRES: executable_test
55
// REQUIRES: swift_test_mode_optimize
66

@@ -19,15 +19,14 @@ var DatasetGlobalTests = TestSuite("DatasetGlobal")
1919
// Fatal error: No unary variant device copy function found for direction: 1 and Variant type_name: tensorflow::DatasetVariantWrapper
2020
#if !CUDA
2121

22-
let scalars = Tensor<Float>([0, 1, 2])
23-
let dataset = Dataset(elements: scalars)
24-
var iterator = dataset.makeIterator()
25-
2622
DatasetGlobalTests.testCPUOrGPU("RuntimeConfigTest") {
2723
expectTrue(_RuntimeConfig.usesTFEagerAPI)
2824
}
2925

3026
DatasetGlobalTests.testCPUOrGPU("DatasetAsGlobalVar") {
27+
let scalars = Tensor<Float>([0, 1, 2])
28+
let dataset = Dataset(elements: scalars)
29+
3130
var expectedVal: Float = 0.0
3231
for item in dataset {
3332
_hostOp(item)
@@ -37,6 +36,10 @@ DatasetGlobalTests.testCPUOrGPU("DatasetAsGlobalVar") {
3736
}
3837

3938
DatasetGlobalTests.testCPUOrGPU("IteratorAsGlobalVar") {
39+
let scalars = Tensor<Float>([0, 1, 2])
40+
let dataset = Dataset(elements: scalars)
41+
var iterator = dataset.makeIterator()
42+
4043
var expectedVal: Float = 0.0
4144
while let item = iterator.next() {
4245
_hostOp(item)

0 commit comments

Comments
 (0)