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/C/GPUTuning/SmartAccessMemory

Code

Copied!

//
// Copyright (c) 2021 - 2023 Advanced Micro Devices, Inc. All rights reserved.
//
//-------------------------------------------------------------------------------------------------


#include "SDK/ADLXHelper/Windows/C/ADLXHelper.h"
#include "SDK/Include/ISmartAccessMemory.h"
#include "SDK/Include/IGPUTuning1.h"

static HANDLE SAMEvent = NULL;

static adlx_bool ADLX_STD_CALL OnGPUTuningChanged(IADLXGPUTuningChangedListener* pGPUTuningChangedListener, IADLXGPUTuningChangedEvent* pGPUTuningChangedEvent)
{
    IADLXGPUTuningChangedEvent1* pGPUTuningChangedEvent1 = NULL;
    pGPUTuningChangedEvent->pVtbl->QueryInterface(pGPUTuningChangedEvent, IID_IADLXGPUTuningChangedEvent1(), &pGPUTuningChangedEvent1);
    adlx_bool SAMChange = pGPUTuningChangedEvent1->pVtbl->IsSmartAccessMemoryChanged(pGPUTuningChangedEvent1);
    if (SAMChange)
    {
        adlx_bool enabled = false, completed = false;
        pGPUTuningChangedEvent1->pVtbl->GetSmartAccessMemoryStatus(pGPUTuningChangedEvent1, &enabled, &completed);
        pGPUTuningChangedEvent1->pVtbl->Release(pGPUTuningChangedEvent1);
        pGPUTuningChangedEvent1 = NULL;
    }

    SetEvent(SAMEvent);
    return true;
}
static IADLXGPUTuningChangedListenerVtbl gpuTuningChangedVtable = { &OnGPUTuningChanged };
static IADLXGPUTuningChangedListener gpuTuningChangedListener = { &gpuTuningChangedVtable };

// Main menu
void MainMenu();

