Skip to content

Commit

Permalink
Update Signpost
Browse files Browse the repository at this point in the history
  • Loading branch information
Kyle-Ye committed Sep 22, 2024
1 parent d27410b commit 70817fd
Show file tree
Hide file tree
Showing 4 changed files with 275 additions and 38 deletions.
165 changes: 165 additions & 0 deletions Sources/COpenSwiftUICore/include/kdebug_Private.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
//
// kdebug_Private.h
// COpenSwiftUICore
//
// Audited for RELEASE_2024
// Status: Complete

#ifndef kdebug_Private_h
#define kdebug_Private_h

#include "OpenSwiftUIBase.h"

#if OPENSWIFTUI_TARGET_OS_DARWIN

/*
* Copyright (c) 2000-2018 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/

#include <stdint.h>
#include <stdbool.h>
#include <sys/cdefs.h>
#include <sys/kdebug.h>

#include <Availability.h>

#pragma mark - user space SPI

/*
* OS components can use the full precision of the "code" field
* (Class, SubClass, Code) to inject events using kdebug_trace() by
* using:
*
* kdebug_trace(KDBG_CODE(DBG_XPC, 15, 1) | DBG_FUNC_NONE, 1, 2, 3, 4);
*
* These trace points can be included in production code, since they
* use reserved, non-overlapping ranges. The performance impact when
* kernel tracing is not enabled is minimal. However, when tracing is enabled,
* each tracepoint becomes a syscall. For this reason, os_signpost(3) is
* recommended instead of kdebug_trace(2).
*
* Classes can be reserved by filing a Radar in xnu | ktrace.
*
* 64-bit arguments may be truncated if the system is using a 32-bit
* kernel.
*
* On error, -1 will be returned and errno will indicate the error.
*/
int kdebug_trace(uint32_t code, uint64_t arg1, uint64_t arg2, uint64_t arg3,
uint64_t arg4)
__OSX_AVAILABLE(10.10) __IOS_AVAILABLE(8.2);

/*!
* @function kdebug_trace_string
*
* @discussion
* This function emits strings to kdebug trace along with an ID and allows
* for previously-traced strings to be overwritten and invalidated.
*
* To start tracing a string and generate an ID to use to refer to it:
*
* string_id = kdebug_trace_string(debugid, 0, "string");
*
* To replace a string previously traced:
*
* string_id = kdebug_trace_string(debugid, string_id, "new string");
*
* To invalidate a string ID:
*
* string_id = kdebug_trace_string(debugid, string_id, NULL);
*
* To check for errors:
*
* if ((int64_t)string_id == -1) { perror("string error") }
*
* @param debugid
* The `debugid` to check if its enabled before tracing and include as
* an argument in the event containing the string.
*
* Some classes or subclasses are reserved for specific uses and are not
* allowed to be used with this function. No function qualifiers are
* allowed on `debugid`.
*
* @param str_id
* When 0, a new ID will be generated and returned if tracing is
* enabled.
*
* Otherwise `str_id` must contain an ID that was previously generated
* with this function. Clents should pass NULL in `str` if `str_id`
* is no longer in use. Otherwise, the string previously mapped to
* `str_id` will be overwritten with the contents of `str`.
*
* @param str
* A NUL-terminated 'C' string containing the characters that should be
* traced alongside `str_id`.
*
* If necessary, the string will be truncated at an
* implementation-defined length. The string must not be the empty
* string, but can be NULL if a valid `str_id` is provided.
*
* @return
* 0 if tracing is disabled or `debugid` is being filtered out of trace.
* It can also return (int64_t)-1 if an error occured. Otherwise,
* it returns the ID to use to refer to the string in future
* kdebug_trace(2) calls.
*
* The errors that can occur are:
*
* EINVAL
* There are function qualifiers on `debugid`, `str` is empty, or
* `str_id` was not generated by this function.
* EPERM
* The `debugid`'s class or subclass is reserved for internal use.
* EFAULT
* `str` is an invalid address or NULL when `str_id` is 0.
*/
extern uint64_t kdebug_trace_string(uint32_t debugid, uint64_t str_id,
const char *str)
__OSX_AVAILABLE(10.11) __IOS_AVAILABLE(9.0);

