123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "gpu/config/gpu_test_expectations_parser.h"
- #include <stddef.h>
- #include <stdint.h>
- #include "base/check_op.h"
- #include "base/files/file_util.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/string_split.h"
- #include "base/strings/string_util.h"
- #include "base/strings/stringprintf.h"
- namespace gpu {
- namespace {
- enum LineParserStage {
- kLineParserBegin = 0,
- kLineParserBugID,
- kLineParserConfigs,
- kLineParserColon,
- kLineParserTestName,
- kLineParserEqual,
- kLineParserExpectations,
- };
- enum Token {
- // os
- kConfigWinXP = 0,
- kConfigWinVista,
- kConfigWin7,
- kConfigWin8,
- kConfigWin10,
- kConfigWin,
- kConfigMacLeopard,
- kConfigMacSnowLeopard,
- kConfigMacLion,
- kConfigMacMountainLion,
- kConfigMacMavericks,
- kConfigMacYosemite,
- kConfigMacElCapitan,
- kConfigMacSierra,
- kConfigMacHighSierra,
- kConfigMacMojave,
- kConfigMacCatalina,
- kConfigMacBigSur,
- kConfigMacMonterey,
- kConfigMac,
- kConfigLinux,
- kConfigChromeOS,
- kConfigAndroid,
- // gpu vendor
- kConfigNVidia,
- kConfigAMD,
- kConfigIntel,
- kConfigVMWare,
- // build type
- kConfigRelease,
- kConfigDebug,
- // ANGLE renderer
- kConfigD3D9,
- kConfigD3D11,
- kConfigGLDesktop,
- kConfigGLES,
- // command decoder
- kConfigPassthrough,
- kConfigValidating,
- // expectation
- kExpectationPass,
- kExpectationFail,
- kExpectationFlaky,
- kExpectationTimeout,
- kExpectationSkip,
- // separator
- kSeparatorColon,
- kSeparatorEqual,
- kNumberOfExactMatchTokens,
- // others
- kConfigGPUDeviceID,
- kTokenComment,
- kTokenWord,
- };
- struct TokenInfo {
- const char* name;
- int32_t flag;
- };
- const TokenInfo kTokenData[] = {
- {"xp", GPUTestConfig::kOsWinXP},
- {"vista", GPUTestConfig::kOsWinVista},
- {"win7", GPUTestConfig::kOsWin7},
- {"win8", GPUTestConfig::kOsWin8},
- {"win10", GPUTestConfig::kOsWin10},
- {"win", GPUTestConfig::kOsWin},
- {"leopard", GPUTestConfig::kOsMacLeopard},
- {"snowleopard", GPUTestConfig::kOsMacSnowLeopard},
- {"lion", GPUTestConfig::kOsMacLion},
- {"mountainlion", GPUTestConfig::kOsMacMountainLion},
- {"mavericks", GPUTestConfig::kOsMacMavericks},
- {"yosemite", GPUTestConfig::kOsMacYosemite},
- {"elcapitan", GPUTestConfig::kOsMacElCapitan},
- {"sierra", GPUTestConfig::kOsMacSierra},
- {"highsierra", GPUTestConfig::kOsMacHighSierra},
- {"mojave", GPUTestConfig::kOsMacMojave},
- {"catalina", GPUTestConfig::kOsMacCatalina},
- {"bigsur", GPUTestConfig::kOsMacBigSur},
- {"monterey", GPUTestConfig::kOsMacMonterey},
- {"mac", GPUTestConfig::kOsMac},
- {"linux", GPUTestConfig::kOsLinux},
- {"chromeos", GPUTestConfig::kOsChromeOS},
- {"android", GPUTestConfig::kOsAndroid},
- {"nvidia", 0x10DE},
- {"amd", 0x1002},
- {"intel", 0x8086},
- {"vmware", 0x15ad},
- {"release", GPUTestConfig::kBuildTypeRelease},
- {"debug", GPUTestConfig::kBuildTypeDebug},
- {"d3d9", GPUTestConfig::kAPID3D9},
- {"d3d11", GPUTestConfig::kAPID3D11},
- {"opengl", GPUTestConfig::kAPIGLDesktop},
- {"gles", GPUTestConfig::kAPIGLES},
- {"passthrough", GPUTestConfig::kCommandDecoderPassthrough},
- {"validating", GPUTestConfig::kCommandDecoderValidating},
- {"pass", GPUTestExpectationsParser::kGpuTestPass},
- {"fail", GPUTestExpectationsParser::kGpuTestFail},
- {"flaky", GPUTestExpectationsParser::kGpuTestFlaky},
- {"timeout", GPUTestExpectationsParser::kGpuTestTimeout},
- {"skip", GPUTestExpectationsParser::kGpuTestSkip},
- {":", 0},
- {"=", 0},
- };
- enum ErrorType {
- kErrorFileIO = 0,
- kErrorIllegalEntry,
- kErrorInvalidEntry,
- kErrorEntryWithOsConflicts,
- kErrorEntryWithGpuVendorConflicts,
- kErrorEntryWithBuildTypeConflicts,
- kErrorEntryWithAPIConflicts,
- kErrorEntryWithCommandDecoderConflicts,
- kErrorEntryWithGpuDeviceIdConflicts,
- kErrorEntryWithExpectationConflicts,
- kErrorEntriesOverlap,
- kNumberOfErrors,
- };
- const char* kErrorMessage[] = {
- "file IO failed",
- "entry with wrong format",
- "entry invalid, likely wrong modifiers combination",
- "entry with OS modifier conflicts",
- "entry with GPU vendor modifier conflicts",
- "entry with GPU build type conflicts",
- "entry with GPU API conflicts",
- "entry with GPU process command decoder conflicts",
- "entry with GPU device id conflicts or malformat",
- "entry with expectation modifier conflicts",
- "two entries' configs overlap",
- };
- Token ParseToken(const std::string& word) {
- if (base::StartsWith(word, "//", base::CompareCase::INSENSITIVE_ASCII))
- return kTokenComment;
- if (base::StartsWith(word, "0x", base::CompareCase::INSENSITIVE_ASCII))
- return kConfigGPUDeviceID;
- for (int32_t i = 0; i < kNumberOfExactMatchTokens; ++i) {
- if (base::EqualsCaseInsensitiveASCII(word, kTokenData[i].name))
- return static_cast<Token>(i);
- }
- return kTokenWord;
- }
- // reference name can have the last character as *.
- bool NamesMatching(const std::string& ref, const std::string& test_name) {
- size_t len = ref.length();
- if (len == 0)
- return false;
- if (ref[len - 1] == '*') {
- if (test_name.length() > len -1 &&
- ref.compare(0, len - 1, test_name, 0, len - 1) == 0)
- return true;
- return false;
- }
- return (ref == test_name);
- }
- } // namespace anonymous
- GPUTestExpectationsParser::GPUTestExpectationsParser() {
- // Some sanity check.
- DCHECK_EQ(static_cast<unsigned int>(kNumberOfExactMatchTokens),
- sizeof(kTokenData) / sizeof(kTokenData[0]));
- DCHECK_EQ(static_cast<unsigned int>(kNumberOfErrors),
- sizeof(kErrorMessage) / sizeof(kErrorMessage[0]));
- }
- GPUTestExpectationsParser::~GPUTestExpectationsParser() = default;
- bool GPUTestExpectationsParser::LoadTestExpectations(const std::string& data) {
- entries_.clear();
- error_messages_.clear();
- std::vector<std::string> lines = base::SplitString(
- data, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- bool rt = true;
- for (size_t i = 0; i < lines.size(); ++i) {
- if (!ParseLine(lines[i], i + 1))
- rt = false;
- }
- if (DetectConflictsBetweenEntries()) {
- entries_.clear();
- rt = false;
- }
- return rt;
- }
- bool GPUTestExpectationsParser::LoadTestExpectations(
- const base::FilePath& path) {
- entries_.clear();
- error_messages_.clear();
- std::string data;
- if (!base::ReadFileToString(path, &data)) {
- error_messages_.push_back(kErrorMessage[kErrorFileIO]);
- return false;
- }
- return LoadTestExpectations(data);
- }
- int32_t GPUTestExpectationsParser::GetTestExpectation(
- const std::string& test_name,
- const GPUTestBotConfig& bot_config) const {
- for (size_t i = 0; i < entries_.size(); ++i) {
- if (NamesMatching(entries_[i].test_name, test_name) &&
- bot_config.Matches(entries_[i].test_config))
- return entries_[i].test_expectation;
- }
- return kGpuTestPass;
- }
- const std::vector<std::string>&
- GPUTestExpectationsParser::GetErrorMessages() const {
- return error_messages_;
- }
- bool GPUTestExpectationsParser::ParseConfig(
- const std::string& config_data, GPUTestConfig* config) {
- DCHECK(config);
- std::vector<std::string> tokens = base::SplitString(
- config_data, base::kWhitespaceASCII, base::KEEP_WHITESPACE,
- base::SPLIT_WANT_NONEMPTY);
- for (size_t i = 0; i < tokens.size(); ++i) {
- Token token = ParseToken(tokens[i]);
- switch (token) {
- case kConfigWinXP:
- case kConfigWinVista:
- case kConfigWin7:
- case kConfigWin8:
- case kConfigWin10:
- case kConfigWin:
- case kConfigMacLeopard:
- case kConfigMacSnowLeopard:
- case kConfigMacLion:
- case kConfigMacMountainLion:
- case kConfigMacMavericks:
- case kConfigMacYosemite:
- case kConfigMacElCapitan:
- case kConfigMacSierra:
- case kConfigMacHighSierra:
- case kConfigMacMojave:
- case kConfigMacCatalina:
- case kConfigMacBigSur:
- case kConfigMacMonterey:
- case kConfigMac:
- case kConfigLinux:
- case kConfigChromeOS:
- case kConfigAndroid:
- case kConfigNVidia:
- case kConfigAMD:
- case kConfigIntel:
- case kConfigVMWare:
- case kConfigRelease:
- case kConfigDebug:
- case kConfigD3D9:
- case kConfigD3D11:
- case kConfigGLDesktop:
- case kConfigGLES:
- case kConfigPassthrough:
- case kConfigValidating:
- case kConfigGPUDeviceID:
- if (token == kConfigGPUDeviceID) {
- if (!UpdateTestConfig(config, tokens[i], 0))
- return false;
- } else {
- if (!UpdateTestConfig(config, token, 0))
- return false;
- }
- break;
- default:
- return false;
- }
- }
- return true;
- }
- bool GPUTestExpectationsParser::ParseLine(
- const std::string& line_data, size_t line_number) {
- std::vector<std::string> tokens = base::SplitString(
- line_data, base::kWhitespaceASCII, base::KEEP_WHITESPACE,
- base::SPLIT_WANT_NONEMPTY);
- int32_t stage = kLineParserBegin;
- GPUTestExpectationEntry entry;
- entry.line_number = line_number;
- GPUTestConfig& config = entry.test_config;
- bool comments_encountered = false;
- for (size_t i = 0; i < tokens.size() && !comments_encountered; ++i) {
- Token token = ParseToken(tokens[i]);
- switch (token) {
- case kTokenComment:
- comments_encountered = true;
- break;
- case kConfigWinXP:
- case kConfigWinVista:
- case kConfigWin7:
- case kConfigWin8:
- case kConfigWin10:
- case kConfigWin:
- case kConfigMacLeopard:
- case kConfigMacSnowLeopard:
- case kConfigMacLion:
- case kConfigMacMountainLion:
- case kConfigMacMavericks:
- case kConfigMacYosemite:
- case kConfigMacElCapitan:
- case kConfigMacSierra:
- case kConfigMacHighSierra:
- case kConfigMacMojave:
- case kConfigMacCatalina:
- case kConfigMacBigSur:
- case kConfigMacMonterey:
- case kConfigMac:
- case kConfigLinux:
- case kConfigChromeOS:
- case kConfigAndroid:
- case kConfigNVidia:
- case kConfigAMD:
- case kConfigIntel:
- case kConfigVMWare:
- case kConfigRelease:
- case kConfigDebug:
- case kConfigD3D9:
- case kConfigD3D11:
- case kConfigGLDesktop:
- case kConfigGLES:
- case kConfigPassthrough:
- case kConfigValidating:
- case kConfigGPUDeviceID:
- // MODIFIERS, could be in any order, need at least one.
- if (stage != kLineParserConfigs && stage != kLineParserBugID) {
- PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
- line_number);
- return false;
- }
- if (token == kConfigGPUDeviceID) {
- if (!UpdateTestConfig(&config, tokens[i], line_number))
- return false;
- } else {
- if (!UpdateTestConfig(&config, token, line_number))
- return false;
- }
- if (stage == kLineParserBugID)
- stage++;
- break;
- case kSeparatorColon:
- // :
- if (stage != kLineParserConfigs) {
- PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
- line_number);
- return false;
- }
- stage++;
- break;
- case kSeparatorEqual:
- // =
- if (stage != kLineParserTestName) {
- PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
- line_number);
- return false;
- }
- stage++;
- break;
- case kTokenWord:
- // BUG_ID or TEST_NAME
- if (stage == kLineParserBegin) {
- // Bug ID is not used for anything; ignore it.
- } else if (stage == kLineParserColon) {
- entry.test_name = tokens[i];
- } else {
- PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
- line_number);
- return false;
- }
- stage++;
- break;
- case kExpectationPass:
- case kExpectationFail:
- case kExpectationFlaky:
- case kExpectationTimeout:
- case kExpectationSkip:
- // TEST_EXPECTATIONS
- if (stage != kLineParserEqual && stage != kLineParserExpectations) {
- PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
- line_number);
- return false;
- }
- if ((kTokenData[token].flag & entry.test_expectation) != 0) {
- PushErrorMessage(kErrorMessage[kErrorEntryWithExpectationConflicts],
- line_number);
- return false;
- }
- entry.test_expectation =
- (kTokenData[token].flag | entry.test_expectation);
- if (stage == kLineParserEqual)
- stage++;
- break;
- default:
- DCHECK(false);
- break;
- }
- }
- if (stage == kLineParserBegin) {
- // The whole line is empty or all comments
- return true;
- }
- if (stage == kLineParserExpectations) {
- if (!config.IsValid()) {
- PushErrorMessage(kErrorMessage[kErrorInvalidEntry], line_number);
- return false;
- }
- entries_.push_back(entry);
- return true;
- }
- PushErrorMessage(kErrorMessage[kErrorIllegalEntry], line_number);
- return false;
- }
- bool GPUTestExpectationsParser::UpdateTestConfig(GPUTestConfig* config,
- int32_t token,
- size_t line_number) {
- DCHECK(config);
- switch (token) {
- case kConfigWinXP:
- case kConfigWinVista:
- case kConfigWin7:
- case kConfigWin8:
- case kConfigWin10:
- case kConfigWin:
- case kConfigMacLeopard:
- case kConfigMacSnowLeopard:
- case kConfigMacLion:
- case kConfigMacMountainLion:
- case kConfigMacMavericks:
- case kConfigMacYosemite:
- case kConfigMacElCapitan:
- case kConfigMacSierra:
- case kConfigMacHighSierra:
- case kConfigMacMojave:
- case kConfigMacCatalina:
- case kConfigMacBigSur:
- case kConfigMacMonterey:
- case kConfigMac:
- case kConfigLinux:
- case kConfigChromeOS:
- case kConfigAndroid:
- if ((config->os() & kTokenData[token].flag) != 0) {
- PushErrorMessage(kErrorMessage[kErrorEntryWithOsConflicts],
- line_number);
- return false;
- }
- config->set_os(config->os() | kTokenData[token].flag);
- break;
- case kConfigNVidia:
- case kConfigAMD:
- case kConfigIntel:
- case kConfigVMWare:
- {
- uint32_t gpu_vendor = static_cast<uint32_t>(kTokenData[token].flag);
- for (size_t i = 0; i < config->gpu_vendor().size(); ++i) {
- if (config->gpu_vendor()[i] == gpu_vendor) {
- PushErrorMessage(
- kErrorMessage[kErrorEntryWithGpuVendorConflicts],
- line_number);
- return false;
- }
- }
- config->AddGPUVendor(gpu_vendor);
- }
- break;
- case kConfigRelease:
- case kConfigDebug:
- if ((config->build_type() & kTokenData[token].flag) != 0) {
- PushErrorMessage(
- kErrorMessage[kErrorEntryWithBuildTypeConflicts],
- line_number);
- return false;
- }
- config->set_build_type(
- config->build_type() | kTokenData[token].flag);
- break;
- case kConfigD3D9:
- case kConfigD3D11:
- case kConfigGLDesktop:
- case kConfigGLES:
- if ((config->api() & kTokenData[token].flag) != 0) {
- PushErrorMessage(kErrorMessage[kErrorEntryWithAPIConflicts],
- line_number);
- return false;
- }
- config->set_api(config->api() | kTokenData[token].flag);
- break;
- case kConfigPassthrough:
- case kConfigValidating:
- if ((config->command_decoder() & kTokenData[token].flag) != 0) {
- PushErrorMessage(kErrorMessage[kErrorEntryWithCommandDecoderConflicts],
- line_number);
- return false;
- }
- config->set_command_decoder(config->command_decoder() |
- kTokenData[token].flag);
- break;
- default:
- DCHECK(false);
- break;
- }
- return true;
- }
- bool GPUTestExpectationsParser::UpdateTestConfig(
- GPUTestConfig* config,
- const std::string& gpu_device_id,
- size_t line_number) {
- DCHECK(config);
- uint32_t device_id = 0;
- if (config->gpu_device_id() != 0 ||
- !base::HexStringToUInt(gpu_device_id, &device_id) ||
- device_id == 0) {
- PushErrorMessage(kErrorMessage[kErrorEntryWithGpuDeviceIdConflicts],
- line_number);
- return false;
- }
- config->set_gpu_device_id(device_id);
- return true;
- }
- bool GPUTestExpectationsParser::DetectConflictsBetweenEntries() {
- bool rt = false;
- for (size_t i = 0; i < entries_.size(); ++i) {
- for (size_t j = i + 1; j < entries_.size(); ++j) {
- if (entries_[i].test_name == entries_[j].test_name &&
- entries_[i].test_config.OverlapsWith(entries_[j].test_config)) {
- PushErrorMessage(kErrorMessage[kErrorEntriesOverlap],
- entries_[i].line_number,
- entries_[j].line_number);
- rt = true;
- }
- }
- }
- return rt;
- }
- void GPUTestExpectationsParser::PushErrorMessage(
- const std::string& message, size_t line_number) {
- error_messages_.push_back(
- base::StringPrintf("Line %d : %s",
- static_cast<int>(line_number), message.c_str()));
- }
- void GPUTestExpectationsParser::PushErrorMessage(
- const std::string& message,
- size_t entry1_line_number,
- size_t entry2_line_number) {
- error_messages_.push_back(
- base::StringPrintf("Line %d and %d : %s",
- static_cast<int>(entry1_line_number),
- static_cast<int>(entry2_line_number),
- message.c_str()));
- }
- GPUTestExpectationsParser:: GPUTestExpectationEntry::GPUTestExpectationEntry()
- : test_expectation(0),
- line_number(0) {
- }
- } // namespace gpu
|