// Menu action control
void MenuControl(IADLXGPUTuningServices1* gpuTuningService1, IADLXGPUList* 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(IADLXGPUTuningServices1* gpuTuningService1, IADLXGPUList* gpus);

// Display AMD SmartAccess Memory support status on a GPU
void ShowSmartAccessMemorySupport(IADLXGPUTuningServices1* gpuTuningService1, IADLXGPUList* gpus);

// Display AMD SmartAccess Memory enabled status
void ShowSmartAccessMemoryState(IADLXGPUTuningServices1* gpuTuningService1, IADLXGPUList* gpus);

// Set AMD SmartAccess Memory state
void SetSmartAccessMemoryState(IADLXGPUTuningServices1* gpuTuningService1, IADLXGPUList* gpus);

int main ()
{
    ADLX_RESULT  res = ADLX_FAIL ;

    // Initialize ADLX
    res = ADLXHelper_Initialize();

    if (ADLX_SUCCEEDED  (res))
    {
        IADLXSystem* sys = ADLXHelper_GetSystemServices();
        IADLXGPUTuningServices* gpuTuningService = NULL;
        IADLXGPUTuningServices1* gpuTuningService1 = NULL;
        IADLXGPUTuningChangedHandling* gpuTuningHandling = NULL;
        IADLXGPUList* gpus = NULL;
        if (sys != NULL)
        {
            res = sys->pVtbl->GetGPUTuningServices (sys, &gpuTuningService);
            if (ADLX_SUCCEEDED (res))
            {
                // Get gpuTuningService1 via gpuTuningService::QueryInterface()
                res = gpuTuningService->pVtbl->QueryInterface(gpuTuningService, IID_IADLXGPUTuningServices1(), &gpuTuningService1);
                if (ADLX_SUCCEEDED (res))
                {

                    res = gpuTuningService1->pVtbl->GetGPUTuningChangedHandling(gpuTuningService1, &gpuTuningHandling);
                    if (ADLX_SUCCEEDED (res))
                    {
                        // Add listener
                        SAMEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
                        ADLX_RESULT  eventRes = gpuTuningHandling->pVtbl->AddGPUTuningEventListener(gpuTuningHandling, &gpuTuningChangedListener);

                        // Menu
                        res = sys->pVtbl->GetGPUs(sys, &gpus);
                        if (ADLX_SUCCEEDED (res))
                        {
                            // Display main menu options
                            MainMenu();

                            // Get and execute the choice
                            MenuControl(gpuTuningService1, gpus);
                        }
                        else
                            printf("Failed to get GPU list\n");

                        // Remove listener
                        if (ADLX_SUCCEEDED (eventRes))
                            eventRes = gpuTuningHandling->pVtbl->RemoveGPUTuningEventListener(gpuTuningHandling, &gpuTuningChangedListener);
                    }
                    else
                        printf("Failed to get GPU Tuning Changed Handling\n");
                }
                else
                    printf("Failed to get gpuTuningService1\n");
            }
            else
                printf("Failed to get gpuTuningService\n");
        }
        else
            printf("Failed to get systemService\n");
        // Free
        if (gpus != NULL)
        {
            gpus->pVtbl->Release(gpus);
            gpus = NULL;
        }
        if (gpuTuningHandling != NULL)
        {
            gpuTuningHandling->pVtbl->Release(gpuTuningHandling);
            gpuTuningHandling = NULL;
        }
        if (gpuTuningService1 != NULL)
        {
            gpuTuningService1->pVtbl->Release(gpuTuningService1);
            gpuTuningService1 = NULL;
        }
        if (gpuTuningService != NULL)
        {
            gpuTuningService->pVtbl->Release(gpuTuningService);
            gpuTuningService = NULL;
        }
    }
    else
        return WaitAndExit ("\tg_ADLXHelp initialize failed", 0);

    // Destroy ADLX
    res = ADLXHelper_Terminate();
    printf("Destroy ADLX res: %d\n", res);

    // Pause to see the print out
    system ("pause");

    return 0;
}

// Main menu
void MainMenu()
{
    printf("\tChoose from the following options:\n");

    printf("\t->Press 1 to display AMD SmartAccess Memory supported GPUs\n");
    printf("\t->Press 2 to display AMD SmartAccess Memory enabled status\n");
    printf("\t->Press 3 to set the AMD SmartAccess Memory state\n");
    printf("\t->Press Q/q to terminate the application\n");
    printf("\t->Press M/m to display main menu options\n");
}

// Menu action control
void MenuControl(IADLXGPUTuningServices1* gpuTuningService1, IADLXGPUList* 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 (NULL != msg)
        printf("%s\n", msg);

    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(IADLXGPUTuningServices1* gpuTuningService1, IADLXGPUList* gpus)
{
    adlx_uint supportedIndex= -1;
    IADLXGPU* oneGPU = NULL;
    IADLXSmartAccessMemory* smartAccessMemory = NULL;
    for (auto index = gpus->pVtbl->Begin(gpus); index != gpus->pVtbl->End(gpus); ++index)
    {
        ADLX_RESULT  res = gpus->pVtbl->At_GPUList(gpus, index, &oneGPU);
        if (ADLX_SUCCEEDED (res))
        {
            // Get the AMD SmartAccess Memory interface
            res = gpuTuningService1->pVtbl->GetSmartAccessMemory(gpuTuningService1, oneGPU, &smartAccessMemory);
            if (ADLX_SUCCEEDED (res))
            {
                adlx_bool supported = false;
                ADLX_RESULT  res = smartAccessMemory->pVtbl->IsSupported(smartAccessMemory, &supported);
                if (ADLX_SUCCEEDED (res) && supported)
                {
                    supportedIndex = index;
                    smartAccessMemory->pVtbl->Release(smartAccessMemory);
                    oneGPU->pVtbl->Release(oneGPU);
                    break;
                }
            }
        }
        if (smartAccessMemory != NULL)
        {
            smartAccessMemory->pVtbl->Release(smartAccessMemory);
            smartAccessMemory = NULL;
        }
        if (oneGPU != NULL)
        {
            oneGPU->pVtbl->Release(oneGPU);
            oneGPU = NULL;
        }
    }
    return supportedIndex;
}

// Display AMD SmartAccess Memory support status on a GPU
void ShowSmartAccessMemorySupport(IADLXGPUTuningServices1* gpuTuningService1, IADLXGPUList* gpus)
{
    auto index = GetGPUIndexSupportSAM(gpuTuningService1, gpus);
    if (index == -1)
        printf("All GPUs doesn't support AMD SmartAccess Memory\n");
    else
        printf("The %dth GPU support AMD SmartAccess Memory\n", (index + 1));
}

// Display AMD SmartAccess Memory enabled status
void ShowSmartAccessMemoryState(IADLXGPUTuningServices1* gpuTuningService1, IADLXGPUList* gpus)
{
    auto index = GetGPUIndexSupportSAM(gpuTuningService1, gpus);
    if (index == -1)
        printf("All GPUs doesn't support AMD SmartAccess Memory\n");
    else
    {
        IADLXGPU* oneGPU = NULL;
        IADLXSmartAccessMemory* smartAccessMemory = NULL;
        ADLX_RESULT  res = gpus->pVtbl->At_GPUList(gpus, index, &oneGPU);
        if (ADLX_SUCCEEDED (res))
        {
            res = gpuTuningService1->pVtbl->GetSmartAccessMemory(gpuTuningService1, oneGPU, &smartAccessMemory);
            if (ADLX_SUCCEEDED (res))
            {
                adlx_bool enabled = false;
                res = smartAccessMemory->pVtbl->IsEnabled(smartAccessMemory, &enabled);
                if (ADLX_SUCCEEDED (res))
                    printf("The AMD SmartAccess Memory is %s on the %dth GPU\n", (enabled ? "enabled" : "disabled"), (index + 1));
                else
                    printf("Call IsEnabled() failed\n");
            }
            else
                printf("Failed to get smartAccessMemory\n");
        }
        else
            printf("Failed to get the GPU\n");

        if (smartAccessMemory != NULL)
        {
            smartAccessMemory->pVtbl->Release(smartAccessMemory);
            smartAccessMemory = NULL;
        }
        if (oneGPU != NULL)
        {
            oneGPU->pVtbl->Release(oneGPU);
            oneGPU = NULL;
        }
    }
}

// Set AMD SmartAccess Memory state
void SetSmartAccessMemoryState(IADLXGPUTuningServices1* gpuTuningService1, IADLXGPUList* gpus)
{
    auto index = GetGPUIndexSupportSAM(gpuTuningService1, gpus);
    if (index == -1)
        printf("All GPUs doesn't support AMD SmartAccess Memory\n");
    else
    {
        IADLXGPU* oneGPU = NULL;
        IADLXSmartAccessMemory* smartAccessMemory = NULL;
        ADLX_RESULT  res = gpus->pVtbl->At_GPUList(gpus, index, &oneGPU);
        if (ADLX_SUCCEEDED (res))
        {
            res = gpuTuningService1->pVtbl->GetSmartAccessMemory(gpuTuningService1, oneGPU, &smartAccessMemory);
            if (ADLX_SUCCEEDED (res))
            {
                adlx_bool enabled = false;
                res = smartAccessMemory->pVtbl->IsEnabled(smartAccessMemory, &enabled);
                if (ADLX_SUCCEEDED (res))
                    printf("Currently AMD SmartAccess Memory is %s on %dth GPU\n", (enabled ? "enabled" : "disabled"), (index + 1));
                else
                    printf("Call IsEnabled() failed\n");
                res = smartAccessMemory->pVtbl->SetEnabled(smartAccessMemory, !enabled);
                if (ADLX_SUCCEEDED (res))
                    printf("Set AMD SmartAccess Memory to %s for %dth GPU\n", (!enabled ? "enabled" : "disabled"), (index + 1));
                else
                    printf("Call SetEnabled() failed\n");

                // 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->pVtbl->IsEnabled(smartAccessMemory, &enabled);
                if (ADLX_SUCCEEDED (res))
                    printf("After setting, AMD SmartAccess Memory is %s on %dth GPU\n", (enabled ? "enabled" : "disabled"), (index + 1));
                else
                    printf("Call IsEnabled() failed\n");
            }
            else
                printf("Failed to get smartAccessMemory\n");
        }
        else
            printf("Failed to get the GPU\n");

        if (smartAccessMemory != NULL)
        {
            smartAccessMemory->pVtbl->Release(smartAccessMemory);
            smartAccessMemory = NULL;
        }
        if (oneGPU != NULL)
        {
            oneGPU->pVtbl->Release(oneGPU);
            oneGPU = NULL;
        }
    }
}