Fixes to determination of VkPhysicalDeviceLimits::timestampPeriod.

- On Apple GPUs, set timestampPeriod to 1.0.
- On non-Apple GPUs, calculate timestampPeriod each time it is retrieved.
- On older devices that do not support GPU timestamps, use nanosecond
  CPU timestamps to be consistent with timestampPeriod of 1.0.
- Change MVKConfiguration::timestampPeriodLowPassAlpha and environment
  variable MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA to 1.0, to use
  only latest value by default.
- Add build-time verification that MVKConfigMembers.def
  includes all members of MVKConfiguration (unrelated).
This commit is contained in:
Bill Hollings 2023-10-16 22:59:21 -04:00
parent 107cf2c34e
commit 3a77f4ea97
8 changed files with 27 additions and 16 deletions

View File

@ -617,9 +617,9 @@ vailable when you request it, resulting in frame delays and visual stuttering.
<a name="timestamping"></a> <a name="timestamping"></a>
### Timestamping ### Timestamping
On non-Apple Silicon devices (older Mac devices), the GPU can switch power and performance On non-Apple GPUs (older Mac devices), the GPU can switch power and performance states as
states as required by usage. This affects the GPU timestamps retrievable through the Vulkan required by usage. This affects the GPU timestamps retrievable through the Vulkan API.
API. As a result, the value of `VkPhysicalDeviceLimits::timestampPeriod` can vary over time. As a result, the value of `VkPhysicalDeviceLimits::timestampPeriod` can vary over time.
Consider calling `vkGetPhysicalDeviceProperties()`, when needed, and retrieve the current Consider calling `vkGetPhysicalDeviceProperties()`, when needed, and retrieve the current
value of `VkPhysicalDeviceLimits::timestampPeriod`, to help you calibrate recent GPU value of `VkPhysicalDeviceLimits::timestampPeriod`, to help you calibrate recent GPU
timestamps queried through the Vulkan API. timestamps queried through the Vulkan API.

View File

@ -29,7 +29,9 @@ Released TBD
- Fix MSL code used in `vkCmdBlitImage()` on depth-stencil formats. - Fix MSL code used in `vkCmdBlitImage()` on depth-stencil formats.
- Improve behavior of swapchain image presentation stalls caused by Metal regression. - Improve behavior of swapchain image presentation stalls caused by Metal regression.
- Add several additional performance trackers, available via logging, or the `mvk_private_api.h` API. - Add several additional performance trackers, available via logging, or the `mvk_private_api.h` API.
- Add configurable lowpass filter for `VkPhysicalDeviceLimits::timestampPeriod`. - Add `MVKConfiguration::timestampPeriodLowPassAlpha` and environment variable
`MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA`, to add a configurable lowpass filter
for varying `VkPhysicalDeviceLimits::timestampPeriod` on non-Apple GPUs.
- Deprecate `MVK_DEBUG` env var, and add `MVK_CONFIG_DEBUG` env var to replace it. - Deprecate `MVK_DEBUG` env var, and add `MVK_CONFIG_DEBUG` env var to replace it.
- Update `MVK_CONFIGURATION_API_VERSION` and `MVK_PRIVATE_API_VERSION` to `38`. - Update `MVK_CONFIGURATION_API_VERSION` and `MVK_PRIVATE_API_VERSION` to `38`.

View File