/*
* Although the performance impact of kdebug_trace() when kernel
* tracing is not enabled is minimal, it may require the caller to
* perform an expensive calculation/summarization. This cost can be
* skipped by checking the kdebug_is_enabled() predicate:
*
* if (kdebug_is_enabled(KDBG_CODE(DBG_XPC, 15, 1))) {
* uint64_t arg1 = ...;
* uint64_t arg2 = ...;
* kdebug_trace(KDBG_CODE(DBG_XPC, 15, 1) | DBG_FUNC_NONE, arg1, arg2, 0, 0);
* }
*
* If tracing is enabled for the code at the time of the check, 1
* will be returned. Otherwise, 0 will be returned.
*/
extern bool kdebug_is_enabled(uint32_t code)
__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0)
__WATCHOS_AVAILABLE(3.0) __TVOS_AVAILABLE(10.0);

#endif

#endif /* kdebug_Private_h */
116 changes: 90 additions & 26 deletions Sources/OpenSwiftUICore/Log/Signpost.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,35 @@
//
// Audited for RELEASE_2021
// Status: WIP
// ID: 34756F646CF7AC3DBE2A8E0B344C962F
// ID: 34756F646CF7AC3DBE2A8E0B344C962F (RELEASE_2021)
// ID: 59349949219F590F26B6A55CEC9D59A2 (RELEASE_2024)

internal import COpenSwiftUICore
internal import OpenGraphShims
#if canImport(Darwin)
import os.signpost
#endif

extension Signpost {
package static let render = Signpost.kdebug(0, "Render")
package static let postUpdateActions = Signpost.kdebug(2, "PostUpdateActions")
package static let renderUpdate = Signpost.kdebug(3, "RenderUpdate")
package static let renderFlattened = Signpost.kdebug(4, "RenderFlattened")
package static let bodyInvoke = Signpost.kdebug(5, "BodyInvoke")
package static let linkCreate = Signpost.os_log(6, "LinkCreate")
package static let linkUpdate = Signpost.os_log(7, "LinkUpdate")
package static let linkDestroy = Signpost.os_log(8, "LinkDestroy")
package static let viewHost = Signpost.kdebug(9, "ViewHost")
package static let platformView = Signpost.os_log(10, "ViewMapping")
package static let platformUpdate = Signpost.os_log(11, "PlatformViewUpdate")
package static let animationState = Signpost.os_log(12, "AnimationState")
package static let eventHandling = Signpost.os_log(13, "EventHandling")
}

#if canImport(Darwin)
private let _signpostLog = OSLog(subsystem: Log.subsystem, category: "OpenSwiftUI")
#endif

