testUtil.c revision a31faf1b7edb5c20d3a8949ba3ca767b4f0a4a7d
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18#include <testUtil.h> 19 20#include <assert.h> 21#include <math.h> 22#include <stdarg.h> 23#include <stdint.h> 24#include <stdio.h> 25#include <stdlib.h> 26#include <time.h> 27#include <sys/time.h> 28#include <cutils/log.h> 29 30#define ALEN(a) (sizeof(a) / sizeof(a [0])) // Array length 31typedef unsigned int bool_t; 32#define true (0 == 0) 33#define false (!true) 34 35#define MAXSTR 200 36 37static const char *logCatTag; 38static const unsigned int uSecsPerSec = 1000000; 39static const unsigned int nSecsPerSec = 1000000000; 40 41// struct timespec to double 42double ts2double(const struct timespec *val) 43{ 44 double rv; 45 46 rv = val->tv_sec; 47 rv += (double) val->tv_nsec / nSecsPerSec; 48 49 return rv; 50} 51 52// struct timeval to double 53double tv2double(const struct timeval *val) 54{ 55 double rv; 56 57 rv = val->tv_sec; 58 rv += (double) val->tv_usec / uSecsPerSec; 59 60 return rv; 61} 62 63// double to struct timespec 64struct timespec double2ts(double amt) 65{ 66 struct timespec rv; 67 68 rv.tv_sec = floor(amt); 69 rv.tv_nsec = (amt - rv.tv_sec) * nSecsPerSec; 70 // TODO: Handle cases where amt is negative 71 while ((unsigned) rv.tv_nsec >= nSecsPerSec) { 72 rv.tv_nsec -= nSecsPerSec; 73 rv.tv_sec++; 74 } 75 76 return rv; 77} 78 79// double to struct timeval 80struct timeval double2tv(double amt) 81{ 82 struct timeval rv; 83 84 rv.tv_sec = floor(amt); 85 rv.tv_usec = (amt - rv.tv_sec) * uSecsPerSec; 86 // TODO: Handle cases where amt is negative 87 while ((unsigned) rv.tv_usec >= uSecsPerSec) { 88 rv.tv_usec -= uSecsPerSec; 89 rv.tv_sec++; 90 } 91 92 return rv; 93} 94 95// Delta (difference) between two struct timespec. 96// It is expected that the time given by the structure pointed to by 97// second, is later than the time pointed to by first. 98struct timespec tsDelta(const struct timespec *first, 99 const struct timespec *second) 100{ 101 struct timespec rv; 102 103 assert(first != NULL); 104 assert(second != NULL); 105 assert(first->tv_nsec >= 0 && first->tv_nsec < nSecsPerSec); 106 assert(second->tv_nsec >= 0 && second->tv_nsec < nSecsPerSec); 107 rv.tv_sec = second->tv_sec - first->tv_sec; 108 if (second->tv_nsec >= first->tv_nsec) { 109 rv.tv_nsec = second->tv_nsec - first->tv_nsec; 110 } else { 111 rv.tv_nsec = (second->tv_nsec + nSecsPerSec) - first->tv_nsec; 112 rv.tv_sec--; 113 } 114 115 return rv; 116} 117 118// Delta (difference) between two struct timeval. 119// It is expected that the time given by the structure pointed to by 120// second, is later than the time pointed to by first. 121struct timeval tvDelta(const struct timeval *first, 122 const struct timeval *second) 123{ 124 struct timeval rv; 125 126 assert(first != NULL); 127 assert(second != NULL); 128 assert(first->tv_usec >= 0 && first->tv_usec < uSecsPerSec); 129 assert(second->tv_usec >= 0 && second->tv_usec < uSecsPerSec); 130 rv.tv_sec = second->tv_sec - first->tv_sec; 131 if (second->tv_usec >= first->tv_usec) { 132 rv.tv_usec = second->tv_usec - first->tv_usec; 133 } else { 134 rv.tv_usec = (second->tv_usec + uSecsPerSec) - first->tv_usec; 135 rv.tv_sec--; 136 } 137 138 return rv; 139} 140 141void testPrint(FILE *stream, const char *fmt, ...) 142{ 143 char line[MAXSTR]; 144 va_list args; 145 146 va_start(args, fmt); 147 vsnprintf(line, sizeof(line), fmt, args); 148 if (stream == stderr) { 149 LOG(LOG_ERROR, logCatTag, "%s", line); 150 } else { 151 LOG(LOG_INFO, logCatTag, "%s", line); 152 } 153 vfprintf(stream, fmt, args); 154 fputc('\n', stream); 155} 156 157// Set tag used while logging to the logcat error interface 158void testSetLogCatTag(const char *tag) 159{ 160 logCatTag = tag; 161} 162 163// Obtain pointer to current log to logcat error interface tag 164const char * testGetLogCatTag(void) 165{ 166 return logCatTag; 167} 168 169/* 170 * Random Modulus 171 * 172 * Pseudo randomly returns unsigned integer in the range [0, mod). 173 * 174 * Precondition: srand48() called to set the seed of 175 * the pseudo random number generator. 176 */ 177unsigned int testRandMod(unsigned int mod) 178{ 179 // Obtain the random value 180 uint32_t val = lrand48(); 181 182 /* 183 * The contents of individual bytes tend to be less than random 184 * across different seeds. For example, srand48(x) and 185 * srand48(x + n * 4) cause lrand48() to return the same sequence of 186 * least significant bits. For small mod values this can produce 187 * noticably non-random sequnces. For mod values of less than 2 188 * byte, will use the randomness from all the bytes. 189 */ 190 if (mod <= 0x10000) { 191 val = (val & 0xffff) ^ (val >> 16); 192 193 // If mod less than a byte, can further combine down to 194 // a single byte. 195 if (mod <= 0x100) { 196 val = (val & 0xff) ^ (val >> 8); 197 } 198 } 199 200 return val % mod; 201} 202 203/* 204 * Random Boolean 205 * 206 * Pseudo randomly returns 0 (false) or 1 (true). 207 * 208 * Precondition: srand48() called to set the seed of 209 * the pseudo random number generator. 210 */ 211int testRandBool(void) 212{ 213 return (testRandMod(2)); 214} 215 216/* 217 * Random Fraction 218 * 219 * Pseudo randomly return a value in the range [0.0, 1.0). 220 * 221 * Precondition: srand48() called to set the seed of 222 * the pseudo random number generator. 223 */ 224double testRandFract(void) 225{ 226 // TODO: use drand48(), after issue 2838717 has been fixed 227 return (double) lrand48() / (double) (1UL << 31); 228} 229 230// Delays for the number of seconds specified by amt or a greater amount. 231// The amt variable is of type float and thus non-integer amounts 232// of time can be specified. This function automatically handles cases 233// where nanosleep(2) returns early due to reception of a signal. 234void testDelay(float amt) 235{ 236 struct timespec start, current, delta; 237 struct timespec remaining; 238 239 // Get the time at which we started 240 clock_gettime(CLOCK_MONOTONIC, &start); 241 242 do { 243 // Get current time 244 clock_gettime(CLOCK_MONOTONIC, ¤t); 245 246 // How much time is left 247 delta = tsDelta(&start, ¤t); 248 if (ts2double(&delta) > amt) { break; } 249 250 // Request to sleep for the remaining time 251 remaining = double2ts(amt - ts2double(&delta)); 252 (void) nanosleep(&remaining, NULL); 253 } while (true); 254} 255 256/* 257 * Hex Dump 258 * 259 * Displays in hex the contents of the memory starting at the location 260 * pointed to by buf, for the number of bytes given by size. 261 * Each line of output is indented by a number of spaces that 262 * can be set by calling xDumpSetIndent(). It is also possible 263 * to offset the displayed address by an amount set by calling 264 * xDumpSetOffset. 265 */ 266static uint8_t xDumpIndent; 267static uint64_t xDumpOffset; 268void 269testXDump(const void *buf, size_t size) 270{ 271 const unsigned int bytesPerLine = 16; 272 int rv; 273 char line[MAXSTR]; 274 const unsigned char *ptr = buf, *start = buf; 275 size_t num = size; 276 char *linep = line; 277 278 while (num) { 279 if (((ptr - start) % bytesPerLine) == 0) { 280 if (linep != line) { 281 testPrintE("%s", line); 282 } 283 linep = line; 284 rv = snprintf(linep, ALEN(line) - (linep - line), 285 "%*s%06llx:", xDumpIndent, "", 286 (long long) (ptr - start) + xDumpOffset); 287 linep += rv; 288 } 289 290 // Check that there is at least room for 4 291 // more characters. The 4 characters being 292 // a space, 2 hex digits and the terminating 293 // '\0'. 294 assert((ALEN(line) - 4) >= (linep - line)); 295 rv = snprintf(linep, ALEN(line) - (linep - line), 296 " %02x", *ptr++); 297 linep += rv; 298 num--; 299 } 300 if (linep != line) { 301 testPrintE("%s", line); 302 } 303} 304 305// Set an indent of spaces for each line of hex dump output 306void 307testXDumpSetIndent(uint8_t indent) 308{ 309 xDumpIndent = indent; 310} 311 312// Obtain the current hex dump indent amount 313uint8_t 314testXDumpGetIndent(void) 315{ 316 return xDumpIndent; 317} 318 319// Set the hex dump address offset amount 320void 321testXDumpSetOffset(uint64_t offset) 322{ 323 xDumpOffset = offset; 324} 325 326// Get the current hex dump address offset amount 327uint64_t 328testXDumpGetOffset(void) 329{ 330 return xDumpOffset; 331} 332