@ -955,7 +955,7 @@ typedef struct {
* The initial value or this parameter is set by the * The initial value or this parameter is set by the
* MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA * MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA
* runtime environment variable or MoltenVK compile-time build setting. * runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, this parameter is set to 0.05 by default, * If neither is set, this parameter is set to 1.0 by default,
* indicating that the timestampPeriod will vary relatively slowly, * indicating that the timestampPeriod will vary relatively slowly,
* with the expectation that the app is querying this value infrequently. * with the expectation that the app is querying this value infrequently.
*/ */

View File

@ -1601,7 +1601,8 @@ void MVKPhysicalDevice::updateTimestampPeriod() {
// Basic lowpass filter TPout = (1 - A)TPout + (A * TPin). // Basic lowpass filter TPout = (1 - A)TPout + (A * TPin).
// The lower A is, the slower TPout will change over time. // The lower A is, the slower TPout will change over time.
float a = mvkConfig().timestampPeriodLowPassAlpha; // First time through, just use the measured value directly.
float a = earlierCPUTs ? mvkConfig().timestampPeriodLowPassAlpha : 1.0;
_properties.limits.timestampPeriod = ((1.0 - a) * _properties.limits.timestampPeriod) + (a * tsPeriod); _properties.limits.timestampPeriod = ((1.0 - a) * _properties.limits.timestampPeriod) + (a * tsPeriod);
} }
} }
@ -2637,7 +2638,7 @@ void MVKPhysicalDevice::initLimits() {
_properties.limits.optimalBufferCopyRowPitchAlignment = 1; _properties.limits.optimalBufferCopyRowPitchAlignment = 1;
_properties.limits.timestampComputeAndGraphics = VK_TRUE; _properties.limits.timestampComputeAndGraphics = VK_TRUE;
_properties.limits.timestampPeriod = mvkGetTimestampPeriod(); // Will be 1.0 on Apple Silicon _properties.limits.timestampPeriod = 1.0; // On non-Apple GPU's, this can vary over time, and is calculated based on actual GPU activity.
_properties.limits.pointSizeRange[0] = 1; _properties.limits.pointSizeRange[0] = 1;
switch (_properties.vendorID) { switch (_properties.vendorID) {

View File

@ -381,7 +381,7 @@ void MVKTimestampQueryPool::endQuery(uint32_t query, MVKCommandEncoder* cmdEncod
// If not using MTLCounterSampleBuffer, update timestamp values, then mark queries as available // If not using MTLCounterSampleBuffer, update timestamp values, then mark queries as available
void MVKTimestampQueryPool::finishQueries(MVKArrayRef<const uint32_t> queries) { void MVKTimestampQueryPool::finishQueries(MVKArrayRef<const uint32_t> queries) {
if ( !_mtlCounterBuffer ) { if ( !_mtlCounterBuffer ) {
uint64_t ts = mvkGetTimestamp(); uint64_t ts = mvkGetElapsedNanoseconds();
for (uint32_t qry : queries) { _timestamps[qry] = ts; } for (uint32_t qry : queries) { _timestamps[qry] = ts; }
} }
MVKQueryPool::finishQueries(queries); MVKQueryPool::finishQueries(queries);

View File

@ -23,16 +23,13 @@
// To use this file, define the macros: // To use this file, define the macros:
// //
// MVK_CONFIG_MEMBER(member, mbrType, name) // MVK_CONFIG_MEMBER(member, mbrType, name)
// MVK_CONFIG_MEMBER_STRING(member, strObj, name) // MVK_CONFIG_MEMBER_STRING(member, mbrType, name)
// //
// then #include this file inline with your code. // then #include this file inline with your code.
// //
// The name prameter is the name of the configuration parameter, which is used as the name // The name prameter is the name of the configuration parameter, which is used as the name
// of the environment variable, and build setting, that sets the config value, and is entered // of the environment variable, and build setting, that sets the config value, and is entered
// here without the "MVK_CONFIG_" prefix. // here without the "MVK_CONFIG_" prefix.
//
// Since string members are set from char pointers, the text must be copied to a std::string
// object, which is passed as a parameter to MVK_CONFIG_MEMBER_STRING.
#ifndef MVK_CONFIG_MEMBER #ifndef MVK_CONFIG_MEMBER
@ -69,7 +66,7 @@ MVK_CONFIG_MEMBER(forceLowPowerGPU, VkBool32,
MVK_CONFIG_MEMBER(semaphoreUseMTLFence, VkBool32, ALLOW_METAL_FENCES) // Deprecated legacy MVK_CONFIG_MEMBER(semaphoreUseMTLFence, VkBool32, ALLOW_METAL_FENCES) // Deprecated legacy
MVK_CONFIG_MEMBER(semaphoreSupportStyle, MVKVkSemaphoreSupportStyle, VK_SEMAPHORE_SUPPORT_STYLE) MVK_CONFIG_MEMBER(semaphoreSupportStyle, MVKVkSemaphoreSupportStyle, VK_SEMAPHORE_SUPPORT_STYLE)
MVK_CONFIG_MEMBER(autoGPUCaptureScope, MVKConfigAutoGPUCaptureScope, AUTO_GPU_CAPTURE_SCOPE) MVK_CONFIG_MEMBER(autoGPUCaptureScope, MVKConfigAutoGPUCaptureScope, AUTO_GPU_CAPTURE_SCOPE)
MVK_CONFIG_MEMBER_STRING(autoGPUCaptureOutputFilepath, evGPUCapFileStrObj, AUTO_GPU_CAPTURE_OUTPUT_FILE) MVK_CONFIG_MEMBER_STRING(autoGPUCaptureOutputFilepath, char*, AUTO_GPU_CAPTURE_OUTPUT_FILE)
MVK_CONFIG_MEMBER(texture1DAs2D, VkBool32, TEXTURE_1D_AS_2D) MVK_CONFIG_MEMBER(texture1DAs2D, VkBool32, TEXTURE_1D_AS_2D)
MVK_CONFIG_MEMBER(preallocateDescriptors, VkBool32, PREALLOCATE_DESCRIPTORS) MVK_CONFIG_MEMBER(preallocateDescriptors, VkBool32, PREALLOCATE_DESCRIPTORS)
MVK_CONFIG_MEMBER(useCommandPooling, VkBool32, USE_COMMAND_POOLING) MVK_CONFIG_MEMBER(useCommandPooling, VkBool32, USE_COMMAND_POOLING)

View File

@ -20,8 +20,19 @@
#include "MVKOSExtensions.h" #include "MVKOSExtensions.h"
#include "MVKFoundation.h" #include "MVKFoundation.h"
// Return the expected size of MVKConfiguration, based on contents of MVKConfigMembers.def.
static constexpr uint32_t getExpectedMVKConfigurationSize() {
#define MVK_CONFIG_MEMBER_STRING(member, mbrType, name) MVK_CONFIG_MEMBER(member, mbrType, name)
#define MVK_CONFIG_MEMBER(member, mbrType, name) cfgSize += sizeof(mbrType);
uint32_t cfgSize = 0;
#include "MVKConfigMembers.def"
return cfgSize;
}
static bool _mvkConfigInitialized = false; static bool _mvkConfigInitialized = false;
static void mvkInitConfigFromEnvVars() { static void mvkInitConfigFromEnvVars() {
static_assert(getExpectedMVKConfigurationSize() == sizeof(MVKConfiguration), "MVKConfigMembers.def does not match the members of MVKConfiguration.");
_mvkConfigInitialized = true; _mvkConfigInitialized = true;
MVKConfiguration evCfg; MVKConfiguration evCfg;
@ -32,8 +43,8 @@ static void mvkInitConfigFromEnvVars() {
#define MVK_CONFIG_MEMBER(member, mbrType, name) \ #define MVK_CONFIG_MEMBER(member, mbrType, name) \
evCfg.member = (mbrType)mvkGetEnvVarNumber(STR(MVK_CONFIG_##name), MVK_CONFIG_##name); evCfg.member = (mbrType)mvkGetEnvVarNumber(STR(MVK_CONFIG_##name), MVK_CONFIG_##name);
#define MVK_CONFIG_MEMBER_STRING(member, strObj, name) \ #define MVK_CONFIG_MEMBER_STRING(member, mbrType, name) \
evCfg.member = mvkGetEnvVarString(STR(MVK_CONFIG_##name), strObj, MVK_CONFIG_##name); evCfg.member = mvkGetEnvVarString(STR(MVK_CONFIG_##name), evGPUCapFileStrObj, MVK_CONFIG_##name);
#include "MVKConfigMembers.def" #include "MVKConfigMembers.def"

View File

@ -323,5 +323,5 @@ void mvkSetConfig(const MVKConfiguration& mvkConfig);
* This can be set to a float between 0.0 and 1.0. * This can be set to a float between 0.0 and 1.0.
*/ */
#ifndef MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA #ifndef MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA
# define MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA 0.05 # define MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA 1.0
#endif #endif