5a0ecc8e48
Change-Id: I0ce8369a7ef569ac82c6e20266d0c98331a43e08
1612 строки
48 KiB
C++
1612 строки
48 KiB
C++
/* Copyright (c) 2010 - 2021 Advanced Micro Devices, Inc.
|
|
|
|
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 <CL/cl.h>
|
|
|
|
#ifdef ATI_OS_WIN
|
|
#include <windows.h>
|
|
|
|
#include "Window.h"
|
|
typedef HMODULE ModuleHandle;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef ATI_OS_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 ATI_OS_WIN
|
|
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 bool 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_wrapper = new OCLWrapper();
|
|
|
|
// 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, NULL);
|
|
// 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
|
|
void 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 ATI_OS_WIN
|
|
#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,
|
|
"##teamcity[testFailed name='%s.%s.%d' message='FAILED' "
|
|
"details='%s']\n",
|
|
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,
|
|
"##teamcity[testStarted name='%s.%s.%d' "
|
|
"captureStandardOutput='true']\n",
|
|
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, "##teamcity[testFinished name='%s.%s.%d']\n",
|
|
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
|
|
void App::RunAllTests() {
|
|
#ifdef ATI_OS_WIN
|
|
|
|
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;
|
|
|
|
if (App::m_svcMsg) {
|
|
oclTestLog(OCLTEST_LOG_ALWAYS,
|
|
"##teamcity[testSuiteStarted name='ocltst']\n");
|
|
}
|
|
|
|
//
|
|
// 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");
|
|
|
|
// 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,
|
|
"##teamcity[testIgnored name='%s.%s.%d']\n",
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
if (App::m_svcMsg) {
|
|
oclTestLog(OCLTEST_LOG_ALWAYS,
|
|
"##teamcity[testSuiteFinished name='ocltst']\n");
|
|
}
|
|
|
|
#ifdef ATI_OS_WIN
|
|
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");
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
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,
|
|
" -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' "
|
|
"or 'intel'\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 {
|
|
// 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;
|
|
}
|
|
|
|
unsigned int parseCommandLineForPlatform(unsigned int argc, char** argv) {
|
|
int c;
|
|
unsigned int platform = 0;
|
|
|
|
while ((c = getopt(argc, argv, "dg:lm:M:o:Ps:t:T:a:A:p:v:wxy:in:rcRV")) !=
|
|
-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, "dg:lm:M:o:Ps:t:T:a:A:p:v:wxy:in:rcRV")) !=
|
|
-1) {
|
|
switch (c) {
|
|
case 'c':
|
|
m_useCPU = true;
|
|
break;
|
|
|
|
case 'p':
|
|
break;
|
|
|
|
case 'w':
|
|
m_console = false;
|
|
hasOption = true;
|
|
break;
|
|
|
|
case 'V':
|
|
m_svcMsg = true;
|
|
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 ATI_OS_WIN
|
|
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 ATI_OS_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 ATI_OS_LINUX
|
|
fprintf(stderr, "Error : %s\n", dlerror());
|
|
#else
|
|
#endif
|
|
} else {
|
|
mod.name = m_paths[i];
|
|
|
|
#ifdef ATI_OS_WIN
|
|
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 ATI_OS_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 ATI_OS_WIN
|
|
FreeLibrary(m_modules[i].hmodule);
|
|
#endif
|
|
#ifdef ATI_OS_LINUX
|
|
dlclose(m_modules[i].hmodule);
|
|
#endif
|
|
}
|
|
|
|
#ifdef ATI_OS_WIN
|
|
if (m_window) delete m_window;
|
|
m_window = 0;
|
|
#endif
|
|
}
|
|
|
|
extern int optind;
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
bool App::m_reRunFailed = false;
|
|
bool App::m_svcMsg = false;
|
|
int main(int argc, char** argv) {
|
|
unsigned int platform = 0;
|
|
platform = parseCommandLineForPlatform(argc, argv);
|
|
// reset optind as we really didn't parse the full command line
|
|
optind = 0;
|
|
App app(platform);
|
|
#ifdef ATI_OS_WIN
|
|
// 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 // ATI_OS_WIN
|
|
#ifdef AUTO_REGRESS
|
|
try {
|
|
#endif /* AUTO_REGRESS */
|
|
app.CommandLine(argc, argv);
|
|
app.printOCLinfo();
|
|
app.ScanForTests();
|
|
for (int i = 0; i < app.GetNumItr(); i++) {
|
|
app.RunAllTests();
|
|
}
|
|
app.CleanUp();
|
|
#ifdef AUTO_REGRESS
|
|
} catch (...) {
|
|
oclTestLog(OCLTEST_LOG_ALWAYS, "Exiting due to unhandled exception!\n");
|
|
return (-1);
|
|
}
|
|
#endif /* AUTO_REGRESS */
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef ATI_OS_WIN
|
|
|
|
#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
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|