/* * Copyright (c) 2017-2018 Apple Inc. All rights reserved. */ #ifndef __OS_SIGNPOST_H__ #define __OS_SIGNPOST_H__ #include __BEGIN_DECLS OS_ASSUME_NONNULL_BEGIN /*! * @header os_signpost * * The os_signpost APIs let clients add lightweight instrumentation to * code for collection and visualization by performance analysis tooling. * * Clients of os_signpost can instrument interesting periods of time * ('intervals') and single points in time ('events'). Intervals can span * processes, be specific to one process, or be specific to a single thread. * * Intervals and events include an os_log-style format string and arguments * which can be used to convey contextual information. */ #pragma mark - Interval Matching Scope /*! * The matching scope for signpost intervals logged with a given os_log_t is * specified in that log handles's configuration plist using the * 'Signpost-Scope' key and defaults to process-wide scope (i.e. 'Process' * value) if unspecified. * * Signpost interval begin and end matching can have 3 different scopes: * * - Thread-wide: The search scope for matching begins and ends is restricted to * single threads. To set this as the search scope for an os_log_t, set * 'Thread' as the string value for the 'Signpost-Scope' key in the * os_log_t's configuration plist. * * - Process-wide (Default value): The search scope for matching begins and ends * is restricted to a single process. (i.e. no cross-process intervals) * To set this as the search scope for an os_log_t, set * 'Process' as the string value for the 'Signpost-Scope' key in the * os_log_t's configuration plist or do not specify any 'Signpost-Scope' key- * value pair. * * - System-wide: The search scope for matching begins and ends is not * restricted. (i.e. cross-process intervals are possible) * To set this as the search scope for an os_log_t, set * 'System' as the string value for the 'Signpost-Scope' key in the * os_log_t's configuration plist. * */ #pragma mark - Signpost IDs /*! * Disambiguating intervals with signpost IDs * * Intervals with the same log handle and interval name can be in flight * simultaneously. In order for tools to correctly match begin signposts with * end signposts, it is necessary to identify each interval with an * os_signpost_id_t. * * If only one interval with a given os_log_t and interval name will ever be in * flight at a time, use the os_signpost_t convenience value * OS_SIGNPOST_ID_EXCLUSIVE. This can avoid having to share state between begin * and end callsites. * * If there exists some non-pointer uint64_t value that uniquely identifies * begin/end pairs, that value can be cast directly to an os_signpost_id_t. * Note that the values OS_SIGNPOST_ID_NULL and OS_SIGNPOST_ID_INVALID are * reserved and identical values may not be used in this manner. * * If there exists a pointer which can identify begin/end pairs, an * os_signpost_id_t can be generated from that pointer with * os_signpost_id_make_with_pointer(). This approach is not applicable to * signposts that span process boundaries. * * If no existing pointer or value is applicable, a new unique value can be * generated using the os_signpost_id_generate() function. The returned value * is guaranteed to be unique within the matching scope specified on the log * handle. */ /*! * @typedef os_signpost_id_t * * @brief * The type to represent a signpost ID. * * @discussion. * Any 64-bit value can be cast to an os_signpost_id_t except for the * OS_SIGNPOST_ID_NULL and OS_SIGNPOST_ID_INVALID reserved values. * * @const OS_SIGNPOST_ID_NULL * Represents the null (absent) signpost ID. It is used by the signpost * subsystem when a given signpost is disabled. * * @const OS_SIGNPOST_ID_INVALID * Represents an invalid signpost ID, which signals that an error has occurred. * * @const OS_SIGNPOST_ID_EXCLUSIVE * A convenience value for signpost intervals that will never occur * concurrently. */ typedef uint64_t os_signpost_id_t; #ifndef __swift__ #define OS_SIGNPOST_ID_NULL ((os_signpost_id_t)0) #define OS_SIGNPOST_ID_INVALID ((os_signpost_id_t)~0) #define OS_SIGNPOST_ID_EXCLUSIVE ((os_signpost_id_t)0xEEEEB0B5B2B2EEEE) #endif /*! * @function os_signpost_id_make_with_pointer * * @abstract * Make an os_signpost_id from a pointer value. * * @discussion * Mangles the pointer to create a valid os_signpost_id, including removing * address randomization. Checks that the signpost matching scope is not * system-wide. * * @param log * Log handle previously created with os_log_create. * * @param ptr * Any pointer that disambiguates among concurrent intervals with the same * os_log_t and interval names. * * @result * Returns a valid os_signpost_id_t. Returns OS_SIGNPOST_ID_NULL if signposts * are turned off. Returns OS_SIGNPOST_ID_INVALID if the log handle is * system-scoped. */ API_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)) OS_EXPORT OS_NOTHROW os_signpost_id_t os_signpost_id_make_with_pointer(os_log_t log, const void *_Nullable ptr); #if __OBJC__ /*! * @function os_signpost_id_make_with_id * * @abstract * Make an os_signpost_id from an Objective-C id, as in * os_signpost_id_make_with_pointer. */ #define os_signpost_id_make_with_id(log, ptr) \ os_signpost_id_make_with_pointer(log, (__bridge const void *_Nullable)(ptr)) #endif /* __OBJC__ */ /*! * @function os_signpost_id_generate * * @abstract * Generates an ID guaranteed to be unique within the matching scope of the * provided log handle. * * @discussion * Each call to os_signpost_id_generate() with a given log handle and its * matching scope will return a different os_signpost_id_t. * * @param log * Log handle previously created with os_log_create. * * @result * Returns a valid os_signpost_id_t. Returns OS_SIGNPOST_ID_NULL if signposts * are disabled. */ API_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)) OS_EXPORT OS_NOTHROW OS_WARN_RESULT os_signpost_id_t os_signpost_id_generate(os_log_t log); #pragma mark - Signpost Enablement /*! * @function os_signpost_enabled * * @abstract * Returns true if signpost log messages are enabled for a particular log * handle. * * @discussion * Returns true if signpost log messages are enabled for a particular log. * Use this to avoid doing expensive argument marshalling leading into a call * to os_signpost_* * * @param log * Log handle previously created with os_log_create. * * @result * Returns ‘true’ if signpost log messages are enabled. */ API_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)) OS_EXPORT OS_NOTHROW OS_PURE OS_WARN_RESULT bool os_signpost_enabled(os_log_t log); #pragma mark - Interval begin/end /*! * @function os_signpost_interval_begin * * @abstract * Begins a signposted interval. * * @param log * Log handle previously created with os_log_create. * * @param interval_id * An ID for the event, see Signpost IDs above. * * @param name * The name of this event. This must be a string literal. * * @param ... (format + arguments) * Additional information to include with this signpost. This format string * must be a string literal, as with the os_log family of functions. */ #define os_signpost_interval_begin(log, interval_id, name, ...) \ os_signpost_emit_with_type(log, OS_SIGNPOST_INTERVAL_BEGIN, \ interval_id, name, ##__VA_ARGS__) /*! * @function os_signpost_animation_interval_begin * * @abstract * Begins a signposted interval that is tagged as an animation. * * @param log * Log handle previously created with os_log_create. * * @param interval_id * An ID for the event, see Signpost IDs above. * * @param name * The name of this event. This must be a string literal. * * @param ... (format + arguments) * Additional information to include with this signpost. This format string * must be a string literal, as with the os_log family of functions. */ #define os_signpost_animation_interval_begin(log, interval_id, name, ...) \ _os_signpost_animation_interval_begin(log, interval_id, name, \ "" __VA_ARGS__) /*! * @function os_signpost_interval_end * * @abstract * Ends a signposted interval. * * @param log * The log handle which was provided to os_signpost_interval_begin, * * @param interval_id * The ID for the event which was provided to os_signpost_interval_begin. See * Signpost IDs above. * * @param name * The name of the event provided to os_signost_interval_begin. This must be a * string literal. * * @param ... (format + arguments) * Additional information to include with this signpost. This format string * must be a string literal, as with the os_log family of functions. */ #define os_signpost_interval_end(log, interval_id, name, ...) \ os_signpost_emit_with_type(log, OS_SIGNPOST_INTERVAL_END, \ interval_id, name, ##__VA_ARGS__) #pragma mark - Signpost event marking /*! * @function os_signpost_event_emit * * @abstract * os_signpost_event_emit marks a point of interest in time with no duration. * * @param log * Log handle previously created with os_log_create. * * @param event_id * An ID for the event, see Signpost IDs above. This ID can be used to convey * additional information about the event that is being emitted without * incurring extra performance overhead. * * @param name * The name of this event. This must be a string literal. * * @param ... (format + arguments) * Additional information to include with this signpost. This format string * must be a string literal, as with the os_log family of functions. */ #define os_signpost_event_emit(log, event_id, name, ...) \ os_signpost_emit_with_type(log, OS_SIGNPOST_EVENT, \ event_id, name, ##__VA_ARGS__) #pragma mark - Points of Interest /*! * @const OS_LOG_CATEGORY_POINTS_OF_INTEREST * * Provide this value as the category to os_log_create to indicate that * signposts on the resulting log handle provide high-level events that can be * used to orient a developer looking at performance data. These will be * displayed by default by performance tools like Instruments.app. */ #ifndef __swift__ #define OS_LOG_CATEGORY_POINTS_OF_INTEREST "PointsOfInterest" #endif #pragma mark - Dynamic Tracing /*! * @const OS_LOG_CATEGORY_DYNAMIC_TRACING * * Provide this value as the category to os_log_create to indicate that * signposts emitted to the resulting log handle should be disabled by * default, reducing the runtime overhead. os_signpost_enabled calls on * the resulting log handle will only return 'true' when a performance * tool like Instruments.app is recording. */ #if OS_LOG_TARGET_HAS_10_15_FEATURES #ifndef __swift__ #define OS_LOG_CATEGORY_DYNAMIC_TRACING "DynamicTracing" #endif #endif /*! * @const OS_LOG_CATEGORY_DYNAMIC_STACK_TRACING * * Provide this value as the category to os_log_create to indicate that * signposts emitted to the resulting log handle should capture user * backtraces. This behavior is more expensive, so os_signpost_enabled * will only return 'true' when a performance tool like Instruments.app * is recording. */ #if OS_LOG_TARGET_HAS_10_15_FEATURES #ifndef __swift__ #define OS_LOG_CATEGORY_DYNAMIC_STACK_TRACING "DynamicStackTracing" #endif #endif #pragma mark - Signpost Internals /*! * @typedef os_signpost_type_t * * @brief * The type of a signpost tracepoint, do not use directly. */ OS_ENUM(os_signpost_type, uint8_t, OS_SIGNPOST_EVENT = 0x00, OS_SIGNPOST_INTERVAL_BEGIN = 0x01, OS_SIGNPOST_INTERVAL_END = 0x02, ); #ifndef __swift__ #define OS_SIGNPOST_TYPE_MASK 0x03 #endif #define _OS_SIGNPOST_ANIMATION_INTERVAL_TAG "isAnimation=YES" #define _os_signpost_animation_interval_begin(log, spid, name, fmt, ...) \ os_signpost_interval_begin(log, spid, name, \ fmt " " _OS_SIGNPOST_ANIMATION_INTERVAL_TAG, \ ##__VA_ARGS__) API_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)) OS_EXPORT OS_NOTHROW OS_NOT_TAIL_CALLED void _os_signpost_emit_with_name_impl(void *dso, os_log_t log, os_signpost_type_t type, os_signpost_id_t spid, const char *name, const char *format, uint8_t *buf, uint32_t size); #define _os_signpost_emit_with_type(emitfn, log, type, spid, name, ...) \ __extension__({ \ os_log_t _log_tmp = (log); \ os_signpost_type_t _type_tmp = (type); \ os_signpost_id_t _spid_tmp = (spid); \ if (_spid_tmp != OS_SIGNPOST_ID_NULL && \ _spid_tmp != OS_SIGNPOST_ID_INVALID && \ os_signpost_enabled(_log_tmp)) { \ OS_LOG_CALL_WITH_FORMAT_NAME((emitfn), \ (&__dso_handle, _log_tmp, _type_tmp, _spid_tmp), \ name, "" __VA_ARGS__); \ } \ }) #if OS_LOG_TARGET_HAS_10_14_FEATURES #define os_signpost_emit_with_type(log, type, spid, name, ...) \ _os_signpost_emit_with_type(_os_signpost_emit_with_name_impl, log, \ type, spid, name, ##__VA_ARGS__) #else #define os_signpost_emit_with_type(log, type, spid, name, ...) \ __extension__({ \ if (_os_signpost_emit_with_name_impl != NULL) { \ _os_signpost_emit_with_type(_os_signpost_emit_with_name_impl, log, \ type, spid, name, ##__VA_ARGS__); \ } \ }) #endif OS_ASSUME_NONNULL_END __END_DECLS #endif // __OS_SIGNPOST_H__