Skip to content

Clock/Instant/Duration #40609

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 36 commits into from
Feb 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ebe3d0f
[WIP] Initial draft at v2 Clock/Instant/Duration
phausler Dec 16, 2021
090aa9a
Ensure the literal types for _DoubleWide are able to be at least 64 b…
phausler Jan 6, 2022
251a8e4
static cast timespec members to long
phausler Jan 6, 2022
e313e1e
Remove runtime exports from clock functions
phausler Jan 6, 2022
e86318a
Export clock functions in implementations as they are in headers
phausler Jan 10, 2022
6750873
Clean up internal properties by adding leading underscores, refine av…
phausler Jan 12, 2022
ce62c2d
Shift operators to concrete Instant types to avoid complexity in solv…
phausler Jan 26, 2022
d9d963f
Adjust diagnostic note and error expectation of ambiguities to reflec…
phausler Jan 27, 2022
cb93fa8
Update stdlib/public/Concurrency/TaskSleep.swift
phausler Jan 26, 2022
53a1986
[stdlib][NFC] Remove trailing whitespace
lorentey Jan 26, 2022
f81d9c7
[stdlib] Remove _DoubleWidth from stdlib's ABI
lorentey Jan 26, 2022
8486237
[stdlib] Strip downd _DoubleWidth to _[U]Int128
lorentey Jan 27, 2022
a53eed7
Additional adjustments to diagnostic notes and errors expectation of …
phausler Jan 27, 2022
01450e7
Disable type checker performance validation for operator overload inf…
phausler Jan 27, 2022
be6c98f
Decorate Duration, DurationProtocol, Instant and clocks with @availab…
phausler Jan 28, 2022
2d9dff4
Restore diagnostic ambiguity test assertion (due to availability)
phausler Jan 28, 2022
df70068
Add a rough attempt at implementing time accessors on win32
phausler Jan 28, 2022
68d4408
Remove unused clock id, rename SPI for swift clock ids and correct a …
phausler Jan 28, 2022
10c0096
remove obsolete case of realtime clock for dispatch after callout
phausler Jan 31, 2022
88e48f4
Use the default implementation of ~ for Int128 and UInt128
phausler Feb 1, 2022
4966f04
Ensure diagnostic ambiguitiy applies evenly to all platforms and thei…
phausler Feb 3, 2022
34284ef
Restore the simd vector build modifications (merge damage)
phausler Feb 3, 2022
7381b48
Update to latest naming results for Instant.Duration
phausler Feb 7, 2022
c8824bd
Updates to latest proposal initializers and accessors and adjust enco…
phausler Feb 8, 2022
8f2b121
Update availability for Clock/Instant/Duration methods and types to b…
phausler Feb 10, 2022
6d07868
Correct *Clock.now to report via the correct runtime API
phausler Feb 10, 2022
294290f
Ensure the hashing of Duration is based upon the attoseconds hashing
phausler Feb 10, 2022
5c24901
Avoid string based encoding and resort back to high and low bit encod…
phausler Feb 10, 2022
731a220
Adjust naming of component initializer to use suffixes on parameters
phausler Feb 10, 2022
8c86e88
Duration decoding should use a mutable container for decoding
phausler Feb 10, 2022
d13249e
fix up components initializer and decode access
phausler Feb 10, 2022
9ba779e
Add platform base initializers for timespec and tiemval to and from D…
phausler Feb 10, 2022
54466a6
Add some first draft documentation for standard library types Duratio…
phausler Feb 11, 2022
fba08fc
Another round of documentation prose and some drive-by availability f…
phausler Feb 11, 2022
79670f7
InstantProtocol availability should be 5.7
phausler Feb 15, 2022
654596a
Correct linux timeval creation to be Int and not Int32
phausler Feb 16, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions include/swift/Runtime/Concurrency.h
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,10 @@ using JobDelay = unsigned long long;
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
void swift_task_enqueueGlobalWithDelay(JobDelay delay, Job *job);

SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
void swift_task_enqueueGlobalWithDeadline(long long sec, long long nsec,
long long tsec, long long tnsec, int clock, Job *job);

/// Enqueue the given job on the main executor.
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
void swift_task_enqueueMainExecutor(Job *job);
Expand All @@ -691,6 +695,21 @@ SWIFT_CC(swift) void (*swift_task_enqueueGlobalWithDelay_hook)(
unsigned long long delay, Job *job,
swift_task_enqueueGlobalWithDelay_original original);

