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 enum class Operation {
29   ADD,
30   SUBTRACT,
31   MULTIPLY,
32   DIVIDE,
33   MODULUS
34 };
35 uint OPERATION_RANGE = static_cast<uint>(Operation::MODULUS) + 1;
36 
37 struct Expression {
38   Operation op;
39 
40   bool leftIsValue;
41   bool rightIsValue;
42 
43   union {
44     int32_t leftValue;
45     Expression* leftExpression;
46   };
47 
48   union {
49     int32_t rightValue;
50     Expression* rightExpression;
51   };
52 };
53 
makeExpression(Expression * exp,uint depth)54 int32_t makeExpression(Expression* exp, uint depth) {
55   exp->op = (Operation)(fastRand(OPERATION_RANGE));
56 
57   int32_t left, right;
58 
59   if (fastRand(8) < depth) {
60     exp->leftIsValue = true;
61     left = fastRand(128) + 1;
62     exp->leftValue = left;
63   } else {
64     exp->leftIsValue = false;
65     exp->leftExpression = allocate<Expression>();
66     left = makeExpression(exp->leftExpression, depth + 1);
67   }
68 
69   if (fastRand(8) < depth) {
70     exp->rightIsValue = true;
71     right = fastRand(128) + 1;
72     exp->rightValue = right;
73   } else {
74     exp->rightIsValue = false;
75     exp->rightExpression = allocate<Expression>();
76     right = makeExpression(exp->rightExpression, depth + 1);
77   }
78 
79   switch (exp->op) {
80     case Operation::ADD:
81       return left + right;
82     case Operation::SUBTRACT:
83       return left - right;
84     case Operation::MULTIPLY:
85       return left * right;
86     case Operation::DIVIDE:
87       return div(left, right);
88     case Operation::MODULUS:
89       return mod(left, right);
90   }
91   throw std::logic_error("Can't get here.");
92 }
93 
evaluateExpression(const Expression & exp)94 int32_t evaluateExpression(const Expression& exp) {
95   uint32_t left, right;
96 
97   if (exp.leftIsValue) {
98     left = exp.leftValue;
99   } else {
100     left = evaluateExpression(*exp.leftExpression);
101   }
102 
103   if (exp.rightIsValue) {
104     right = exp.rightValue;
105   } else {
106     right = evaluateExpression(*exp.rightExpression);
107   }
108 
109   switch (exp.op) {
110     case Operation::ADD:
111       return left + right;
112     case Operation::SUBTRACT:
113       return left - right;
114     case Operation::MULTIPLY:
115       return left * right;
116     case Operation::DIVIDE:
117       return div(left, right);
118     case Operation::MODULUS:
119       return mod(left, right);
120   }
121   throw std::logic_error("Can't get here.");
122 }
123 
124 class ExpressionTestCase {
125 public:
126   typedef Expression Request;
127   typedef int32_t Response;
128   typedef int32_t Expectation;
129 
setupRequest(Expression * request)130   static inline int32_t setupRequest(Expression* request) {
131     return makeExpression(request, 0);
132   }
handleRequest(const Expression & request,int32_t * response)133   static inline void handleRequest(const Expression& request, int32_t* response) {
134     *response = evaluateExpression(request);
135   }
checkResponse(int32_t response,int32_t expected)136   static inline bool checkResponse(int32_t response, int32_t expected) {
137     return response == expected;
138   }
139 
spaceUsed(const Expression & expression)140   static size_t spaceUsed(const Expression& expression) {
141     return sizeof(Expression) +
142         (expression.leftExpression == nullptr ? 0 : spaceUsed(*expression.leftExpression)) +
143         (expression.rightExpression == nullptr ? 0 : spaceUsed(*expression.rightExpression));
144   }
145 };
146 
147 }  // namespace null
148 }  // namespace benchmark
149 }  // namespace capnp
150 
main(int argc,char * argv[])151 int main(int argc, char* argv[]) {
152   return capnp::benchmark::benchmarkMain<
153       capnp::benchmark::null::BenchmarkTypes,
154       capnp::benchmark::null::ExpressionTestCase>(argc, argv);
155 }
156