null-catrank.c++ (4898B)
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #include "null-common.h" 23 24 namespace capnp { 25 namespace benchmark { 26 namespace null { 27 28 struct SearchResult { 29 const char* url; 30 double score; 31 const char* snippet; 32 }; 33 34 struct ScoredResult { 35 double score; 36 const SearchResult* result; 37 38 ScoredResult() = default; 39 ScoredResult(double score, const SearchResult* result): score(score), result(result) {} 40 41 inline bool operator<(const ScoredResult& other) const { return score > other.score; } 42 }; 43 44 class CatRankTestCase { 45 public: 46 typedef List<SearchResult> Request; 47 typedef List<SearchResult> Response; 48 typedef int Expectation; 49 50 static int setupRequest(List<SearchResult>* request) { 51 int count = fastRand(1000); 52 int goodCount = 0; 53 54 request->init(count); 55 for (int i = 0; i < count; i++) { 56 SearchResult& result = request->items[i]; 57 result.score = 1000 - i; 58 char* pos = reinterpret_cast<char*>(arenaPos); 59 result.url = pos; 60 61 strcpy(pos, "http://example.com/"); 62 pos += strlen("http://example.com/"); 63 int urlSize = fastRand(100); 64 for (int j = 0; j < urlSize; j++) { 65 *pos++ = 'a' + fastRand(26); 66 } 67 *pos++ = '\0'; 68 69 // Retroactively allocate the space we used. 70 if (allocate<char>(pos - result.url) != result.url) { 71 throw std::bad_alloc(); 72 } 73 74 bool isCat = fastRand(8) == 0; 75 bool isDog = fastRand(8) == 0; 76 goodCount += isCat && !isDog; 77 78 pos = reinterpret_cast<char*>(arenaPos); 79 result.snippet = pos; 80 81 *pos++ = ' '; 82 83 int prefix = fastRand(20); 84 for (int j = 0; j < prefix; j++) { 85 const char* word = WORDS[fastRand(WORDS_COUNT)]; 86 size_t len = strlen(word); 87 memcpy(pos, word, len); 88 pos += len; 89 } 90 91 if (isCat) { 92 strcpy(pos, "cat "); 93 pos += 4; 94 } 95 if (isDog) { 96 strcpy(pos, "dog "); 97 pos += 4; 98 } 99 100 int suffix = fastRand(20); 101 for (int j = 0; j < suffix; j++) { 102 const char* word = WORDS[fastRand(WORDS_COUNT)]; 103 size_t len = strlen(word); 104 memcpy(pos, word, len); 105 pos += len; 106 } 107 *pos++ = '\0'; 108 109 // Retroactively allocate the space we used. 110 if (allocate<char>(pos - result.snippet) != result.snippet) { 111 throw std::bad_alloc(); 112 } 113 } 114 115 return goodCount; 116 } 117 118 static void handleRequest(const List<SearchResult>& request, List<SearchResult>* response) { 119 std::vector<ScoredResult> scoredResults; 120 scoredResults.reserve(request.size); 121 122 for (auto& result: request) { 123 double score = result.score; 124 if (strstr(result.snippet, " cat ") != nullptr) { 125 score *= 10000; 126 } 127 if (strstr(result.snippet, " dog ") != nullptr) { 128 score /= 10000; 129 } 130 scoredResults.emplace_back(score, &result); 131 } 132 133 std::sort(scoredResults.begin(), scoredResults.end()); 134 135 response->init(scoredResults.size()); 136 SearchResult* dst = response->items; 137 for (auto& result: scoredResults) { 138 dst->url = copyString(result.result->url); 139 dst->score = result.score; 140 dst->snippet = copyString(result.result->snippet); 141 ++dst; 142 } 143 } 144 145 static bool checkResponse(const List<SearchResult>& response, int expectedGoodCount) { 146 int goodCount = 0; 147 for (auto& result: response) { 148 if (result.score > 1001) { 149 ++goodCount; 150 } else { 151 break; 152 } 153 } 154 155 return goodCount == expectedGoodCount; 156 } 157 }; 158 159 } // namespace null 160 } // namespace benchmark 161 } // namespace capnp 162 163 int main(int argc, char* argv[]) { 164 return capnp::benchmark::benchmarkMain< 165 capnp::benchmark::null::BenchmarkTypes, 166 capnp::benchmark::null::CatRankTestCase>(argc, argv); 167 }