Skip to content

Commit

Permalink
Merge pull request #2017 from billhollings/config-timestampPeriod-low…
Browse files Browse the repository at this point in the history
…pass

Add configurable lowpass filter for VkPhysicalDeviceLimits::timestampPeriod.
  • Loading branch information
billhollings authored Sep 12, 2023
2 parents a2d5b25 + 62e0368 commit 54dad69
Show file tree
Hide file tree
Showing 12 changed files with 211 additions and 117 deletions.
56 changes: 8 additions & 48 deletions Common/MVKOSExtensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,62 +108,22 @@ void mvkDispatchToMainAndWait(dispatch_block_t block);
#pragma mark Process environment

/**
* Returns the value of the environment variable at the given name,
* or an empty string if no environment variable with that name exists.
*
* If pWasFound is not null, its value is set to true if the environment
* variable exists, or false if not.
* Sets the value of the environment variable at the given name, into the
* std::string, and returns whether the environment variable was found.
*/
std::string mvkGetEnvVar(std::string varName, bool* pWasFound = nullptr);
bool mvkGetEnvVar(const char* evName, std::string& evStr);

/**
* Returns the value of the environment variable at the given name,
* or zero if no environment variable with that name exists.
*
* If pWasFound is not null, its value is set to true if the environment
* variable exists, or false if not.
* Returns a pointer to a string containing the value of the environment variable at
* the given name, or returns the default value if the environment variable was not set.
*/
int64_t mvkGetEnvVarInt64(std::string varName, bool* pWasFound = nullptr);
const char* mvkGetEnvVarString(const char* evName, std::string& evStr, const char* defaultValue = "");

/**
* Returns the value of the environment variable at the given name,
* or false if no environment variable with that name exists.
*
* If pWasFound is not null, its value is set to true if the environment
* variable exists, or false if not.
* or returns the default value if the environment variable was not set.
*/
bool mvkGetEnvVarBool(std::string varName, bool* pWasFound = nullptr);

