1 /* 2 * Copyright (c) 2017-2018,2021 Arm Limited. 3 * 4 * SPDX-License-Identifier: MIT 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to 8 * deal in the Software without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in all 14 * copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 #ifndef ARM_COMPUTE_TEST_MEASUREMENT 25 #define ARM_COMPUTE_TEST_MEASUREMENT 26 27 #include "../Utils.h" 28 #include "arm_compute/core/Error.h" 29 30 #include <list> 31 #include <ostream> 32 #include <string> 33 34 namespace arm_compute 35 { 36 namespace test 37 { 38 namespace framework 39 { 40 /** Generic measurement that stores values as either double or long long int. */ 41 struct Measurement 42 { 43 /** Measurement value */ 44 struct Value 45 { 46 /** Constructor 47 * 48 * @param[in] is_floating Will the value stored be floating point ? 49 */ ValueMeasurement::Value50 Value(bool is_floating) 51 : v{ 0 }, is_floating_point(is_floating) 52 { 53 } 54 55 /** Add the value stored to the stream as a string 56 */ 57 friend std::ostream &operator<<(std::ostream &os, const Value &value) 58 { 59 if(value.is_floating_point) 60 { 61 os << arithmetic_to_string(value.v.floating_point, 4); 62 } 63 else 64 { 65 os << arithmetic_to_string(value.v.integer); 66 } 67 return os; 68 } 69 /** Convert the value stored to string 70 */ to_stringMeasurement::Value71 std::string to_string() const 72 { 73 std::stringstream ss; 74 ss << *this; 75 return ss.str(); 76 } 77 /** Add with another value and return the sum 78 * 79 * @param[in] b Other value 80 * 81 * @return Sum of the stored value + b 82 */ 83 Value operator+(Value b) const 84 { 85 if(is_floating_point) 86 { 87 b.v.floating_point += v.floating_point; 88 } 89 else 90 { 91 b.v.integer += v.integer; 92 } 93 return b; 94 } 95 96 /** Subtract with another value and return the result 97 * 98 * @param[in] b Other value 99 * 100 * @return Result of the stored value - b 101 */ 102 Value operator-(Value b) const 103 { 104 if(is_floating_point) 105 { 106 b.v.floating_point -= v.floating_point; 107 } 108 else 109 { 110 b.v.integer -= v.integer; 111 } 112 return b; 113 } 114 115 /** Multiple with another value and return the result 116 * 117 * @param[in] b Other value 118 * 119 * @return Result of the stored value * b 120 */ 121 Value operator*(Value b) const 122 { 123 if(is_floating_point) 124 { 125 b.v.floating_point *= v.floating_point; 126 } 127 else 128 { 129 b.v.integer *= v.integer; 130 } 131 return b; 132 } 133 134 /** Return the stored value divided by an integer. 135 * 136 * @param[in] b Integer to divide the value by. 137 * 138 * @return Stored value / b 139 */ 140 Value operator/(int b) const 141 { 142 Value res(is_floating_point); 143 if(is_floating_point) 144 { 145 res.v.floating_point = v.floating_point / b; 146 } 147 else 148 { 149 res.v.integer = v.integer / b; 150 } 151 return res; 152 } 153 154 /** Subtract another value and return the updated stored value. 155 * 156 * @param[in] b Other value 157 * 158 * @return The updated stored value 159 */ 160 Value &operator-=(const Value &b) 161 { 162 if(is_floating_point) 163 { 164 v.floating_point -= b.v.floating_point; 165 } 166 else 167 { 168 v.integer -= b.v.integer; 169 } 170 return *this; 171 } 172 173 /** Compare the stored value with another value 174 * 175 * @param[in] b Value to compare against 176 * 177 * @return The result of stored value < b 178 */ 179 bool operator<(const Value &b) const 180 { 181 if(is_floating_point) 182 { 183 return v.floating_point < b.v.floating_point; 184 } 185 else 186 { 187 return v.integer < b.v.integer; 188 } 189 } 190 191 /** Get the relative standard deviation to a given distribution as a percentage. 192 * 193 * @param[in] variance The variance of the distribution. 194 * @param[in] mean The mean of the distribution. 195 * 196 * @return the relative standard deviation. 197 */ relative_standard_deviationMeasurement::Value198 static double relative_standard_deviation(const Value &variance, const Value &mean) 199 { 200 if(variance.is_floating_point) 201 { 202 return 100.0 * sqrt(variance.v.floating_point) / mean.v.floating_point; 203 } 204 else 205 { 206 return 100.0 * sqrt(static_cast<double>(variance.v.integer)) / mean.v.integer; 207 } 208 } 209 210 /** Stored value */ 211 union 212 { 213 double floating_point; 214 long long int integer; 215 } v; 216 bool is_floating_point; /**< Is the stored value floating point or integer ? */ 217 }; 218 219 /** Compare the stored value with another value 220 * 221 * @param[in] b Value to compare against 222 * 223 * @return The result of stored value < b 224 */ 225 bool operator<(const Measurement &b) const 226 { 227 return _value < b.value(); 228 } 229 230 /** Stream output operator to print the measurement. 231 * 232 * Prints value and unit. 233 * 234 * @param[out] os Output stream. 235 * @param[in] measurement Measurement. 236 * 237 * @return the modified output stream. 238 */ 239 friend inline std::ostream &operator<<(std::ostream &os, const Measurement &measurement) 240 { 241 os << measurement._value << " " << measurement._unit; 242 return os; 243 } 244 245 /** Constructor to store a floating point value 246 * 247 * @param[in] v Value to store 248 * @param[in] unit Unit of @p v 249 * @param[in] raw (Optional) The raw value(s) @p was generated from. 250 */ 251 template < typename Floating, typename std::enable_if < !std::is_integral<Floating>::value, int >::type = 0 > 252 Measurement(Floating v, std::string unit, std::list<std::string> raw = {}) _unitMeasurement253 : _unit(unit), _raw_data(std::move(raw)), _value(true) 254 { 255 _value.v.floating_point = static_cast<double>(v); 256 if(_raw_data.empty()) 257 { 258 _raw_data = { _value.to_string() }; 259 } 260 } 261 262 /** Constructor to store an integer value 263 * 264 * @param[in] v Value to store 265 * @param[in] unit Unit of @p v 266 * @param[in] raw (Optional) The raw value(s) @p was generated from. 267 */ 268 template <typename Integer, typename std::enable_if<std::is_integral<Integer>::value, int>::type = 0> 269 Measurement(Integer v, std::string unit, std::list<std::string> raw = {}) _unitMeasurement270 : _unit(unit), _raw_data(std::move(raw)), _value(false) 271 { 272 _value.v.integer = static_cast<long long int>(v); 273 if(_raw_data.empty()) 274 { 275 _raw_data = { _value.to_string() }; 276 } 277 } 278 279 /** Accessor for the unit of the measurement 280 * 281 * @return Unit of the measurement 282 */ unitMeasurement283 const std::string &unit() const 284 { 285 return _unit; 286 } 287 288 /** Accessor for the raw data 289 * 290 * @return The raw data 291 */ raw_dataMeasurement292 const std::list<std::string> &raw_data() const 293 { 294 return _raw_data; 295 } 296 297 /** Accessor for the stored value 298 * 299 * @return The stored value 300 */ valueMeasurement301 const Value &value() const 302 { 303 return _value; 304 } 305 306 private: 307 std::string _unit; 308 std::list<std::string> _raw_data; 309 Value _value; 310 }; 311 312 } // namespace framework 313 } // namespace test 314 } // namespace arm_compute 315 #endif /* ARM_COMPUTE_TEST_MEASUREMENT */ 316