Hash :
44b5f0a5
Author :
Date :
2025-01-06T16:01:28
OpenCL: Pass in options to the CTS tests In the case where options are specified, pass them down to the CTS tests. New tests with options for copy_images, fill_images and bruteforce are added. The changes in `angle.json` file are autogenerated by running `python3 scripts.run_code_generation.py` Bug: angleproject:388319897 Change-Id: I1c7e133d8df00e008857b652132b45975f61a08e Signed-off-by: Gowtham Tammana <g.tammana@samsung.com> Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/6153935 Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Austin Annestrand <a.annestrand@samsung.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
#include <gtest/gtest.h>
#if !defined(__APPLE__)
# include <CL/cl.h>
#endif
#include <stdlib.h>
#include <cassert>
#include <fstream>
#include "harness/testHarness.h"
#include "common/string_utils.h"
#include "common/system_utils.h"
#include "src/tests/test_utils/runner/TestSuite.h"
#include "util/OSWindow.h"
#define MAX_LINE_LENGTH 3000
// The |main| function in each CTS executable is renamed to |ANGLE_oclcts_main|. It is called by
// the test functions.
extern int ANGLE_oclcts_main(int argc, const char **argv);
namespace
{
constexpr char kInfoTag[] = "*RESULT";
std::string TrimString(const std::string &input, const std::string &trimChars)
{
auto begin = input.find_first_not_of(trimChars);
if (begin == std::string::npos)
{
return "";
}
std::string::size_type end = input.find_last_not_of(trimChars);
if (end == std::string::npos)
{
return input.substr(begin);
}
return input.substr(begin, end - begin + 1);
}
class OpenCLCaseList
{
public:
OpenCLCaseList();
struct CaseInfo
{
CaseInfo(const std::string &testNameIn, int expectationIn)
: testCaseDescription(testNameIn), expectation(expectationIn)
{
// The test list is specified in the form <testSuiteName.testName testArgs>. Parse the
// string as such.
size_t startPos = testCaseDescription.find('.');
testSuiteName = testCaseDescription.substr(0, startPos);
testNameWithArgs = "";
if (startPos != std::string::npos)
testNameWithArgs = testCaseDescription.substr(startPos + 1);
}
std::string testCaseDescription;
std::string testSuiteName;
std::string testNameWithArgs;
int expectation;
};
void initialize(angle::TestSuite *instance);
const CaseInfo &getCaseInfo(size_t caseIndex) const
{
assert(mInitialized);
assert(caseIndex < mCaseInfoList.size());
return mCaseInfoList[caseIndex];
}
size_t numCases() const
{
assert(mInitialized);
return mCaseInfoList.size();
}
private:
std::vector<CaseInfo> mCaseInfoList;
bool mInitialized = false;
};
OpenCLCaseList::OpenCLCaseList() {}
const OpenCLCaseList &GetTestList()
{
angle::TestSuite *instance = angle::TestSuite::GetInstance();
static OpenCLCaseList sCaseList;
sCaseList.initialize(instance);
return sCaseList;
}
void OpenCLCaseList::initialize(angle::TestSuite *instance)
{
mInitialized = true;
constexpr char kTestExpectationsPath[] = "src/tests/cl_support/openclcts_expectations.txt";
constexpr char kTestMustPassPath[] = "src/tests/cl_support/openclcts_mustpass.txt";
constexpr size_t kMaxPath = 512;
std::array<char, kMaxPath> foundDataPath;
if (!angle::FindTestDataPath(kTestExpectationsPath, foundDataPath.data(), foundDataPath.size()))
{
std::cerr << "Unable to find test expectations path (" << kTestExpectationsPath << ")\n";
exit(EXIT_FAILURE);
}
if (!instance->loadAllTestExpectationsFromFile(std::string(foundDataPath.data())))
{
exit(EXIT_FAILURE);
}
if (!angle::FindTestDataPath(kTestMustPassPath, foundDataPath.data(), foundDataPath.size()))
{
std::cerr << "Unable to find test must pass list path (" << kTestMustPassPath << ")\n";
exit(EXIT_FAILURE);
}
std::ifstream caseListStream(std::string(foundDataPath.data()));
if (caseListStream.fail())
{
std::cerr << "Failed to load the case list." << std::endl;
exit(EXIT_FAILURE);
}
while (!caseListStream.eof())
{
std::string inString;
std::getline(caseListStream, inString);
std::string testName = TrimString(inString, angle::kWhitespaceASCII);
if (testName.empty())
continue;
int expectation = instance->getTestExpectation(testName);
mCaseInfoList.push_back(CaseInfo(testName, expectation));
}
}
class OpenCLTestSuiteStats
{
public:
OpenCLTestSuiteStats() {}
private:
void setUpTestStats();
void printTestStats();
void countTestResult(int result);
uint32_t mTestCount;
uint32_t mPassedTestCount;
uint32_t mFailedTestCount;
uint32_t mTestExceptionCount;
uint32_t mNotSupportedTestCount;
uint32_t mSkippedTestCount;
std::vector<std::string> mUnexpectedFailed;
std::vector<std::string> mUnexpectedPasses;
friend class OpenCLTest;
};
void OpenCLTestSuiteStats::setUpTestStats()
{
mPassedTestCount = 0;
mFailedTestCount = 0;
mNotSupportedTestCount = 0;
mTestExceptionCount = 0;
mTestCount = 0;
mSkippedTestCount = 0;
mUnexpectedPasses.clear();
mUnexpectedFailed.clear();
}
std::string GetTestStatLine(const std::string &key, const std::string &value)
{
return std::string(kInfoTag) + ": " + key + ": " + value + "\n";
}
void OpenCLTestSuiteStats::printTestStats()
{
uint32_t crashedCount =
mTestCount - (mPassedTestCount + mFailedTestCount + mNotSupportedTestCount +
mTestExceptionCount + mSkippedTestCount);
std::cout << GetTestStatLine("Total", std::to_string(mTestCount));
std::cout << GetTestStatLine("Passed", std::to_string(mPassedTestCount));
std::cout << GetTestStatLine("Failed", std::to_string(mFailedTestCount));
std::cout << GetTestStatLine("Skipped", std::to_string(mSkippedTestCount));
std::cout << GetTestStatLine("Not Supported", std::to_string(mNotSupportedTestCount));
std::cout << GetTestStatLine("Exception", std::to_string(mTestExceptionCount));
std::cout << GetTestStatLine("Crashed", std::to_string(crashedCount));
if (!mUnexpectedPasses.empty())
{
std::cout << GetTestStatLine("Unexpected Passed Count",
std::to_string(mUnexpectedPasses.size()));
for (const std::string &testName : mUnexpectedPasses)
{
std::cout << GetTestStatLine("Unexpected Passed Tests", testName);
}
}
if (!mUnexpectedFailed.empty())
{
std::cout << GetTestStatLine("Unexpected Failed Count",
std::to_string(mUnexpectedFailed.size()));
for (const std::string &testName : mUnexpectedFailed)
{
std::cout << GetTestStatLine("Unexpected Failed Tests", testName);
}
}
}
void OpenCLTestSuiteStats::countTestResult(int result)
{
switch (result)
{
case EXIT_SUCCESS:
mPassedTestCount++;
break;
default:
mFailedTestCount++;
break;
}
}
class OpenCLTest : public testing::Test
{
public:
OpenCLTest(size_t caseIndex) : mTestCaseIndex(caseIndex) {}
static void SetUpTestSuite();
static void TearDownTestSuite();
protected:
void TestBody() override;
private:
size_t mTestCaseIndex = 0;
static OpenCLTestSuiteStats sTestSuiteData;
};
OpenCLTestSuiteStats OpenCLTest::sTestSuiteData = OpenCLTestSuiteStats();
// static function called once before running all of OpenCLTest under the same test suite
void OpenCLTest::SetUpTestSuite()
{
sTestSuiteData.setUpTestStats();
}
// static function called once after running all of OpenCLTest under the same test suite
void OpenCLTest::TearDownTestSuite()
{
sTestSuiteData.printTestStats();
}
void OpenCLTest::TestBody()
{
const auto &caseInfo = GetTestList().getCaseInfo(mTestCaseIndex);
// Tests that crash exit the harness before collecting the result. To tally the number of
// crashed tests we track how many tests we "tried" to run.
sTestSuiteData.mTestCount++;
if (caseInfo.expectation == angle::GPUTestExpectationsParser::kGpuTestSkip)
{
sTestSuiteData.mSkippedTestCount++;
std::cout << "Test skipped.\n";
return;
}
// test name and options
std::vector<std::string> testNameVector;
angle::SplitStringAlongWhitespace(caseInfo.testNameWithArgs, &testNameVector);
std::vector<const char *> argv;
argv.push_back(caseInfo.testSuiteName.c_str());
for (const auto &str : testNameVector)
{
argv.push_back(str.c_str());
}
int argc = argv.size();
// C requires argv[argc] shall be null pointer
argv.push_back(nullptr);
const int result = ANGLE_oclcts_main(argc, argv.data());
sTestSuiteData.countTestResult(result);
if (caseInfo.expectation == angle::GPUTestExpectationsParser::kGpuTestPass ||
caseInfo.expectation == angle::GPUTestExpectationsParser::kGpuTestFlaky)
{
EXPECT_EQ(result, EXIT_SUCCESS);
if (result != EXIT_SUCCESS)
{
sTestSuiteData.mUnexpectedFailed.push_back(caseInfo.testCaseDescription);
}
}
else if (result == EXIT_SUCCESS)
{
std::cout << "Test expected to fail but passed!" << std::endl;
sTestSuiteData.mUnexpectedPasses.push_back(caseInfo.testCaseDescription);
}
}
void RegisterCLCTSTests()
{
const OpenCLCaseList &testList = GetTestList();
for (size_t caseIndex = 0; caseIndex < testList.numCases(); caseIndex++)
{
auto factory = [caseIndex]() { return new OpenCLTest(caseIndex); };
// The mustpass list contains lines in the form suite.name. There is one executable per
// test suite, and the suite name can be found in ANGLE_CL_SUITE_NAME. Tests that are from
// other suites are excluded for this executable.
//
// Note that the CTS has groups of test suites, but so far the test suite names alone are
// unique so the group name is not placed in the mustpass.
const std::string &testSuiteName = testList.getCaseInfo(caseIndex).testSuiteName;
const std::string &testName = testList.getCaseInfo(caseIndex).testNameWithArgs;
if (testSuiteName != ANGLE_CL_SUITE_NAME)
{
continue;
}
testing::RegisterTest(testSuiteName.c_str(), testName.c_str(), nullptr, nullptr, __FILE__,
__LINE__, factory);
}
}
} // anonymous namespace
int main(int argc, char **argv)
{
// Set up the environment for the CTS
#ifdef ANGLE_OPENCL_ICD_PATH
{
// The icd file is placed in the executable directory
const std::string moduleDir = angle::GetModuleDirectory();
const std::string icdPath = angle::ConcatenatePath(moduleDir, ANGLE_OPENCL_ICD_PATH);
angle::SetEnvironmentVar("OCL_ICD_VENDORS", icdPath.c_str());
}
#endif // ANGLE_OPENCL_ICD_PATH
// TODO: Fix TestSuite so that it "consumes" the args that it picks up, leaving any that is not
// recognized. The left over should then be passed to `ANGLE_oclcts_main` in `TestBody`.
// http://anglebug.com/372722560
angle::TestSuite testSuite(&argc, argv, RegisterCLCTSTests);
return testSuite.run();
}