SmartAccessMemory
Demonstrates how to control AMD SmartAccess Memory when programming with ADLX.
Command Prompts
Command Prompt | Description |
---|---|
1 | Display AMD SmartAccess Memory support status on a GPU. |
2 | Display AMD SmartAccess Memory enabled status. |
3 | Set AMD SmartAccess Memory state. |
M/m | Show this menu. |
Q/q | Quit. |
Sample Path
/Samples/CPP/GPUTuning/SmartAccessMemory
Code
//
// Copyright (c) 2021 - 2024 Advanced Micro Devices, Inc. All rights reserved.
//
//-------------------------------------------------------------------------------------------------
#include "SDK/ADLXHelper/Windows/Cpp/ADLXHelper.h"
#include "SDK/Include/ISmartAccessMemory.h"
#include "SDK/Include/IGPUTuning1.h"
#include <iostream>
// Use ADLX namespace
using namespace adlx;
// ADLXHelper instance
// No outstanding interfaces from ADLX must exist when ADLX is destroyed.
// Use global variables to ensure validity of the interface.
static ADLXHelper g_ADLXHelp;
static HANDLE SAMEvent = nullptr;
class GPUTuningChangedListener : public IADLXGPUTuningChangedListener
{
public:
bool ADLX_STD_CALL OnGPUTuningChanged(IADLXGPUTuningChangedEvent* pGPUTuningChangedEvent)
{
IADLXGPUTuningChangedEvent1Ptr pGPUTuningChangedEvent1 = IADLXGPUTuningChangedEvent1Ptr(pGPUTuningChangedEvent);
adlx_bool SAMChange = pGPUTuningChangedEvent1->IsSmartAccessMemoryChanged();
if (SAMChange)
{
adlx_bool enabled = false, completed = false;
pGPUTuningChangedEvent1->GetSmartAccessMemoryStatus(&enabled, &completed);
}
SetEvent(SAMEvent);
return true;
}
};
// Main menu
void MainMenu();
// Menu action control
void MenuControl(IADLXGPUTuningServices1Ptr gpuTuningService1, IADLXGPUListPtr gpus);
// Wait for exit with error message
int WaitAndExit(const char* msg, const int retCode);
// Find the first GPU index that supports AMD SmartAccess Memory. Return -1 if all GPUs are not supported
adlx_uint GetGPUIndexSupportSAM(IADLXGPUTuningServices1Ptr gpuTuningService1, IADLXGPUListPtr gpus);
// Display AMD SmartAccess Memory support status on a GPU
void ShowSmartAccessMemorySupport(IADLXGPUTuningServices1Ptr gpuTuningService1, IADLXGPUListPtr gpus);
// Display AMD SmartAccess Memory enabled status
void ShowSmartAccessMemoryState(IADLXGPUTuningServices1Ptr gpuTuningService1, IADLXGPUListPtr gpus);
// Set AMD SmartAccess Memory state
void SetSmartAccessMemoryState(IADLXGPUTuningServices1Ptr gpuTuningService1, IADLXGPUListPtr gpus);
int main()
{
ADLX_RESULT res = ADLX_FAIL ;
// Initialize ADLX
res = g_ADLXHelp.Initialize();
if (ADLX_SUCCEEDED (res))
{
IADLXGPUTuningServicesPtr gpuTuningService;
res = g_ADLXHelp.GetSystemServices()->GetGPUTuningServices(&gpuTuningService);
if (ADLX_SUCCEEDED (res))
{
// Get gpuTuningService1 via gpuTuningService::QueryInterface()
IADLXGPUTuningServices1Ptr gpuTuningService1;
res = gpuTuningService->QueryInterface(gpuTuningService1->IID(), reinterpret_cast<void**>(&gpuTuningService1));
if (ADLX_SUCCEEDED (res))
{
IADLXGPUTuningChangedHandlingPtr gpuTuningHandling;
res = gpuTuningService1->GetGPUTuningChangedHandling(&gpuTuningHandling);
if (ADLX_SUCCEEDED (res))
{
// Add listener
SAMEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
static GPUTuningChangedListener listener;
ADLX_RESULT eventRes = gpuTuningHandling->AddGPUTuningEventListener(&listener);
// Menu
IADLXGPUListPtr gpus;
res = g_ADLXHelp.GetSystemServices()->GetGPUs(&gpus);
if (ADLX_SUCCEEDED (res))
{
// Display main menu options
MainMenu();
// Get and execute the choice
MenuControl(gpuTuningService1, gpus);
}
else
std::cout << "Failed to get GPU list" << std::endl;
// Remove listener
if (ADLX_SUCCEEDED (eventRes))
eventRes = gpuTuningHandling->RemoveGPUTuningEventListener(&listener);
}
else
std::cout << "Failed to get GPU Tuning Changed Handling" << std::endl;
}
else
std::cout << "Failed to get gpuTuningService1" << std::endl;
}
else
std::cout << "Failed to get gpuTuningService" << std::endl;
}
else
return WaitAndExit("\\tg_ADLXHelp initialize failed", 0);
// Destroy ADLX
res = g_ADLXHelp.Terminate();
std::cout << "Destroy ADLX res: " << res << std::endl;
// Pause to see the print out
system("pause");
return 0;
}
// Main menu
void MainMenu()
{
std::cout << "\\tChoose from the following options:" << std::endl;
std::cout << "\\t->Press 1 to display AMD SmartAccess Memory supported GPUs" << std::endl;
std::cout << "\\t->Press 2 to display AMD SmartAccess Memory enabled status" << std::endl;
std::cout << "\\t->Press 3 to set the AMD SmartAccess Memory state" << std::endl;
std::cout << "\\t->Press Q/q to terminate the application" << std::endl;
std::cout << "\\t->Press M/m to display main menu options" << std::endl;
}
// Menu action control
void MenuControl(IADLXGPUTuningServices1Ptr gpuTuningService1, IADLXGPUListPtr gpus)
{
int num = 0;
while ((num = getchar()) != 'q' && num != 'Q')
{
switch (num)
{
// Display AMD SmartAccess Memory support status on a GPU
case '1':
ShowSmartAccessMemorySupport(gpuTuningService1, gpus);
break;
// Display AMD SmartAccess Memory enabled status
case '2':
ShowSmartAccessMemoryState(gpuTuningService1, gpus);
break;
// Set AMD SmartAccess Memory state
case '3':
SetSmartAccessMemoryState(gpuTuningService1, gpus);
break;
// Display menu options
case 'm':
case 'M':
MainMenu();
break;
default:
break;
}
}
}
// Wait for exit with error message
int WaitAndExit(const char* msg, const int retCode)
{
// Printout the message and pause to see it before returning the desired code
if (nullptr != msg)
std::cout << msg << std::endl;
system("pause");
return retCode;
}
// Find the first GPU index that supports AMD SmartAccess Memory. Return -1 if all GPUs are not supported
adlx_uint GetGPUIndexSupportSAM(IADLXGPUTuningServices1Ptr gpuTuningService1, IADLXGPUListPtr gpus)
{
adlx_uint supportedIndex = -1;
IADLXGPUPtr oneGPU;
IADLXSmartAccessMemoryPtr smartAccessMemory;
for (auto index = gpus->Begin(); index != gpus->End(); ++index)
{
ADLX_RESULT res = gpus->At(index, &oneGPU);
if (ADLX_SUCCEEDED (res))
{
// Get the AMD SmartAccess Memory interface
res = gpuTuningService1->GetSmartAccessMemory(oneGPU, &smartAccessMemory);
if (ADLX_SUCCEEDED (res))
{
adlx_bool supported = false;
ADLX_RESULT res = smartAccessMemory->IsSupported(&supported);
if (ADLX_SUCCEEDED (res) && supported)
{
supportedIndex = index;
break;
}
}
}
}
return supportedIndex;
}
// Display AMD SmartAccess Memory support status on a GPU
void ShowSmartAccessMemorySupport(IADLXGPUTuningServices1Ptr gpuTuningService1, IADLXGPUListPtr gpus)
{
auto index = GetGPUIndexSupportSAM(gpuTuningService1, gpus);
if (index == -1)
std::cout << "All GPUs doesn't support AMD SmartAccess Memory" << std::endl;
else
std::cout << "The " << (index + 1) << "th GPU support AMD SmartAccess Memory" << std::endl;
}
// Display AMD SmartAccess Memory enabled status
void ShowSmartAccessMemoryState(IADLXGPUTuningServices1Ptr gpuTuningService1, IADLXGPUListPtr gpus)
{
auto index = GetGPUIndexSupportSAM(gpuTuningService1, gpus);
if (index == -1)
std::cout << "All GPUs doesn't support AMD SmartAccess Memory" << std::endl;
else
{
IADLXGPUPtr oneGPU;
ADLX_RESULT res = gpus->At(index, &oneGPU);
if (ADLX_SUCCEEDED (res))
{
IADLXSmartAccessMemoryPtr smartAccessMemory;
res = gpuTuningService1->GetSmartAccessMemory(oneGPU, &smartAccessMemory);
if (ADLX_SUCCEEDED (res))
{
adlx_bool enabled = false;
res = smartAccessMemory->IsEnabled(&enabled);
if (ADLX_SUCCEEDED (res))
std::cout << "The AMD SmartAccess Memory is " << (enabled ? "enabled" : "disabled") << " on the " << (index + 1) << "th GPU" << std::endl;
else
std::cout << "Call IsEnabled() failed" << std::endl;
}
else
std::cout << "Failed to get smartAccessMemory" << std::endl;
}
else
std::cout << "Failed to get the GPU" << std::endl;
}
}
// Set AMD SmartAccess Memory state
void SetSmartAccessMemoryState(IADLXGPUTuningServices1Ptr gpuTuningService1, IADLXGPUListPtr gpus)
{
auto index = GetGPUIndexSupportSAM(gpuTuningService1, gpus);
if (index == -1)
std::cout << "All GPUs doesn't support AMD SmartAccess Memory" << std::endl;
else
{
IADLXGPUPtr oneGPU;
ADLX_RESULT res = gpus->At(index, &oneGPU);
if (ADLX_SUCCEEDED (res))
{
IADLXSmartAccessMemoryPtr smartAccessMemory;
res = gpuTuningService1->GetSmartAccessMemory(oneGPU, &smartAccessMemory);
if (ADLX_SUCCEEDED (res))
{
adlx_bool enabled = false;
res = smartAccessMemory->IsEnabled(&enabled);
if (ADLX_SUCCEEDED (res))
std::cout << "Currently AMD SmartAccess Memory is " << (enabled ? "enabled" : "disabled") << " on " << (index + 1) << "th GPU" << std::endl;
else
std::cout << "Call IsEnabled() failed" << std::endl;
res = smartAccessMemory->SetEnabled(!enabled);
if (ADLX_SUCCEEDED (res))
std::cout << "Set AMD SmartAccess Memory to " << (!enabled ? "enabled" : "disabled") << " for " << (index + 1) << "th GPU" << std::endl;
else
std::cout << "Call SetEnabled() failed" << std::endl;
// First event received quickly before SAM start
WaitForSingleObject(SAMEvent, 2000);
// When receive the first event, avoid calling any other ADLX method, and if any UI application is running, we must close it to avoid crashing
// Close(application)......
// Second event received after SAM completed, the maximum consuming time less than 20 seconds.
WaitForSingleObject(SAMEvent, 20000);
// Now SAM completed, we can restart the UI application, and continue to call ADLX function
// Start(application)......
res = smartAccessMemory->IsEnabled(&enabled);
if (ADLX_SUCCEEDED (res))
std::cout << "After setting, AMD SmartAccess Memory is " << (enabled ? "enabled" : "disabled") << " on " << (index + 1) << "th GPU" << std::endl;
else
std::cout << "Call IsEnabled() failed" << std::endl;
}
else
std::cout << "Failed to get smartAccessMemory" << std::endl;
}
else
std::cout << "Failed to get the GPU" << std::endl;
}
}