typedef SWIFT_CC(swift) void (*swift_task_enqueueGlobalWithDeadline_original)(
long long sec,
long long nsec,
long long tsec,
long long tnsec,
int clock, Job *job);
SWIFT_EXPORT_FROM(swift_Concurrency)
SWIFT_CC(swift) void (*swift_task_enqueueGlobalWithDeadline_hook)(
long long sec,
long long nsec,
long long tsec,
long long tnsec,
int clock, Job *job,
swift_task_enqueueGlobalWithDeadline_original original);

/// A hook to take over main executor enqueueing.
typedef SWIFT_CC(swift) void (*swift_task_enqueueMainExecutor_original)(
Job *job);
Expand Down Expand Up @@ -825,6 +844,21 @@ void swift_task_donateThreadToGlobalExecutorUntil(bool (*condition)(void*),

#endif

enum swift_clock_id : int {
swift_clock_id_continuous = 1,
swift_clock_id_suspending = 2
};

SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
void swift_get_time(long long *seconds,
long long *nanoseconds,
swift_clock_id clock_id);

SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
void swift_get_clock_res(long long *seconds,
long long *nanoseconds,
swift_clock_id clock_id);

#ifdef __APPLE__
/// A magic symbol whose address is the mask to apply to a frame pointer to
/// signal that it is an async frame. Do not try to read the actual value of
Expand Down
4 changes: 4 additions & 0 deletions stdlib/public/Concurrency/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I
AsyncThrowingStream.swift
AsyncStream.cpp
Deque.swift
Clock.cpp
Clock.swift
ContinuousClock.swift
SuspendingClock.swift
${swift_concurrency_extra_sources}
linker-support/magic-symbols-for-install-name.c

Expand Down
140 changes: 140 additions & 0 deletions stdlib/public/Concurrency/Clock.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//===--- Clock.cpp - Time and clock resolution ----------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/Runtime/Concurrency.h"

#if __has_include(<time.h>)
#define HAS_TIME 1
#include <time.h>
#endif
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
#endif

using namespace swift;

SWIFT_EXPORT_FROM(swift_Concurrency)
SWIFT_CC(swift)
void swift_get_time(
long long *seconds,
long long *nanoseconds,
swift_clock_id clock_id) {
switch (clock_id) {
case swift_clock_id_continuous: {
#if defined(__linux__) && HAS_TIME
struct timespec continuous;
clock_gettime(CLOCK_BOOTTIME, &continuous);
*seconds = continuous.tv_sec;
*nanoseconds = continuous.tv_nsec;
#elif defined(__APPLE__) && HAS_TIME
struct timespec continuous;
clock_gettime(CLOCK_MONOTONIC, &continuous);
*seconds = continuous.tv_sec;
*nanoseconds = continuous.tv_nsec;
#elif defined(_WIN32)
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
LARGE_INTEGER count;
QueryPerformanceCounter(&count);
*seconds = count.QuadPart / freq.QuadPart;
if (freq.QuadPart < 1000000000) {
*nanoseconds =
((count.QuadPart % freq.QuadPart) * 1000000000) / freq.QuadPart;
} else {
*nanoseconds =
(count.QuadPart % freq.QuadPart) * (1000000000.0 / freq.QuadPart);
}
#else
#error Missing platform continuous time definition
#endif
break;
}
case swift_clock_id_suspending: {
#if defined(__linux__) && HAS_TIME
struct timespec suspending;
clock_gettime(CLOCK_MONOTONIC_RAW, &suspending);
*seconds = suspending.tv_sec;
*nanoseconds = suspending.tv_nsec;
#elif defined(__APPLE__) && HAS_TIME
struct timespec suspending;
clock_gettime(CLOCK_UPTIME_RAW, &suspending);
*seconds = suspending.tv_sec;
*nanoseconds = suspending.tv_nsec;
#elif defined(_WIN32)
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
LARGE_INTEGER count;
QueryPerformanceCounter(&count);
*seconds = count.QuadPart / freq.QuadPart;
if (freq.QuadPart < 1000000000) {
*nanoseconds =
((count.QuadPart % freq.QuadPart) * 1000000000) / freq.QuadPart;
} else {
*nanoseconds =
(count.QuadPart % freq.QuadPart) * (1000000000.0 / freq.QuadPart);
}
#else
#error Missing platform suspending time definition
#endif
break;
}
}
}

SWIFT_EXPORT_FROM(swift_Concurrency)
SWIFT_CC(swift)
void swift_get_clock_res(
long long *seconds,
long long *nanoseconds,
swift_clock_id clock_id) {
switch (clock_id) {
case swift_clock_id_continuous: {
#if defined(__linux__) && HAS_TIME
struct timespec continuous;
clock_getres(CLOCK_BOOTTIME, &continuous);
*seconds = continuous.tv_sec;
*nanoseconds = continuous.tv_nsec;
#elif defined(__APPLE__) && HAS_TIME
struct timespec continuous;
clock_getres(CLOCK_MONOTONIC, &continuous);
*seconds = continuous.tv_sec;
*nanoseconds = continuous.tv_nsec;
#elif defined(_WIN32)
*seconds = 0;
*nanoseconds = 1000;
#else
#error Missing platform continuous time definition
#endif
break;
}
case swift_clock_id_suspending: {
struct timespec suspending;
#if defined(__linux__) && HAS_TIME
clock_getres(CLOCK_MONOTONIC_RAW, &suspending);
*seconds = suspending.tv_sec;
*nanoseconds = suspending.tv_nsec;
#elif defined(__APPLE__) && HAS_TIME
clock_gettime(CLOCK_UPTIME_RAW, &suspending);
*seconds = suspending.tv_sec;
*nanoseconds = suspending.tv_nsec;
#elif defined(_WIN32)
*seconds = 0;
*nanoseconds = 1000;
#else
#error Missing platform suspending time definition
#endif
break;
}
}
}
98 changes: 98 additions & 0 deletions stdlib/public/Concurrency/Clock.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import Swift

/// A mechanism in which to measure time, and delay work until a given point
/// in time.
///
/// Types that conform to the `Clock` protocol define a concept of "now" which
/// is the specific instant in time that property is accessed. Any pair of calls
/// to the `now` property may have a minimum duration between them - this
/// minimum resolution is exposed by the `minimumResolution` property to inform
/// any user of the type the expected granularity of accuracy.
///
/// One of the primary uses for clocks is to schedule task sleeping. This method
/// resumes the calling task after a given deadline has been met or passed with
/// a given tolerance value. The tolerance is expected as a leeway around the
/// deadline. The clock may reschedule tasks within the tolerance to ensure
/// efficient execution of resumptions by reducing potential operating system
/// wake-ups. If no tolerance is specified (i.e. nil is passed in) the sleep
/// function is expected to schedule with a default tolerance strategy.
///
/// For more information about specific clocks see `ContinuousClock` and
/// `SuspendingClock`.
@available(SwiftStdlib 5.7, *)
public protocol Clock: Sendable {
associatedtype Instant: InstantProtocol

var now: Instant { get }
var minimumResolution: Instant.Duration { get }

func sleep(until deadline: Instant, tolerance: Instant.Duration?) async throws
}


@available(SwiftStdlib 5.7, *)
extension Clock {
/// Measure the elapsed time to execute a closure.
///
/// let clock = ContinuousClock()
/// let elapsed = clock.measure {
/// someWork()
/// }
@available(SwiftStdlib 5.7, *)
public func measure(_ work: () throws -> Void) rethrows -> Instant.Duration {
let start = now
try work()
let end = now
return start.duration(to: end)
}

/// Measure the elapsed time to execute an asynchronous closure.
///
/// let clock = ContinuousClock()
/// let elapsed = await clock.measure {
/// await someWork()
/// }
@available(SwiftStdlib 5.7, *)
public func measure(
_ work: () async throws -> Void
) async rethrows -> Instant.Duration {
let start = now
try await work()
let end = now
return start.duration(to: end)
}
}

@available(SwiftStdlib 5.7, *)
@usableFromInline
enum _ClockID: Int32 {
case continuous = 1
case suspending = 2
}

@available(SwiftStdlib 5.7, *)
@_silgen_name("swift_get_time")
@usableFromInline
internal func _getTime(
seconds: UnsafeMutablePointer<Int64>,
nanoseconds: UnsafeMutablePointer<Int64>,
clock: _ClockID)

@available(SwiftStdlib 5.7, *)
@_silgen_name("swift_get_clock_res")
@usableFromInline
internal func _getClockRes(
seconds: UnsafeMutablePointer<Int64>,
nanoseconds: UnsafeMutablePointer<Int64>,
clock: _ClockID)
Loading