/******************************************************************************* * * MIT License * * Copyright (C) 2023-2026 Advanced Micro Devices, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * *******************************************************************************/ #include // hiptensor includes #include "include/platform.hpp" #include "logger.hpp" #include "util.hpp" #include #include #include #include "common.hpp" void printBool(bool in) { std::cout << (in ? "PASSED" : "FAILED") << std::endl; } bool loggerSingletonTest() { auto& loggerInit = hiptensor::Logger::instance(); auto& logger = hiptensor::Logger::instance(); return (loggerInit == logger); } bool hiptensorLoggerSetCallbackTest() { static bool checkEntry = false; auto callBackFunc = [](int32_t logContext, const char* funcName, const char* msg) { checkEntry = ((logContext == static_cast(hiptensor::Logger::LogLevel_t::LOG_LEVEL_API_TRACE)) && !strcmp(funcName, "TestFunction") && (strstr(msg, "TestMessage") != NULL)); }; if(hiptensorLoggerSetCallback(callBackFunc) != HIPTENSOR_STATUS_SUCCESS) { return false; } using hiptensor::Logger; auto& logger = Logger::instance(); if(logger->logAPITrace("TestFunction", "TestMessage") != hiptensor::Logger::Status_t::SUCCESS || checkEntry == false) { return false; } if(hiptensorLoggerSetCallback(nullptr) != HIPTENSOR_STATUS_SUCCESS) { return false; } return true; } bool hiptensorLoggerSetFileTest() { std::string fname = hiptensor::test::generateTempFilename(); // hiptensorLoggerSetFile should have filestream open in write mode. FILE* fp = hiptensor::test::safeFopen(fname.c_str(), "r"); if(hiptensorLoggerSetFile(fp) == HIPTENSOR_STATUS_SUCCESS) { return false; } long fileSizeOrig = 0, fileSizeAfter = 0; // hiptensorLoggerSetFile with file in write mode. fp = hiptensor::test::safeFopen(fname.c_str(), "w"); if(fp == NULL) { std::cout << " Failed to Open File. Check Permissions!"; return false; } else { fseek(fp, 0, SEEK_END); fileSizeOrig = ftell(fp); fseek(fp, 0, SEEK_SET); } //Only Sets Filestream to fp. Doesn't write logs yet. if(hiptensorLoggerSetFile(fp) != HIPTENSOR_STATUS_SUCCESS) { return false; } //Call API again to write logs to fp if(hiptensorLoggerSetFile(fp) != HIPTENSOR_STATUS_SUCCESS) { return false; } //Check size after API call fseek(fp, 0, SEEK_END); fileSizeAfter = ftell(fp); // Redirect the logger away from fp before closing it. The logger holds mWriteStream = fp // with mOwnsStream = false (caller-owned), so it will not close fp itself. If we close fp // first, any subsequent logAPITrace call (e.g. at the start of the next test) would // fprintf to a dangling pointer, causing intermittent heap corruption on Linux. hiptensorLoggerSetFile(stdout); fclose(fp); std::remove(fname.c_str()); if(fileSizeAfter <= fileSizeOrig) { return false; } return true; } bool hiptensorLoggerOpenFileTest() { std::string fname = hiptensor::test::generateTempFilename(); const char* fname_c = fname.c_str(); // Create the file to verify write permissions, then close it immediately. // On Windows, fopen("w") holds an exclusive lock; we must not keep it open // while calling hiptensorLoggerOpenFile, which opens the same path internally. { FILE* fp = hiptensor::test::safeFopen(fname_c, "w"); if(fp == NULL) { std::cout << " Failed to Open File. Check Permissions!"; return false; } fclose(fp); } // Switch the logger's write stream to fname_c. if(hiptensorLoggerOpenFile(fname_c) != HIPTENSOR_STATUS_SUCCESS) { std::remove(fname.c_str()); return false; } // Trigger a log write to fname_c via a public API call. hiptensorLoggerSetCallback(nullptr); // Redirect the logger to stdout; this closes (and flushes) the logger's handle to fname_c, // ensuring all buffered content is written before we read the file size. hiptensorLoggerSetFile(stdout); // Verify that something was written to fname_c. long fileSize = 0; FILE* fp = hiptensor::test::safeFopen(fname_c, "r"); if(fp != NULL) { fseek(fp, 0, SEEK_END); fileSize = ftell(fp); fclose(fp); } std::remove(fname.c_str()); return fileSize > 0; } bool hiptensorLoggerSetLevelTest() { // Test all log levels enumerated in hiptensorLogLevel_t if(hiptensorLoggerSetLevel(HIPTENSOR_LOG_LEVEL_OFF) != HIPTENSOR_STATUS_SUCCESS) { return false; } if(hiptensorLoggerSetLevel(HIPTENSOR_LOG_LEVEL_ERROR) != HIPTENSOR_STATUS_SUCCESS) { return false; } if(hiptensorLoggerSetLevel(HIPTENSOR_LOG_LEVEL_PERF_TRACE) != HIPTENSOR_STATUS_SUCCESS) { return false; } if(hiptensorLoggerSetLevel(HIPTENSOR_LOG_LEVEL_PERF_HINT) != HIPTENSOR_STATUS_SUCCESS) { return false; } if(hiptensorLoggerSetLevel(HIPTENSOR_LOG_LEVEL_HEURISTICS_TRACE) != HIPTENSOR_STATUS_SUCCESS) { return false; } if(hiptensorLoggerSetLevel(HIPTENSOR_LOG_LEVEL_API_TRACE) != HIPTENSOR_STATUS_SUCCESS) { return false; } // Test out-of-range input value if(hiptensorLoggerSetLevel(hiptensorLogLevel_t(3)) == HIPTENSOR_STATUS_SUCCESS) { return false; } return true; } bool hiptensorLoggerSetMaskTest() { // Test all bitmask values in range for(int i = 0x00; i <= 0x1F; i++) { if(hiptensorLoggerSetMask(i) != HIPTENSOR_STATUS_SUCCESS) { return false; } } // Test out-of-range input value if(hiptensorLoggerSetMask(0x20) == HIPTENSOR_STATUS_SUCCESS) { return false; } return true; } bool hiptensorLoggerForceDisableTest() { if(hiptensorLoggerForceDisable() != HIPTENSOR_STATUS_SUCCESS) { return false; } return true; } int main(int argc, char* argv[]) { bool totalPass = true; bool testPass = false; const char* logFile = "test.log"; hiptensorLoggerOpenFile(logFile); hiptensorLoggerSetLevel(HIPTENSOR_LOG_LEVEL_API_TRACE); testPass = loggerSingletonTest(); totalPass &= testPass; std::cout << "Logger Singleton: "; printBool(testPass); testPass = hiptensorLoggerSetCallbackTest(); totalPass &= testPass; std::cout << "hiptensorLoggerSetCallback: "; printBool(testPass); testPass = hiptensorLoggerSetFileTest(); totalPass &= testPass; std::cout << "hiptensorLoggerSetFile: "; printBool(testPass); testPass = hiptensorLoggerOpenFileTest(); totalPass &= testPass; std::cout << "hiptensorLoggerOpenFile: "; printBool(testPass); //As the above function call sets to a temporary file, need to call OpenFile again. hiptensorLoggerOpenFile(logFile); testPass = hiptensorLoggerSetLevelTest(); totalPass &= testPass; std::cout << "hiptensorLoggerSetLevel: "; printBool(testPass); testPass = hiptensorLoggerSetMaskTest(); totalPass &= testPass; std::cout << "hiptensorLoggerSetMask: "; printBool(testPass); // This test must be performed last as hiptensorLoggerForceDisable() cannot be undone testPass = hiptensorLoggerForceDisableTest(); totalPass &= testPass; std::cout << "hiptensorLoggerForceDisableTest: "; printBool(testPass); // Redirect the logger away from test.log before deleting it. // On Windows, a file cannot be removed while it is open. // hiptensorLoggerSetFile calls fclose() on the current stream (mOwnsStream=true), // which releases the file handle regardless of whether the logger is force-disabled. hiptensorLoggerSetFile(stdout); std::remove(logFile); if(!totalPass) return -1; return 0; }