package struct Signpost {
#if canImport(Darwin)
package static let archiving = OSSignposter(logger: Log.archiving)
Expand All @@ -19,24 +41,79 @@ package struct Signpost {

package static let moduleName: String = Tracing.libraryName(defining: Signpost.self)

@inlinable
package static func os_log(_: UInt8, _ name: StaticString) -> Signpost {
Signpost(style: .os_log(name), stability: .debug)
}

@inlinable
package static func kdebug(_ code: UInt8, _: StaticString?) -> Signpost {
Signpost(style: .kdebug(code), stability: .debug)
}

package static func kdebug(_ code: UInt8) -> Signpost {
Signpost(style: .kdebug(code), stability: .debug)
}

private enum Style {
case kdebug(UInt8)
case os_log(StaticString)
}

private enum Stability: Hashable {
case disabled
case verbose
case debug
case published

@inline(__always)
static var valid: [Stability] {
#if DEBUG
[.debug, .published]
#else
[.published]
#endif
}
}

private let style: Style
private let stability: Stability

// TODO
@inlinable
package var disabled: Signpost {
Signpost(style: style, stability: .disabled)
}

@inlinable
package var verbose: Signpost {
Signpost(style: style, stability: .verbose)
}

@inlinable
package var published: Signpost {
Signpost(style: style, stability: .published)
}

package var isEnabled: Bool {
switch stability {
case .disabled, .verbose, .debug:
guard Stability.valid.contains(where: { $0 == stability }) else {
return false
case .published:
return true
}
#if canImport(Darwin)
switch style {
case let .kdebug(code):
return kdebug_is_enabled(UInt32(code))
case let .os_log(name):
guard kdebug_is_enabled(UInt32(OSSignpostType.event.rawValue & 0xfc) | 0x14110000) else {
return false
}
return _signpostLog.signpostsEnabled
}
#else
return true
#endif
}

package static let render = Signpost(style: .kdebug(0), stability: .published)
package static let renderUpdate = Signpost(style: .kdebug(0), stability: .published)
package static let viewHost = Signpost(style: .kdebug(9), stability: .published)
package static let bodyInvoke = Signpost(style: .kdebug(5), stability: .published)

// TODO
@_transparent
@inline(__always)
package func traceInterval<R>(
Expand All @@ -51,6 +128,7 @@ package struct Signpost {
return closure()
}

// TODO
@_transparent
@inline(__always)
package func traceInterval<R>(
Expand All @@ -67,23 +145,9 @@ package struct Signpost {
}
}

extension Signpost {
private enum Style {
case kdebug(UInt8)
case os_log(StaticString)
}

private enum Stability: Hashable {
case disabled
case verbose
case debug
case published
}
}

// TODO
@_transparent
@inline(__always)
// FIXME
package func traceRuleBody<R>(_ type: Any.Type, body: () -> R) -> R {
Signpost.bodyInvoke.traceInterval(
"%{public}@.body [in %{public}@]",
Expand Down
2 changes: 0 additions & 2 deletions Sources/OpenSwiftUICore/Util/Tracing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ internal import OpenGraphShims
import Foundation

enum Tracing {
// RELEASE_2021 ID: D59B7A281FFF29619A43A3D8F551CCE1
// RELEASE_2024 ID: 56D4CED87D5B226E2B40FB60C47D6F49
private static var moduleLookupCache = ThreadSpecific<[UnsafeRawPointer : String]>([:])

static func libraryName(defining type: Any.Type) -> String {
Expand Down
30 changes: 20 additions & 10 deletions Tests/OpenSwiftUICoreTests/Util/TracingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,27 @@ import Testing
struct TracingTests {
struct Demo {}

@Test(.disabled(if: !attributeGraphEnabled, "OGTypeDescription is not implemented yet"))
func name() {
#expect(Tracing.nominalTypeName(Int.self) == "Int")
#expect(Tracing.nominalTypeName(String.self) == "String")
#expect(Tracing.nominalTypeName(Demo.self) == "TracingTests.Demo")
@Test(
.disabled(if: !attributeGraphEnabled, "OGTypeDescription is not implemented yet"),
arguments: [
(type: Int.self as Any.Type, nominalName: "Int"),
(type: String.self as Any.Type, nominalName: "String"),
(type: Demo.self as Any.Type, nominalName: "TracingTests.Demo"),
]
)
func name(type: Any.Type, nominalName: String) {
#expect(Tracing.nominalTypeName(type) == nominalName)
}

@Test(.disabled(if: !attributeGraphEnabled, "OGTypeNominalDescriptor is not implemented yet"))
func library() async throws {
#expect(Tracing.libraryName(defining: Int.self) == "libswiftCore.dylib")
#expect(Tracing.libraryName(defining: String.self) == "libswiftCore.dylib")
#expect(Tracing.libraryName(defining: Demo.self) == "OpenSwiftUICoreTests")
@Test(
.disabled(if: !attributeGraphEnabled, "OGTypeNominalDescriptor is not implemented yet"),
arguments: [
(type: Int.self as Any.Type, libraryName: "libswiftCore.dylib"),
(type: String.self as Any.Type, libraryName: "libswiftCore.dylib"),
(type: Demo.self as Any.Type, libraryName: "OpenSwiftUICoreTests"),
]
)
func library(type: Any.Type, libraryName: String) {
#expect(Tracing.libraryName(defining: type) == libraryName)
}
}

0 comments on commit 70817fd

Please sign in to comment.