#define MVK_SET_FROM_ENV_OR_BUILD_BOOL(cfgVal, EV) \
do { \
bool wasFound = false; \
bool ev = mvkGetEnvVarBool(#EV, &wasFound); \
cfgVal = wasFound ? ev : EV; \
} while(false)

#define MVK_SET_FROM_ENV_OR_BUILD_INT64(cfgVal, EV) \
do { \
bool wasFound = false; \
int64_t ev = mvkGetEnvVarInt64(#EV, &wasFound); \
cfgVal = wasFound ? ev : EV; \
} while(false)

// Pointer cast permits cfgVal to be an enum var
#define MVK_SET_FROM_ENV_OR_BUILD_INT32(cfgVal, EV) \
do { \
bool wasFound = false; \
int64_t ev = mvkGetEnvVarInt64(#EV, &wasFound); \
int64_t val = wasFound ? ev : EV; \
*(int32_t*)&cfgVal = (int32_t)std::min(std::max(val, (int64_t)INT32_MIN), (int64_t)INT32_MAX); \
} while(false)

#define MVK_SET_FROM_ENV_OR_BUILD_STRING(cfgVal, EV, strObj) \
do { \
bool wasFound = false; \
std::string ev = mvkGetEnvVar(#EV, &wasFound); \
strObj = wasFound ? std::move(ev) : EV; \
cfgVal = strObj.c_str(); \
} while(false)
double mvkGetEnvVarNumber(const char* evName, double defaultValue = 0.0);


#pragma mark -
Expand Down
17 changes: 9 additions & 8 deletions Common/MVKOSExtensions.mm
Original file line number Diff line number Diff line change
Expand Up @@ -81,21 +81,22 @@ void mvkDispatchToMainAndWait(dispatch_block_t block) {
#pragma mark -
#pragma mark Process environment

string mvkGetEnvVar(string varName, bool* pWasFound) {
bool mvkGetEnvVar(const char* varName, string& evStr) {
@autoreleasepool {
NSDictionary* nsEnv = [[NSProcessInfo processInfo] environment];
NSString* envStr = nsEnv[@(varName.c_str())];
if (pWasFound) { *pWasFound = envStr != nil; }
return envStr ? envStr.UTF8String : "";
NSString* nsStr = nsEnv[@(varName)];
if (nsStr) { evStr = nsStr.UTF8String; }
return nsStr != nil;
}
}

int64_t mvkGetEnvVarInt64(string varName, bool* pWasFound) {
return strtoll(mvkGetEnvVar(varName, pWasFound).c_str(), NULL, 0);
const char* mvkGetEnvVarString(const char* varName, string& evStr, const char* defaultValue) {
return mvkGetEnvVar(varName, evStr) ? evStr.c_str() : defaultValue;
}

bool mvkGetEnvVarBool(std::string varName, bool* pWasFound) {
return mvkGetEnvVarInt64(varName, pWasFound) != 0;
double mvkGetEnvVarNumber(const char* varName, double defaultValue) {
string evStr;
return mvkGetEnvVar(varName, evStr) ? strtod(evStr.c_str(), nullptr) : defaultValue;
}


Expand Down
4 changes: 2 additions & 2 deletions Docs/MoltenVK_Runtime_UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -517,8 +517,8 @@ you can address the issue as follows:
- Errors encountered during **Runtime Shader Conversion** are logged to the console.

- To help understand conversion issues during **Runtime Shader Conversion**, you can enable the
logging of the *SPIR-V* and *MSL* shader source code during shader conversion, by turning on
the `MVKConfiguration::debugMode` configuration parameter, or setting the value of the `MVK_DEBUG`
logging of the *SPIR-V* and *MSL* shader source code during shader conversion, by turning on the
`MVKConfiguration::debugMode` configuration parameter, or setting the value of the `MVK_CONFIG_DEBUG`
runtime environment variable to `1`. See the [*MoltenVK Configuration*](#moltenvk_config)
description above.

Expand Down
2 changes: 2 additions & 0 deletions Docs/Whats_New.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Released TBD
- Fix case where a `CAMetalDrawable` with invalid pixel format causes onscreen flickering.
- 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 configurable lowpass filter for `VkPhysicalDeviceLimits::timestampPeriod`.
- 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`.


Expand Down
10 changes: 10 additions & 0 deletions MoltenVK/MoltenVK.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,10 @@
A9B51BD8225E986A00AC74D2 /* MVKOSExtensions.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9B51BD2225E986A00AC74D2 /* MVKOSExtensions.mm */; };
A9B51BD9225E986A00AC74D2 /* MVKOSExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B51BD6225E986A00AC74D2 /* MVKOSExtensions.h */; };
A9B51BDA225E986A00AC74D2 /* MVKOSExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B51BD6225E986A00AC74D2 /* MVKOSExtensions.h */; };
A9C327562AAFBD390025EE79 /* MVKConfigMembers.def in Headers */ = {isa = PBXBuildFile; fileRef = A9C327542AAF8A770025EE79 /* MVKConfigMembers.def */; };
A9C327572AAFBD3A0025EE79 /* MVKConfigMembers.def in Headers */ = {isa = PBXBuildFile; fileRef = A9C327542AAF8A770025EE79 /* MVKConfigMembers.def */; };
A9C327582AAFBD3A0025EE79 /* MVKConfigMembers.def in Headers */ = {isa = PBXBuildFile; fileRef = A9C327542AAF8A770025EE79 /* MVKConfigMembers.def */; };
A9C327592AAFBD3B0025EE79 /* MVKConfigMembers.def in Headers */ = {isa = PBXBuildFile; fileRef = A9C327542AAF8A770025EE79 /* MVKConfigMembers.def */; };
A9C96DD01DDC20C20053187F /* MVKMTLBufferAllocation.h in Headers */ = {isa = PBXBuildFile; fileRef = A9C96DCE1DDC20C20053187F /* MVKMTLBufferAllocation.h */; };
A9C96DD11DDC20C20053187F /* MVKMTLBufferAllocation.h in Headers */ = {isa = PBXBuildFile; fileRef = A9C96DCE1DDC20C20053187F /* MVKMTLBufferAllocation.h */; };
A9C96DD21DDC20C20053187F /* MVKMTLBufferAllocation.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9C96DCF1DDC20C20053187F /* MVKMTLBufferAllocation.mm */; };
Expand Down Expand Up @@ -670,6 +674,7 @@
A9B51BD2225E986A00AC74D2 /* MVKOSExtensions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKOSExtensions.mm; sourceTree = "<group>"; };
A9B51BD6225E986A00AC74D2 /* MVKOSExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKOSExtensions.h; sourceTree = "<group>"; };
A9B8EE0A1A98D796009C5A02 /* libMoltenVK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMoltenVK.a; sourceTree = BUILT_PRODUCTS_DIR; };
A9C327542AAF8A770025EE79 /* MVKConfigMembers.def */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = MVKConfigMembers.def; sourceTree = "<group>"; };
A9C83DCD24533E22003E5261 /* MVKCommandTypePools.def */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = MVKCommandTypePools.def; sourceTree = "<group>"; };
A9C86CB61C55B8350096CAF2 /* MoltenVKShaderConverter.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = MoltenVKShaderConverter.xcodeproj; path = ../MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj; sourceTree = "<group>"; };
A9C96DCE1DDC20C20053187F /* MVKMTLBufferAllocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKMTLBufferAllocation.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -843,6 +848,7 @@
4553AEF62251617100E8EBCD /* MVKBlockObserver.m */,
45557A5121C9EFF3008868BD /* MVKCodec.h */,
45557A4D21C9EFF3008868BD /* MVKCodec.mm */,
A9C327542AAF8A770025EE79 /* MVKConfigMembers.def */,
45557A5721CD83C3008868BD /* MVKDXTnCodec.def */,
A9A5E9C525C0822700E9085E /* MVKEnvironment.cpp */,
A98149431FB6A3F7005F00B4 /* MVKEnvironment.h */,
Expand Down Expand Up @@ -1008,6 +1014,7 @@
2FEA0A7824902F9F00EEF3AD /* MVKDeviceMemory.h in Headers */,
2FEA0A7924902F9F00EEF3AD /* MVKMTLResourceBindings.h in Headers */,
2FEA0A7A24902F9F00EEF3AD /* MVKExtensions.def in Headers */,
A9C327572AAFBD3A0025EE79 /* MVKConfigMembers.def in Headers */,
2FEA0A7B24902F9F00EEF3AD /* mvk_datatypes.hpp in Headers */,
2FEA0A7C24902F9F00EEF3AD /* MVKCommandEncodingPool.h in Headers */,
2FEA0A7D24902F9F00EEF3AD /* MVKResource.h in Headers */,
Expand Down Expand Up @@ -1070,6 +1077,7 @@
A94FB7C41C7DFB4800632CA3 /* MVKCmdRenderPass.h in Headers */,
A94FB7BC1C7DFB4800632CA3 /* MVKCmdPipeline.h in Headers */,
A9F3D9DC24732A4D00745190 /* MVKSmallVectorAllocator.h in Headers */,
A9C327562AAFBD390025EE79 /* MVKConfigMembers.def in Headers */,
A94FB7F81C7DFB4800632CA3 /* MVKPipeline.h in Headers */,
A94FB7F01C7DFB4800632CA3 /* MVKImage.h in Headers */,
4553AEFD2251617100E8EBCD /* MVKBlockObserver.h in Headers */,
Expand Down Expand Up @@ -1147,6 +1155,7 @@
A94FB7BD1C7DFB4800632CA3 /* MVKCmdPipeline.h in Headers */,
A9F3D9DD24732A4D00745190 /* MVKSmallVectorAllocator.h in Headers */,
A94FB7F91C7DFB4800632CA3 /* MVKPipeline.h in Headers */,
A9C327582AAFBD3A0025EE79 /* MVKConfigMembers.def in Headers */,
A94FB7F11C7DFB4800632CA3 /* MVKImage.h in Headers */,
4553AEFE2251617100E8EBCD /* MVKBlockObserver.h in Headers */,
A94FB7B91C7DFB4800632CA3 /* MVKCmdTransfer.h in Headers */,
Expand Down Expand Up @@ -1204,6 +1213,7 @@
DCFD7EFD2A45BC6E007BBBF7 /* MVKSync.h in Headers */,
DCFD7EFE2A45BC6E007BBBF7 /* MVKDevice.h in Headers */,
DCFD7EFF2A45BC6E007BBBF7 /* MVKSmallVector.h in Headers */,
A9C327592AAFBD3B0025EE79 /* MVKConfigMembers.def in Headers */,
DCFD7F002A45BC6E007BBBF7 /* MVKCommandPool.h in Headers */,
DCFD7F012A45BC6E007BBBF7 /* MVKShaderModule.h in Headers */,
DCFD7F022A45BC6E007BBBF7 /* MVKVulkanAPIObject.h in Headers */,
Expand Down
37 changes: 36 additions & 1 deletion MoltenVK/MoltenVK/API/mvk_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ typedef struct {
* and the changed value will immediately effect subsequent MoltenVK behaviour.
*
* The initial value or this parameter is set by the
* MVK_DEBUG
* MVK_CONFIG_DEBUG
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter is false if MoltenVK was
* built in Release mode, and true if MoltenVK was built in Debug mode.
Expand Down Expand Up @@ -919,13 +919,48 @@ typedef struct {
/**
* Maximize the concurrent executing compilation tasks.
*
* The value of this parameter must be changed before creating a VkInstance,
* for the change to take effect.
*
* The initial value or this parameter is set by the
* MVK_CONFIG_SHOULD_MAXIMIZE_CONCURRENT_COMPILATION
* runtime environment variable or MoltenVK compile-time build setting.
* This setting requires macOS 13.3 & is disabled by default.
*/
VkBool32 shouldMaximizeConcurrentCompilation;

/**
* This parameter is ignored on Apple Silicon devices.
*
* Non-Apple GPUs can have a dynamic timestamp period, which varies over time according to GPU
* workload. Depending on how often the app samples the VkPhysicalDeviceLimits::timestampPeriod
* value using vkGetPhysicalDeviceProperties(), the app may want up-to-date, but potentially
* volatile values, or it may find average values more useful.
*
* The value of this parameter sets the alpha (A) value of a simple lowpass filter
* on the timestampPeriod value, of the form:
*
* TPout = (1 - A)TPout + (A * TPin)
*
* The alpha value can be set to a float between 0.0 and 1.0. Values of alpha closer to
* 0.0 cause the value of timestampPeriod to vary slowly over time and be less volatile,
* and values of alpha closer to 1.0 cause the value of timestampPeriod to vary quickly
* and be more volatile.
*
* Apps that query the timestampPeriod value infrequently will prefer low volatility, whereas
* apps that query frequently may prefer higher volatility, to track more recent changes.
*
* The value of this parameter can be changed at any time, and will affect subsequent queries.
*
* The initial value or this parameter is set by the
* MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, this parameter is set to 0.05 by default,
* indicating that the timestampPeriod will vary relatively slowly,
* with the expectation that the app is querying this value infrequently.
*/
float timestampPeriodLowPassAlpha;

} MVKConfiguration;


Expand Down
2 changes: 1 addition & 1 deletion MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ class MVKPhysicalDevice : public MVKDispatchableVulkanAPIObject {
void initExtensions();
void initCounterSets();
bool needsCounterSetRetained();
void updateTimestampsAndPeriod();
void updateTimestampPeriod();
MVKArrayRef<MVKQueueFamily*> getQueueFamilies();
void initPipelineCacheUUID();
uint32_t getHighestGPUCapability();
Expand Down
16 changes: 8 additions & 8 deletions MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@
}

void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties* properties) {
updateTimestampsAndPeriod();
updateTimestampPeriod();
*properties = _properties;
}

Expand Down Expand Up @@ -1570,10 +1570,10 @@
// If needed, update the timestamp period for this device, using a crude lowpass filter to level out
// wild temporary changes, particularly during initial queries before much GPU activity has occurred.
// On Apple GPUs, CPU & GPU timestamps are the same, and timestamp period never changes.
void MVKPhysicalDevice::updateTimestampsAndPeriod() {
if (_properties.vendorID == kAppleVendorId) { return; }

if ([_mtlDevice respondsToSelector: @selector(sampleTimestamps:gpuTimestamp:)]) {
void MVKPhysicalDevice::updateTimestampPeriod() {
if (_properties.vendorID != kAppleVendorId &&
[_mtlDevice respondsToSelector: @selector(sampleTimestamps:gpuTimestamp:)]) {

MTLTimestamp earlierCPUTs = _prevCPUTimestamp;
MTLTimestamp earlierGPUTs = _prevGPUTimestamp;
[_mtlDevice sampleTimestamps: &_prevCPUTimestamp gpuTimestamp: &_prevGPUTimestamp];
Expand All @@ -1582,9 +1582,9 @@
if (elapsedCPUNanos && elapsedGPUTicks) { // Ensure not zero
float tsPeriod = elapsedCPUNanos / elapsedGPUTicks;

// Basic lowpass filter Y = (1 - a)Y + a*X.
// The lower a is, the slower Y will change over time.
static const float a = 0.05;
// Basic lowpass filter TPout = (1 - A)TPout + (A * TPin).
// The lower A is, the slower TPout will change over time.
float a = mvkConfig().timestampPeriodLowPassAlpha;
_properties.limits.timestampPeriod = ((1.0 - a) * _properties.limits.timestampPeriod) + (a * tsPeriod);
}
}
Expand Down
Loading

0 comments on commit 54dad69

Please sign in to comment.