Files
TheRock/rocm-systems/projects/clr/opencl/tests/ocltst/env/ocltst.cpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

1561 lines
47 KiB
C++

/*
* Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
*
* SPDX-License-Identifier: MIT
*/
/////////////////////////////////////////////////////////////////////////////
#include <CL/cl.h>
#ifdef _WIN32
#include <windows.h>
#include "Window.h"
typedef HMODULE ModuleHandle;
#endif
/////////////////////////////////////////////////////////////////////////////
#ifdef __linux__
#include <dlfcn.h>
typedef void* ModuleHandle;
#endif
/////////////////////////////////////////////////////////////////////////////
#include "BaseTestImp.h"
#include "Module.h"
#include "OCLLog.h"
#include "OCLTest.h"
#include "OCLTestImp.h"
#include "OCLTestList.h"
#include "OCLWrapper.h"
#include "Timer.h"
#include "Worker.h"
#include "getopt.h"
#include "oclsysinfo.h"
#include "pfm.h"
//! Including OCLutilities Thread utility
#include "OCL/Thread.h"
//! Lock that needs to be obtained to access the global
//! module variable
static OCLutil::Lock moduleLock;
#include <assert.h>
#include <stdio.h>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
/////////////////////////////////////////////////////////////////////////////
#ifdef _WIN32
static LONG WINAPI xFilter(LPEXCEPTION_POINTERS xEP);
void serviceStubCall();
#endif
#define MAX_DEVICES 16
#undef CHECK_RESULT
#define CHECK_RESULT(test, msg) \
if ((test)) { \
printf("\n%s\n", msg); \
exit(1); \
}
//! Declaration of a function that find devices of a specific type for the
//! chosen platform
int findAdapters(unsigned int platformIdx, bool useCPU, cl_platform_id*);
//! class App that is used to run the tests on the system
class App {
public:
static bool m_reRunFailed;
static const char* m_svcMsg;
//! Constructor for App
App(unsigned int platform)
: m_list(false),
m_console(true),
m_useCPU(false),
m_dump(false),
m_perflab(false),
m_noSysInfoPrint(false),
m_numItr(1),
mp_testOrder(NULL),
m_rndOrder(false),
m_spawned(0),
m_threads(1),
m_runthread(0),
m_width(512),
m_height(512),
m_window(0),
m_platform(platform) {
// initialize OCLWrapper reference
// m_workers = Set of worker objects that are used to run a subtest from a
// module
for (unsigned int i = 0; i < 256; i++) m_workers[i] = 0;
// Setting the number of devices
/*
* Force caltst to use 1 thread at a time in Windows
* only contextual calls are thread safe currently
*/
m_numDevices = findAdapters(m_platform, m_useCPU, &mpform_id);
m_wrapper = new OCLWrapper(mpform_id);
// m_numDevices = 1;
// Report structure used to store the results of the tests
#if 0
testReport = (Report **)malloc(sizeof(Report *) * m_numDevices);
for(unsigned int i = 0; i < m_numDevices; i++)
{
testReport[i] = new Report;
}
#else
testReport = (Report**)malloc(sizeof(Report*));
testReport[0] = new Report;
#endif
}
//! Destructor for App
~App() {
// Deleting the Worker objects
for (unsigned int i = 0; i < 256; i++) {
if (m_workers[i]) {
delete m_workers[i];
m_workers[i] = 0;
}
}
// Deleting the report structures
// for(unsigned int i = 0; i < m_numDevices; i++)
for (unsigned int i = 0; i < 1; i++) {
delete testReport[i];
}
free(testReport);
m_wrapper->clUnloadPlatformAMD(mpform_id);
delete m_wrapper;
}
//! Function used to create a worker object corresponding to a subtest in a
//! module
void SetWorker(unsigned int index, OCLWrapper* wrapper, Module* module, TestMethod run,
unsigned int id, unsigned int subtest, unsigned int test, bool dump, bool view,
bool useCPU, void* window, unsigned int x, unsigned int y, bool perflab,
unsigned int deviceId, unsigned int platform) {
if (index >= 256) return;
if (m_workers[index]) delete m_workers[index];
m_workers[index] = new Worker(wrapper, module, run, id, subtest, test, dump, view, useCPU,
window, x, y, perflab, deviceId, platform);
assert(m_workers[index] != 0);
// oclTestLog(OCLTEST_LOG_ALWAYS, "Worker Device Id = %d\n",
// m_workers[index]->getDeviceId());
}
//! Function to return the 'index'th m_workers
Worker* GetWorker(unsigned int index) {
if (index >= 256) return 0;
return m_workers[index];
}
//! Create a thread to run the subtest
void AddThread(unsigned int workerindex, unsigned int usage) {
Worker* worker = GetWorker(workerindex);
if (worker == 0) {
return;
}
// usage = Whether to use threads or not
if (usage != 0) {
// Creating a thread
// getTestMethod = runSubTest here
// which takes a Worker object as an argument
m_pool[workerindex].create(worker->getTestMethod(), (void*)(worker));
m_spawned++;
} else {
// Same as above without using threads
TestMethod run = worker->getTestMethod();
if (run) {
run(worker);
UpdateTestReport(workerindex, worker->getResult());
}
}
return;
}
//! Function which waits for all threads to execute and also updates the
//! report
void WaitAllThreads() {
for (unsigned int w = 0; w < m_spawned; w++) {
m_pool[w].join();
UpdateTestReport(w, m_workers[w]->getResult());
}
m_spawned = 0;
}
//! Function to add a worker thread so as to run a subtest of a module
//! @param run = runSubtest function
//! @param index = index of the module in m_modules
//! @param subtest = the subtest number to run
//! @param usage = whether to use threads or not
//! @param test = The test in the module to be executed
void AddWorkerThread(unsigned int index, unsigned int subtest, unsigned int test,
unsigned int usage, TestMethod run) {
if (m_spawned > m_threads) {
WaitAllThreads();
}
// Creating a worker thread for each device
#if 0
for(unsigned int i = 0; i < m_numDevices; i++)
{
SetWorker(i,
m_wrapper,
&m_modules[index],
run,
m_spawned,
subtest,
test,
m_dump,
!m_console,
m_useCPU,
m_window,
m_width,
m_height,
m_perflab,
i,
m_platform);
}
#else
for (unsigned int i = 0; i < 1; i++) {
SetWorker(i, m_wrapper, &m_modules[index], run, m_spawned, subtest, test, m_dump, !m_console,
m_useCPU, m_window, m_width, m_height, m_perflab, m_deviceId, m_platform);
}
#endif
// Creating and executing a thread for each device
// for(unsigned int i = 0; i < m_numDevices; i++)
for (unsigned int i = 0; i < 1; i++) {
AddThread(i, usage);
}
}
void printOCLinfo(void);
//! Function to process the commandline arguments
void CommandLine(unsigned int argc, char** argv);
//! Function to scan for the different tests in the module
void ScanForTests();
//! Function to run all the specified tests.
//! \return true if all requested tests are executed and pass successfully;
//! false if any test fails, if no tests are executed, or when
//! running in list-only mode.
bool RunAllTests();
//! Free memory
void CleanUp();
//! Function to set the order in which test are executed.
void SetTestRunOrder(int);
//! Function to print the test order
void PrintTestOrder(int);
//! Function to get the number of iterations.
int GetNumItr(void) { return m_numItr; }
private:
typedef std::vector<unsigned int> TestIndexList;
typedef std::vector<std::string> StringList;
void AddToList(StringList& strlist, const char* str);
void LoadList(StringList& strlist, const char* filename);
bool TestInList(StringList& strlist, const char* testname);
//! Array storing the report for each device
Report** testReport;
//! Function to update the result of each device
void UpdateTestReport(int index, TestResult* result) {
if (result != NULL) {
if (result->passed) {
if (testReport[index]->max->value < result->value) {
testReport[index]->max->value = result->value;
testReport[index]->max->resultString = result->resultString;
}
if (testReport[index]->min->value > result->value) {
testReport[index]->min->value = result->value;
testReport[index]->min->resultString = result->resultString;
}
} else {
testReport[index]->numFailedTests++;
testReport[index]->success = false;
}
} else {
testReport[index]->numFailedTests++;
testReport[index]->success = false;
}
}
//! Functions used to find the range of the tests to be run
void GetTestIndexList(TestIndexList& testIndices, StringList& testList,
const char* szModuleTestname, int maxIndex);
void PruneTestIndexList(TestIndexList& testIndices, TestIndexList& avoidIndices,
TestIndexList& erasedIndices);
StringList m_paths;
StringList m_tests;
StringList m_avoid;
std::vector<Module> m_modules;
bool m_list;
bool m_console;
bool m_useCPU;
bool m_dump;
bool m_perflab;
bool m_noSysInfoPrint;
int m_numItr;
int* mp_testOrder;
bool m_rndOrder;
//! m_pool = Various threads created to execute tests on multiple devices
OCLutil::Thread m_pool[256];
Worker* m_workers[256];
//! Number of threads spawned
unsigned int m_spawned;
//! Upper limit on the number of threads that can be spawned
unsigned int m_threads;
unsigned int m_runthread;
unsigned int m_width;
unsigned int m_height;
void* m_window;
//! which index/platform id from the platforms vector returned by
//! cl::Platform::get we should run on
unsigned int m_platform;
cl_platform_id mpform_id;
//! Number of devices on the system
unsigned int m_numDevices;
//
//! Device ID to use on the system
unsigned int m_deviceId;
// OCLWrapper reference
OCLWrapper* m_wrapper;
};
void App::printOCLinfo(void) {
std::string calinfo;
if (!m_noSysInfoPrint) {
oclSysInfo(calinfo, m_useCPU, m_deviceId, m_platform);
oclTestLog(OCLTEST_LOG_ALWAYS, calinfo.c_str());
}
}
/*-----------------------------------------------------
Function to randomize the order in which tests are executed
-------------------------------------------------------*/
#ifdef _WIN32
#include <time.h>
#endif
// void App::SetTestRunOrder(int test_count)
void App::SetTestRunOrder(int mod_index) {
assert(mp_testOrder != NULL);
unsigned int test_count = m_modules[mod_index].get_count();
StringList uniqueTests;
for (unsigned int i = 0; i < m_tests.size(); ++i) {
// see if the tests are being run using indices
size_t nFirstBracket = m_tests[i].find("[");
// set the test name
std::string szTestName = m_tests[i];
// order of execution is set based on base name so get the base name
if (nFirstBracket != std::string::npos) szTestName = szTestName.substr(0, nFirstBracket);
bool bTestExists = false;
for (unsigned int j = 0; j < uniqueTests.size(); ++j) {
if (strcmp(szTestName.c_str(), uniqueTests[j].c_str()) == 0) {
bTestExists = true;
break;
}
}
if (!bTestExists) {
AddToList(uniqueTests, szTestName.c_str());
}
}
for (unsigned int i = 0; i < test_count && i < uniqueTests.size(); i++) {
for (unsigned int j = 0; j < test_count; j++) {
unsigned int index = i;
// add all the prev test indices
for (int k = 0; k < mod_index; k++) index += m_modules[k].get_count();
std::string szTestName = uniqueTests[index];
if (strcmp(szTestName.c_str(), m_modules[mod_index].get_name(j)) == 0) {
mp_testOrder[i] = j;
break;
}
}
}
if (m_rndOrder) {
srand((unsigned int)time(NULL));
for (unsigned int i = 0; i < test_count; i++) {
// find two random indices
int index1 = (int)((float)test_count * (rand() / (RAND_MAX + 1.0)));
int index2 = (int)((float)test_count * (rand() / (RAND_MAX + 1.0)));
// swap the data
int tmp = mp_testOrder[index1];
mp_testOrder[index1] = mp_testOrder[index2];
mp_testOrder[index2] = tmp;
}
}
}
/////////////////////////////////////////////////////////////////////////////
// Process device string. Returns true if there is a primary ATI Radeon device
// adapter, false otherwise
static bool procDevString(const char* devString) {
// Search for the string "Radeon" inside the device string
if (strstr(devString, "Radeon") || strstr(devString, "R600") || strstr(devString, "RV630") ||
strstr(devString, "RV670") ||
(strstr(devString, "Stream") && strstr(devString, "Processor"))) {
// Ignore if the device is a secondary device, i.e., not an adapter
if (strstr(devString, "Secondary")) {
return false;
}
} else {
return false;
}
return true;
}
//!
//! Function to find the total number of adapters on the system
//!
int findAdapters(unsigned int platformIdx, bool useCPU, cl_platform_id* mpform) {
unsigned int numOfAdapters = 0;
cl_int error = 0;
cl_uint numPlatforms = 0;
error = clGetPlatformIDs(0, NULL, &numPlatforms);
CHECK_RESULT((error != CL_SUCCESS), "clGetPlatformIDs failed");
CHECK_RESULT((platformIdx >= numPlatforms), "Invalid platform");
cl_platform_id* platforms = new cl_platform_id[numPlatforms];
error = clGetPlatformIDs(numPlatforms, platforms, NULL);
CHECK_RESULT(error != CL_SUCCESS, "clGetPlatformIDs failed");
cl_platform_id platform = 0;
platform = platforms[platformIdx];
delete[] platforms;
cl_device_type devType = CL_DEVICE_TYPE_GPU;
if (useCPU) devType = CL_DEVICE_TYPE_CPU;
error = clGetDeviceIDs(platform, devType, 0, 0, &numOfAdapters);
CHECK_RESULT((error != CL_SUCCESS), "clGetDeviceIDs failed");
if (mpform) {
(*mpform) = platform;
}
return (int)numOfAdapters;
}
int calibrate(OCLTest* test) {
int n = 1;
#if 0
while (1)
{
double timer = run(test, n);
if (timer > 2.)
{
break;
}
n *= 2;
}
#endif
return n;
}
void* dummyThread(void* argv) {
unsigned int counter = 0;
while (counter < 1000000) counter++;
return argv;
}
//! Function used to run the test specified
//! It would look something like OCLPerfInputspeed[0]
double run(OCLTest* test, int passes) {
CPerfCounter counter;
counter.Reset();
counter.Start();
int i;
for (i = 0; i < passes; i++) {
test->run();
}
counter.Stop();
double timer = counter.GetElapsedTime();
counter.Reset();
return timer;
}
//! Function to display the result after a test is finished
//! It also stores the result in a TestResult object
void report(Worker* w, const char* testname, int testnum, unsigned int crc, const char* errorMsg,
float timer, TestResult* tr, const char* testDesc) {
unsigned int thread = w->getId();
bool perflab = w->getPerflab();
unsigned int deviceId = w->getDeviceId();
char tmpUnits[256];
if (perflab) {
oclTestLog(OCLTEST_LOG_ALWAYS, "%10.3f\n", timer);
} else {
const char* passedOrFailed[] = {"FAILED", "PASSED"};
// char teststring[256];
// sprintf(teststring, "%s[%d]", testname, testnum);
// sprintf(tmpUnits, "Device[%d]:\t%-32s:\t%s\n", deviceId, teststring,
// ((tr->passed) ? passedOrFailed[1] : passedOrFailed[0]));
// If crc is not 0 or errorMsg is not empty, print the full stats
if ((crc != 0) || (errorMsg && (errorMsg[0] != '\0'))) {
sprintf(tmpUnits, "%s %s: %s[%d] T[%1d] [%3d], %10.3f %-20s (chksum 0x%08x)\n", testDesc,
((tr->passed) ? passedOrFailed[1] : passedOrFailed[0]),
w->isCPUEnabled() ? "CPU" : "GPU", deviceId, thread, testnum, timer, errorMsg, crc);
} else {
sprintf(tmpUnits, "%s %s: %s[%d] T[%1d] [%3d], %10.3f\n", testDesc,
((tr->passed) ? passedOrFailed[1] : passedOrFailed[0]),
w->isCPUEnabled() ? "CPU" : "GPU", deviceId, thread, testnum, timer);
}
oclTestLog(OCLTEST_LOG_ALWAYS, tmpUnits);
tr->value = timer;
tr->resultString.assign(tmpUnits);
if (App::m_svcMsg && !tr->passed) {
char escaped[2 * sizeof(tmpUnits)];
char* ptr = escaped;
for (int i = 0; tmpUnits[i] != '\0'; ++i) {
switch (tmpUnits[i]) {
case '\n':
*ptr++ = '|';
*ptr++ = 'n';
break;
case '\r':
*ptr++ = '|';
*ptr++ = 'r';
break;
case '\'':
case '|':
case ']':
case '[':
*ptr++ = '|';
default:
*ptr++ = tmpUnits[i];
}
}
*ptr = '\0';
oclTestLog(OCLTEST_LOG_ALWAYS,
"##%s[testFailed name='%s.%s.%d' message='FAILED' "
"details='%s']\n",
App::m_svcMsg, w->getModule()->get_libname(), testname, testnum, escaped);
}
}
}
//! Thread Entry point
void* runSubtest(void* worker) {
char units[256];
double conversion;
unsigned int crc = 0;
bool second_run = false;
// Getting the worker object that is running in this thread
Worker* w = (Worker*)worker;
if (w == 0) return NULL;
unsigned int test = w->getTestIndex();
unsigned int subtest = w->getSubTest();
unsigned int deviceId = w->getDeviceId();
unsigned int platformIndex = w->getPlatformID();
TestResult* result = w->getResult();
RERUN_TEST:
// Acquiring lock on the 'module' object common to all threads
moduleLock.lock();
Module* m = w->getModule();
if (m == 0 || m->create_test == 0) return NULL;
// If we can, used the cached version,
// otherwise create the test.
OCLTest* pt = (m->cached_test ? m->cached_test[subtest] : NULL);
if (!pt) {
pt = m->create_test(subtest);
if (pt->cache_test() && m->cached_test) {
m->cached_test[subtest] = pt;
}
}
pt->clearError();
OCLTestImp* tmp = pt->toOCLTestImp();
if (tmp) {
tmp->setOCLWrapper(w->getOCLWrapper());
}
std::string subtestName = m->get_name(subtest);
moduleLock.unlock();
if (pt == 0) return NULL;
pt->resetDescString();
if (App::m_svcMsg) {
oclTestLog(OCLTEST_LOG_ALWAYS,
"##%s[testStarted name='%s.%s.%d' "
"captureStandardOutput='true']\n",
App::m_svcMsg, m->get_libname(), subtestName.c_str(), test);
}
// setting the type to CPU.
if (w->isCPUEnabled()) {
pt->useCPU();
}
// Setting the device according to the worker thread
pt->setDeviceId(w->getDeviceId());
pt->setPlatformIndex(w->getPlatformID());
// Opening the 'test'th subtest of 'pt'
pt->open(test, units, conversion, deviceId);
pt->clearPerfInfo();
char buffer[256];
sprintf(buffer, "%s[%3d]", subtestName.c_str(), test);
oclTestLog(OCLTEST_LOG_ALWAYS, "%-32s", buffer);
if (pt->hasErrorOccured()) {
result->passed = false;
report(w, subtestName.c_str(), test, crc, pt->getErrorMsg(), pt->getPerfInfo(), result,
pt->testDescString.c_str());
} else {
unsigned int n = calibrate(pt);
double timer = run(pt, n);
crc = pt->close();
if (pt->hasErrorOccured()) {
// run second time if the test fails the first time.
if (!second_run && App::m_reRunFailed && !App::m_svcMsg) {
second_run = true;
// Destroying a test object
moduleLock.lock();
if (!pt->cache_test()) {
m->destroy_test(pt);
}
moduleLock.unlock();
pt->clearError();
goto RERUN_TEST;
}
}
result->passed = !pt->hasErrorOccured();
/// print conditional pass if it is passes the second time.
if (second_run && result->passed) {
report(w, subtestName.c_str(), test, crc, "Conditional PASS", pt->getPerfInfo(), result,
pt->testDescString.c_str());
} else {
report(w, subtestName.c_str(), test, crc, pt->getErrorMsg(), pt->getPerfInfo(), result,
pt->testDescString.c_str());
}
}
if (App::m_svcMsg) {
oclTestLog(OCLTEST_LOG_ALWAYS, "##%s[testFinished name='%s.%s.%d']\n", App::m_svcMsg,
m->get_libname(), subtestName.c_str(), test);
}
// Make sure we clear the error after we report that there was an error.
pt->clearError();
// Destroying a test object
moduleLock.lock();
if (!pt->cache_test()) {
m->destroy_test(pt);
}
moduleLock.unlock();
return NULL;
}
void App::PrintTestOrder(int mod_index) {
oclTestLog(OCLTEST_LOG_ALWAYS, "Module: %s (%d tests)\n", m_modules[mod_index].name.c_str(),
m_modules[mod_index].get_count());
for (unsigned int j = 0; j < m_modules[mod_index].get_count(); j++) {
oclTestLog(OCLTEST_LOG_ALWAYS, "%s\n", m_modules[mod_index].get_name(mp_testOrder[j]));
}
}
//! Function that runs all the tests specified in the command-line
bool App::RunAllTests() {
bool status = true;
#ifdef _WIN32
if (!m_console) m_window = new Window("Test", 100, 100, m_width, m_height, 0);
#endif
//
// Add all tests to run list if none specified
//
if (m_tests.size() < 1) {
for (unsigned int i = 0; i < m_modules.size(); i++) {
for (unsigned int j = 0; j < m_modules[i].get_count(); j++) {
AddToList(m_tests, m_modules[i].get_name(j));
}
}
}
unsigned int num_passes = 0;
unsigned int num_failures = 0;
//
// Run each test
//
for (unsigned int i = 0; i < m_modules.size(); i++) {
oclTestLog(OCLTEST_LOG_ALWAYS, "\n-------------------------------------------------\n");
oclTestLog(OCLTEST_LOG_ALWAYS, "The OpenCL Testing Module %s Version = %d \n",
m_modules[i].get_libname(), m_modules[i].get_version());
oclTestLog(OCLTEST_LOG_ALWAYS, "-------------------------------------------------\n");
if (App::m_svcMsg) {
oclTestLog(OCLTEST_LOG_ALWAYS, "##%s[testSuiteStarted name='ocltst %s']\n", App::m_svcMsg,
m_modules[i].get_libname());
}
// array to keep track of order of test execution.
int test_count = m_modules[i].get_count();
mp_testOrder = new int[test_count];
memset((void*)mp_testOrder, 0, sizeof(*mp_testOrder) * test_count);
SetTestRunOrder(i);
//
// List all tests first if the option was turned on
//
if (m_list) {
PrintTestOrder(i);
delete[] mp_testOrder;
continue;
// return;
}
for (unsigned int itr_var = 0; itr_var < m_modules[i].get_count(); itr_var++) {
// done for random order generation
unsigned int subtest = mp_testOrder[itr_var];
const char* name = m_modules[i].get_name(subtest);
if (itr_var < m_tests.size() && TestInList(m_tests, name)) {
OCLTest* pt = NULL;
if (m_modules[i].cached_test) {
pt = m_modules[i].cached_test[subtest];
}
// Try to use the cached version first!
if (!pt) {
pt = m_modules[i].create_test(subtest);
if (pt->cache_test() && m_modules[i].cached_test) {
m_modules[i].cached_test[subtest] = pt;
}
}
int numSubTests = pt->getNumSubTests();
assert(numSubTests > 0);
TestIndexList testIndices;
GetTestIndexList(testIndices, m_tests, name, numSubTests - 1);
TestIndexList avoidIndices;
GetTestIndexList(avoidIndices, m_avoid, name, numSubTests - 1);
TestIndexList erasedIndices;
PruneTestIndexList(testIndices, avoidIndices, erasedIndices);
int numTestsRun = 0;
for (unsigned int j = 0; j < testIndices.size(); j++) {
unsigned int test = testIndices[j];
WaitAllThreads();
AddWorkerThread(i, subtest, test, pt->getThreadUsage(), runSubtest);
for (unsigned int thread = 1; (thread < m_threads) && (thread < m_modules.size());
thread++) {
AddWorkerThread(thread, subtest, test, pt->getThreadUsage(), dummyThread);
}
numTestsRun++;
}
WaitAllThreads();
// Printing the test report
// First checking whether the number of subtests is greater than 1.
// No point printing report for a one subtest test
if (numTestsRun > 0) {
if (testReport[0]->success) {
num_passes++;
} else {
num_failures++;
}
}
if (App::m_svcMsg) {
for (unsigned int j = 0; j < erasedIndices.size(); j++) {
oclTestLog(OCLTEST_LOG_ALWAYS, "##%s[testIgnored name='%s.%s.%d']\n", App::m_svcMsg,
m_modules[i].get_libname(), name, erasedIndices[j]);
}
}
// Resetting the values of the test reports
// for(unsigned int j = 0; j < m_numDevices; j++)
for (unsigned int j = 0; j < 1; j++) {
testReport[j]->reset();
}
m_modules[i].destroy_test(pt);
if (m_modules[i].cached_test) {
m_modules[i].cached_test[subtest] = NULL;
}
}
}
if (App::m_svcMsg) {
oclTestLog(OCLTEST_LOG_ALWAYS, "##%s[testSuiteFinished name='ocltst %s']\n", App::m_svcMsg,
m_modules[i].get_libname());
}
// print the order in which the test are executed if they are
// randomized.
if (m_rndOrder) {
PrintTestOrder(i);
}
// deleting the test order
delete[] mp_testOrder;
}
#ifdef _WIN32
if (!m_console && m_window) {
((Window*)m_window)->ConsumeEvents();
}
#endif
float total_tests = (float)(num_passes + num_failures);
float percent_passed = 0.0f;
float percent_failed = 0.0f;
float percent_total = 0.0f;
if (total_tests > 0) {
percent_passed = 100.0f * ((float)num_passes / total_tests);
percent_failed = 100.0f * ((float)num_failures / total_tests);
percent_total = 100.0f * ((float)total_tests / total_tests);
}
oclTestLog(OCLTEST_LOG_ALWAYS, "\n\n");
oclTestLog(OCLTEST_LOG_ALWAYS, "----------------------------------------\n");
oclTestLog(OCLTEST_LOG_ALWAYS, "Total Passed Tests: %8d (%6.2f%s)\n", num_passes, percent_passed,
"%");
oclTestLog(OCLTEST_LOG_ALWAYS, "Total Failed Tests: %8d (%6.2f%s)\n", num_failures,
percent_failed, "%");
oclTestLog(OCLTEST_LOG_ALWAYS, "----------------------------------------\n");
oclTestLog(OCLTEST_LOG_ALWAYS, "Total Run Tests: %8d (%6.2f%s)\n", (int)total_tests,
percent_total, "%");
oclTestLog(OCLTEST_LOG_ALWAYS, "\n\n");
// fail the ocltst process if there are any failed tests
status = (num_failures == 0);
return status;
}
/////////////////////////////////////////////////////////////////////////////
void App::AddToList(StringList& strlist, const char* str) {
std::string s(str);
strlist.push_back(s);
}
void App::LoadList(StringList& strlist, const char* filename) {
char buffer[1024];
FILE* fp = fopen(filename, "r");
if (fp == NULL) return;
while (fgets(buffer, 1000, fp) != NULL) {
size_t length = strlen(buffer);
if (length > 0) {
if (buffer[length - 1] != '\n') {
length++;
}
buffer[length - 1] = 0;
AddToList(strlist, buffer);
}
}
fclose(fp);
}
static void Help(const char* name) {
oclTestLog(OCLTEST_LOG_ALWAYS,
"%s (-w | -V | -m | -M | -l | -t | -T | -p | -d | -x | -y | -g| "
"-o | -n )\n",
name);
oclTestLog(OCLTEST_LOG_ALWAYS, " -w : enable window mode\n");
oclTestLog(OCLTEST_LOG_ALWAYS, " -V : enable TeamCity service messages\n");
oclTestLog(OCLTEST_LOG_ALWAYS, " -J : enable Jenkins service messages\n");
oclTestLog(OCLTEST_LOG_ALWAYS,
" -d : dump test output to portable float map (pfm)\n");
oclTestLog(OCLTEST_LOG_ALWAYS, " -m <module> : specify a DLL module with tests\n");
oclTestLog(OCLTEST_LOG_ALWAYS,
" -M <filename> : specify a text file with one DLL module per line\n");
oclTestLog(OCLTEST_LOG_ALWAYS, " -l : list test names in DLL modules and exit\n");
oclTestLog(OCLTEST_LOG_ALWAYS, " -s <count> : number of threads to spawn\n");
oclTestLog(OCLTEST_LOG_ALWAYS, " -t <testname> : run test\n");
oclTestLog(OCLTEST_LOG_ALWAYS, " -T <filename> : specify a text file with one test per line\n");
oclTestLog(OCLTEST_LOG_ALWAYS, " -a <testname> : specify a test to avoid\n");
oclTestLog(OCLTEST_LOG_ALWAYS,
" -A <filename> : specify a text file of tests to avoid with "
"one test per line\n");
oclTestLog(OCLTEST_LOG_ALWAYS,
" -p <platform> : specify a platform to run on, 'amd','nvidia' "
",'intel' or 'ms'\n");
oclTestLog(OCLTEST_LOG_ALWAYS, " -h : this help text\n");
oclTestLog(OCLTEST_LOG_ALWAYS,
" -x : x dimension for debug output image (and window)\n");
oclTestLog(OCLTEST_LOG_ALWAYS,
" -y : y dimension for debug output image (and window)\n");
oclTestLog(OCLTEST_LOG_ALWAYS,
" -P : Perflab mode (just print the result without "
"any supplementary information)\n");
oclTestLog(OCLTEST_LOG_ALWAYS,
" -n #number : run the tests specified with -m, -M, -t or -T "
"options multiple times\n");
oclTestLog(OCLTEST_LOG_ALWAYS,
" -r : Option to Randomize the order in which the "
"tests are executed.\n");
oclTestLog(OCLTEST_LOG_ALWAYS,
" -R : Option to ReRun failed tests for conditional "
"pass.\n");
oclTestLog(OCLTEST_LOG_ALWAYS, " -i : Don't print system information\n");
oclTestLog(OCLTEST_LOG_ALWAYS, " -g <GPUid> : GPUid to run the tests on\n");
oclTestLog(OCLTEST_LOG_ALWAYS, " -o <filename> : dump the output to a specified file\n");
oclTestLog(OCLTEST_LOG_ALWAYS, " -c : Run the test on the CPU device.\n");
oclTestLog(OCLTEST_LOG_ALWAYS, " : \n");
oclTestLog(OCLTEST_LOG_ALWAYS,
" : To run only one subtest of a test, append the "
"subtest to\n");
oclTestLog(OCLTEST_LOG_ALWAYS,
" : the end of the test name in brackets. i.e. test[1]");
oclTestLog(OCLTEST_LOG_ALWAYS, "\n");
exit(0);
}
unsigned int getPlatformID(const char* str) {
std::string strOfCLVendor(str);
std::string strOfCLPlatformName;
unsigned int platform = 0;
// currently, the only input values amd,nvidia and intel are supported
if (strOfCLVendor == "amd") {
strOfCLPlatformName = "Advanced Micro Devices, Inc.";
} else if (strOfCLVendor == "intel") {
strOfCLPlatformName = "Intel(R) Corporation";
} else if (strOfCLVendor == "nvidia") {
strOfCLPlatformName = "NVIDIA Corporation";
} else if (strOfCLVendor == "ms") {
strOfCLPlatformName = "Microsoft";
} else {
// fall-back on platform index 0
return platform;
}
cl_int status;
cl_uint numPlatforms = 0;
status = clGetPlatformIDs(0, NULL, &numPlatforms);
if (status != CL_SUCCESS) {
return platform;
}
cl_platform_id* platforms = new cl_platform_id[numPlatforms];
status = clGetPlatformIDs(numPlatforms, platforms, NULL);
if (status == CL_SUCCESS) {
unsigned int i;
for (i = 0; i < numPlatforms; ++i) {
char buff[200];
status = clGetPlatformInfo(platforms[i], CL_PLATFORM_VENDOR, sizeof(buff), buff, NULL);
if (status != CL_SUCCESS) {
break;
}
if (strcmp(buff, strOfCLPlatformName.c_str()) == 0) {
platform = i;
break;
}
}
}
delete[] platforms;
return platform;
}
static const char* supported_options = "dg:lm:M:o:Ps:t:T:a:A:p:v:wxy:in:rcRVJ";
unsigned int parseCommandLineForPlatform(unsigned int argc, char** argv) {
int c;
unsigned int platform = 0;
while ((c = getopt(argc, argv, supported_options)) != -1) {
switch (c) {
case 'p':
platform = getPlatformID(optarg);
break;
default:
break;
}
}
return platform;
}
void App::CommandLine(unsigned int argc, char** argv) {
unsigned int i = 1;
int c;
bool hasOption = false;
unsigned int tmpNumDevices = 0;
unsigned int tmpDeviceId = 0;
m_deviceId = 0;
int tmp;
while ((c = getopt(argc, argv, supported_options)) != -1) {
switch (c) {
case 'c':
m_useCPU = true;
break;
case 'p':
break;
case 'w':
m_console = false;
hasOption = true;
break;
case 'V':
m_svcMsg = "teamcity";
break;
case 'J':
m_svcMsg = "jenkins";
break;
case 'd':
m_dump = true;
hasOption = true;
break;
case 'm':
AddToList(m_paths, optarg);
hasOption = true;
break;
case 'M':
LoadList(m_paths, optarg);
hasOption = true;
break;
case 'a':
AddToList(m_avoid, optarg);
hasOption = true;
break;
case 'A':
LoadList(m_avoid, optarg);
hasOption = true;
break;
case 'l':
m_list = true;
hasOption = true;
break;
// command line switch to loop execution of any specified test or tests n
// number of times
case 'n':
m_numItr = atoi(optarg);
break;
// command line switch to randomize the order of test execution in OCLTest
case 'r':
m_rndOrder = true;
break;
// command line switch to rerun the failed tests to see if they pass on
// second run
case 'R': {
m_reRunFailed = true;
break;
}
case 't':
AddToList(m_tests, optarg);
hasOption = true;
break;
case 'T':
LoadList(m_tests, optarg);
hasOption = true;
break;
case 's':
m_threads = atoi(optarg);
hasOption = true;
break;
case 'h':
Help(argv[0]);
break;
case 'x':
m_width = atoi(optarg);
hasOption = true;
break;
case 'y':
m_height = atoi(optarg);
hasOption = true;
break;
case 'P':
m_perflab = true;
hasOption = true;
break;
case 'g':
#if 0
tmpNumDevices = (unsigned int)atoi(optarg);
if(m_numDevices < tmpNumDevices)
{
oclTestLog(OCLTEST_LOG_ALWAYS, "Number of Devices(%d) less than specified by the user(%d). Using %d devices.\n", m_numDevices, tmpNumDevices, m_numDevices);
}
else
{
m_numDevices = tmpNumDevices;
}
#else
tmpDeviceId = (unsigned int)atoi(optarg);
#endif
break;
case 'v':
tmp = atoi(optarg);
if (tmp >= 0 && tmp < 100) {
oclTestSetLogLevel(atoi(optarg));
} else {
oclTestLog(OCLTEST_LOG_ALWAYS, "Invalid verbose level\n");
}
break;
case 'o': {
hasOption = true;
oclTestEnableLogToFile(optarg);
} break;
case 'i':
m_noSysInfoPrint = true;
break;
default:
Help(argv[0]);
break;
}
}
// Reset devices in case user overrode defaults
m_numDevices = findAdapters(m_platform, m_useCPU, &mpform_id);
if (m_numDevices < (tmpDeviceId + 1)) {
m_deviceId = 0;
oclTestLog(OCLTEST_LOG_ALWAYS,
"User specified deviceId(%d) exceedes the number of "
"Devices(%d). Using device %d.\n",
tmpDeviceId, m_numDevices, m_deviceId);
} else {
m_deviceId = tmpDeviceId;
}
if (!hasOption) {
Help(argv[0]);
}
}
bool App::TestInList(StringList& strlist, const char* szModuleTestname) {
if (szModuleTestname == NULL) {
return false;
}
for (unsigned int i = 0; i < strlist.size(); i++) {
// check to see if an index is specified for this test name
int nIndex = -1;
std::string szTestName = strlist[i];
if (szTestName.find("[") != std::string::npos) {
size_t nFirstBracket = szTestName.find("[");
size_t nLastBracket = szTestName.find("]");
if ((nFirstBracket != std::string::npos) && (nLastBracket != std::string::npos) &&
(nLastBracket > nFirstBracket)) {
szTestName = szTestName.substr(0, nFirstBracket);
}
}
if (strcmp(szModuleTestname, szTestName.c_str()) == 0) {
return true;
}
}
return false;
}
void App::GetTestIndexList(TestIndexList& testIndices, StringList& testList,
const char* szModuleTestname, int maxIndex) {
for (unsigned int i = 0; i < testList.size(); i++) {
IndicesRange nIndex = {0, maxIndex};
// If the test name string ends with [...] parse the text
// between the brackets to determine the index range.
std::string szTestName = testList[i];
if (szTestName.find("[") != std::string::npos) {
size_t nFirstBracket = szTestName.find("[");
size_t nLastBracket = szTestName.find("]");
if ((nFirstBracket != std::string::npos) && (nLastBracket != std::string::npos) &&
(nLastBracket > nFirstBracket)) {
// Getting the string between the brackets '[' and ']'
// The values can be one of the following:-
// [a-b] - Run tests from a to b
// [a-] - Run tests from subtest a to subtest total_tests
// [-b] - Run tests from subtest 0 to subtest b
// a and b are indices of the tests to run
std::string nIndexString =
szTestName.substr(nFirstBracket + 1, nLastBracket - nFirstBracket - 1);
size_t nIntermediateHyphen = szTestName.find("-");
if ((nIntermediateHyphen != std::string::npos) && (nIntermediateHyphen < nLastBracket) &&
(nIntermediateHyphen > nFirstBracket)) {
// Getting the start index
if ((nIntermediateHyphen - 1) == nFirstBracket) {
nIndex.startIndex = 0;
} else {
nIndex.startIndex =
atoi(szTestName.substr(nFirstBracket + 1, nIntermediateHyphen - nFirstBracket - 1)
.c_str());
}
// Getting the end index
if ((nIntermediateHyphen + 1) == nLastBracket) {
nIndex.endIndex = maxIndex;
} else {
nIndex.endIndex = atoi(
szTestName.substr(nIntermediateHyphen + 1, nLastBracket - nIntermediateHyphen - 1)
.c_str());
}
} else {
nIndex.startIndex =
atoi(szTestName.substr(nFirstBracket + 1, nLastBracket - nFirstBracket - 1).c_str());
nIndex.endIndex = nIndex.startIndex;
}
}
szTestName = szTestName.substr(0, nFirstBracket);
}
if (strcmp(szModuleTestname, szTestName.c_str()) == 0) {
// If the values are out of order, swap them.
if (nIndex.startIndex > nIndex.endIndex) {
int tmp = nIndex.startIndex;
nIndex.startIndex = nIndex.endIndex;
nIndex.endIndex = tmp;
}
// Add the indices in the specified range to the list.
for (int i = nIndex.startIndex; i <= nIndex.endIndex; ++i) {
if (i <= maxIndex) {
testIndices.push_back(i);
} else {
oclTestLog(OCLTEST_LOG_ALWAYS, "Error: Invalid test index for subtest: %s!\n",
szModuleTestname);
}
}
// Now sort and prune duplicates.
std::sort(testIndices.begin(), testIndices.end());
std::unique(testIndices.begin(), testIndices.end());
}
}
}
void App::PruneTestIndexList(TestIndexList& testIndices, TestIndexList& avoidIndices,
TestIndexList& erasedIndices) {
for (TestIndexList::iterator it = testIndices.begin(); it != testIndices.end();) {
unsigned int index = *it;
TestIndexList::iterator result = std::find(avoidIndices.begin(), avoidIndices.end(), index);
if (result != avoidIndices.end()) {
it = testIndices.erase(it);
erasedIndices.push_back(index);
} else {
++it;
}
}
}
void App::ScanForTests() {
for (unsigned int i = 0; i < m_paths.size(); i++) {
Module mod;
#ifdef _WIN32
std::string::iterator myIter;
myIter = m_paths[i].end();
myIter--;
if (*myIter == 0x0a) m_paths[i].erase(myIter);
mod.hmodule = LoadLibrary(m_paths[i].c_str());
#endif
#ifdef __linux__
mod.hmodule = dlopen(m_paths[i].c_str(), RTLD_NOW);
#endif
if (mod.hmodule == NULL) {
fprintf(stderr, "Could not load module: %s\n", m_paths[i].c_str());
#ifdef __linux__
fprintf(stderr, "Error : %s\n", dlerror());
#else
#endif
} else {
mod.name = m_paths[i];
#ifdef _WIN32
mod.get_count = (TestCountFuncPtr)GetProcAddress(mod.hmodule, "OCLTestList_TestCount");
mod.get_name = (TestNameFuncPtr)GetProcAddress(mod.hmodule, "OCLTestList_TestName");
mod.create_test = (CreateTestFuncPtr)GetProcAddress(mod.hmodule, "OCLTestList_CreateTest");
mod.destroy_test = (DestroyTestFuncPtr)GetProcAddress(mod.hmodule, "OCLTestList_DestroyTest");
mod.get_version =
(TestVersionFuncPtr)GetProcAddress(mod.hmodule, "OCLTestList_TestLibVersion");
mod.get_libname = (TestLibNameFuncPtr)GetProcAddress(mod.hmodule, "OCLTestList_TestLibName");
#endif
#ifdef __linux__
mod.get_count = (TestCountFuncPtr)dlsym(mod.hmodule, "OCLTestList_TestCount");
mod.get_name = (TestNameFuncPtr)dlsym(mod.hmodule, "OCLTestList_TestName");
mod.create_test = (CreateTestFuncPtr)dlsym(mod.hmodule, "OCLTestList_CreateTest");
mod.destroy_test = (DestroyTestFuncPtr)dlsym(mod.hmodule, "OCLTestList_DestroyTest");
mod.get_version = (TestVersionFuncPtr)dlsym(mod.hmodule, "OCLTestList_TestLibVersion");
mod.get_libname = (TestLibNameFuncPtr)dlsym(mod.hmodule, "OCLTestList_TestLibName");
#endif
mod.cached_test = new OCLTest*[mod.get_count()];
for (int x = 0, y = mod.get_count(); x < y; ++x) {
mod.cached_test[x] = NULL;
}
m_modules.push_back(mod);
}
}
}
void App::CleanUp() {
for (unsigned int i = 0; i < m_modules.size(); i++) {
if (m_modules[i].cached_test) {
delete[] m_modules[i].cached_test;
}
#ifdef _WIN32
FreeLibrary(m_modules[i].hmodule);
#endif
#ifdef __linux__
dlclose(m_modules[i].hmodule);
#endif
}
#ifdef _WIN32
if (m_window) delete m_window;
m_window = 0;
#endif
}
extern int optind;
/////////////////////////////////////////////////////////////////////////////
bool App::m_reRunFailed = false;
const char* App::m_svcMsg = nullptr;
int main(int argc, char** argv) {
#if EMU_ENV
printf("Built for Emulation Environment\n");
#endif // EMU_ENV
unsigned int platform = 0;
platform = parseCommandLineForPlatform(argc, argv);
// reset optind as we really didn't parse the full command line
optind = 1;
bool status = true;
App app(platform);
#ifdef _WIN32
// this function is registers windows service routine when ocltst is launched
// by the OS on service initialization. On other scenarios, this function does
// nothing.
serviceStubCall();
// SetErrorMode(SEM_NOGPFAULTERRORBOX);
// const LPTOP_LEVEL_EXCEPTION_FILTER oldFilter =
// SetUnhandledExceptionFilter(xFilter);
#endif // _WIN32
#ifdef AUTO_REGRESS
try {
#endif /* AUTO_REGRESS */
app.CommandLine(argc, argv);
app.printOCLinfo();
app.ScanForTests();
for (int i = 0; i < app.GetNumItr(); i++) {
if (!app.RunAllTests()) {
status = false;
}
}
app.CleanUp();
#ifdef AUTO_REGRESS
} catch (...) {
oclTestLog(OCLTEST_LOG_ALWAYS, "Exiting due to unhandled exception!\n");
return (-1);
}
#endif /* AUTO_REGRESS */
// return 0 if all tests passed, 1 otherwise
return status ? 0 : 1;
}
#ifdef _WIN32
#include <dbghelp.h>
typedef unsigned int uint32;
typedef size_t uintp;
struct StackEntry {
uintp addr;
uint32 line;
uint32 disp;
char symbol[128];
char file[128];
};
static const unsigned int MAX_DEPTH_PER_NODE = 24;
struct Info {
bool operator==(const Info& b) const { return key == b.key; }
uintp key; // pointer, handle, whatever
StackEntry stack[MAX_DEPTH_PER_NODE];
};
static void dumpTraceBack(CONTEXT& context) {
Info info;
oclTestLog(OCLTEST_LOG_ALWAYS, "Exception: exiting!\n");
HANDLE process = GetCurrentProcess();
STACKFRAME64 stackframe;
memset(&stackframe, 0, sizeof(STACKFRAME64));
#if defined(_WIN64)
stackframe.AddrPC.Offset = context.Rip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Rsp;
stackframe.AddrStack.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Rbp;
stackframe.AddrFrame.Mode = AddrModeFlat;
#else
stackframe.AddrPC.Offset = context.Eip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Esp;
stackframe.AddrStack.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Ebp;
stackframe.AddrFrame.Mode = AddrModeFlat;
#endif
unsigned int depth = 0;
if (SymInitialize(process, NULL, true)) {
while ((depth < MAX_DEPTH_PER_NODE) &&
StackWalk64(IMAGE_FILE_MACHINE_I386, process, GetCurrentThread(), &stackframe, &context,
NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
if (stackframe.AddrPC.Offset != 0) {
//
// we don't want to evaluate the names/lines yet
// so just record the address
//
info.stack[depth].addr = (uintp)stackframe.AddrPC.Offset;
DWORD64 disp64;
DWORD disp;
IMAGEHLP_SYMBOL64* symInfo;
IMAGEHLP_LINE64 lineInfo;
uintp addr = (uintp)stackframe.AddrPC.Offset;
char buffer[128];
symInfo = (IMAGEHLP_SYMBOL64*)&buffer[0];
symInfo->SizeOfStruct = sizeof(symInfo);
symInfo->MaxNameLength = (sizeof(buffer) - sizeof(IMAGEHLP_SYMBOL64));
lineInfo.SizeOfStruct = sizeof(lineInfo);
if (SymGetSymFromAddr64(process, addr, &disp64, symInfo)) {
sprintf(info.stack[depth].symbol, "%s", symInfo->Name);
info.stack[depth].disp = (uint32)disp64;
} else {
sprintf(info.stack[depth].symbol, "");
}
if (SymGetLineFromAddr64(process, addr, &disp, &lineInfo)) {
sprintf(info.stack[depth].file, "%s", lineInfo.FileName);
info.stack[depth].line = lineInfo.LineNumber;
} else {
info.stack[depth].file[0] = '\0';
}
depth++;
}
}
}
SymCleanup(process);
int j = 0;
while (j < MAX_DEPTH_PER_NODE && info.stack[j].addr != 0) {
oclTestLog(OCLTEST_LOG_ALWAYS, " %s()+%d (0x%.8x) %s:%d\n", info.stack[j].symbol,
info.stack[j].disp, info.stack[j].addr, info.stack[j].file, info.stack[j].line);
j++;
}
}
static LONG WINAPI xFilter(LPEXCEPTION_POINTERS xEP) {
CONTEXT context;
CONTEXT* xCtx = &context;
memset(xCtx, 0, sizeof(CONTEXT));
context.ContextFlags = CONTEXT_FULL;
memcpy(xCtx, xEP->ContextRecord, sizeof(CONTEXT));
dumpTraceBack(context);
return (EXCEPTION_EXECUTE_HANDLER);
}
#undef CHECK_RESULT
#endif // WIN_OS
/////////////////////////////////////////////////////////////////////////////