//==============================================================================
// Copyright (c) 2015 Advanced Micro Devices, Inc. All rights reserved.
/// \author AMD Developer Tools Team
/// \file
/// \brief  This file is the main agent file for the HSA PMC module
//==============================================================================

#include <hsa_api_trace.h>

#include <cstdlib>
#include <iostream>

#include "Logger.h"
#include "FileUtils.h"
#include "GlobalSettings.h"

#include "HSAAgentUtils.h"

#include "HSAGPAProfiler.h"

#include "AutoGenerated/HSAPMCInterception.h"

#include "../CLOccupancyAgent/CLOccupancyInfoManager.h"

extern "C" DLL_PUBLIC void amdtCodeXLStopProfiling()
{
    HSAGPAProfiler::Instance()->EnableProfiling(false);
}

extern "C" DLL_PUBLIC void amdtCodeXLResumeProfiling()
{
    HSAGPAProfiler::Instance()->EnableProfiling(true);
}

void InitAgent()
{
    static bool isAgentInitialized = false;

    if (!isAgentInitialized)
    {
        isAgentInitialized = true;
#ifdef _DEBUG
        FileUtils::CheckForDebuggerAttach();
#endif

        std::string strLogFile = FileUtils::GetDefaultOutputPath() + "hsapmcagent.log";
        GPULogger::LogFileInitialize(strLogFile.c_str());

        Parameters params;
        FileUtils::GetParametersFromFile(params);

        GlobalSettings::GetInstance()->m_params = params;
   }
}

extern "C" bool DLL_PUBLIC OnLoad(void* pTable, uint64_t runtimeVersion, uint64_t failedToolCount, const char* const* pFailedToolNames)
{
    InitAgent();

    if (!CheckRuntimeToolsLibLoaded(runtimeVersion, failedToolCount, pFailedToolNames))
    {
        std::cout << RCP_PRODUCT_NAME " could not be enabled. Version mismatch between HSA runtime and " << HSA_RUNTIME_TOOLS_LIB << std::endl;
        return false;
    }

    std::cout << RCP_PRODUCT_NAME " " << RCP_VERSION_STRING << " is enabled\n";

    HsaApiTable* pHsaTable = reinterpret_cast<HsaApiTable*>(pTable);

    InitHSAAPIInterceptPMC(pHsaTable);

    if (GlobalSettings::GetInstance()->m_params.m_bKernelOccupancy)
    {
        std::string occupancyFile = GlobalSettings::GetInstance()->m_params.m_strOutputFile;
        size_t passStringPosition = occupancyFile.find("_pass");

        if (passStringPosition != std::string::npos)
        {
            //Remove the appended "_pass"" string and the extension
            occupancyFile = occupancyFile.substr(0, passStringPosition);
        }

        OccupancyInfoManager::Instance()->SetOutputFile(occupancyFile);
        OccupancyInfoEntry::m_cListSeparator = GlobalSettings::GetInstance()->m_params.m_cOutputSeparator;
    }

    std::string strError;

    if (!HSAGPAProfiler::Instance()->Init(GlobalSettings::GetInstance()->m_params, strError))
    {
        GPULogger::Log(GPULogger::logERROR, "Error loading HSA PMC Profiler. Error: %s\n", strError.c_str());
        return false;
    }

    return true;
}

extern "C" void DLL_PUBLIC OnUnload()
{
    // wait for all remaining sessions to end.
    // This is a safety net -- there shouldn't be any remaining sessions in well-behaved apps
    HSAGPAProfiler::Instance()->WaitForCompletedSessions();

    if (GlobalSettings::GetInstance()->m_params.m_bKernelOccupancy)
    {
        OccupancyInfoManager::Instance()->SaveToOccupancyFile();
    }

    DoneHSAAPIInterceptPMC();
}

extern "C" void DLL_PUBLIC OnLoadTool()
{
    InitAgent();
    // not needed, but rocprofiler library requires tool libraries to export OnLoadTool and OnUnloadTool
    GPULogger::Log(GPULogger::logMESSAGE, "HSAPMCAgent - OnLoadTool called\n");
}

extern "C" void DLL_PUBLIC OnUnloadTool()
{
    // not needed, but rocprofiler library requires tool libraries to export OnLoadTool and OnUnloadTool
    GPULogger::Log(GPULogger::logMESSAGE, "HSAPMCAgent - OnUnloadTool called\n");
}

