Home | History | Annotate | Download | only in testUtil
      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 <errno.h>
     22 #include <math.h>
     23 #include <stdarg.h>
     24 #include <stdint.h>
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <time.h>
     28 
     29 #include <sys/time.h>
     30 #include <sys/wait.h>
     31 
     32 #include <cutils/log.h>
     33 
     34 #define ALEN(a) (sizeof(a) / sizeof(a [0]))  // Array length
     35 typedef unsigned int bool_t;
     36 #define true (0 == 0)
     37 #define false (!true)
     38 
     39 #define MAXSTR 200
     40 
     41 static const char *logCatTag;
     42 static const unsigned int uSecsPerSec = 1000000;
     43 static const unsigned int nSecsPerSec = 1000000000;
     44 
     45 // struct timespec to double
     46 double ts2double(const struct timespec *val)
     47 {
     48     double rv;
     49 
     50     rv = val->tv_sec;
     51     rv += (double) val->tv_nsec / nSecsPerSec;
     52 
     53     return rv;
     54 }
     55 
     56 // struct timeval to double
     57 double tv2double(const struct timeval *val)
     58 {
     59     double rv;
     60 
     61     rv = val->tv_sec;
     62     rv += (double) val->tv_usec / uSecsPerSec;
     63 
     64     return rv;
     65 }
     66 
     67 // double to struct timespec
     68 struct timespec double2ts(double amt)
     69 {
     70     struct timespec rv;
     71 
     72     rv.tv_sec = floor(amt);
     73     rv.tv_nsec = (amt - rv.tv_sec) * nSecsPerSec;
     74     // TODO: Handle cases where amt is negative
     75     while ((unsigned) rv.tv_nsec >= nSecsPerSec) {
     76         rv.tv_nsec -= nSecsPerSec;
     77         rv.tv_sec++;
     78     }
     79 
     80     return rv;
     81 }
     82 
     83 // double to struct timeval
     84 struct timeval double2tv(double amt)
     85 {
     86     struct timeval rv;
     87 
     88     rv.tv_sec = floor(amt);
     89     rv.tv_usec = (amt - rv.tv_sec) * uSecsPerSec;
     90     // TODO: Handle cases where amt is negative
     91     while ((unsigned) rv.tv_usec >= uSecsPerSec) {
     92         rv.tv_usec -= uSecsPerSec;
     93         rv.tv_sec++;
     94     }
     95 
     96     return rv;
     97 }
     98 
     99 // Delta (difference) between two struct timespec.
    100 // It is expected that the time given by the structure pointed to by
    101 // second, is later than the time pointed to by first.
    102 struct timespec tsDelta(const struct timespec *first,
    103                         const struct timespec *second)
    104 {
    105     struct timespec rv;
    106 
    107     assert(first != NULL);
    108     assert(second != NULL);
    109     assert(first->tv_nsec >= 0 && first->tv_nsec < nSecsPerSec);
    110     assert(second->tv_nsec >= 0 && second->tv_nsec < nSecsPerSec);
    111     rv.tv_sec = second->tv_sec - first->tv_sec;
    112     if (second->tv_nsec >= first->tv_nsec) {
    113         rv.tv_nsec = second->tv_nsec - first->tv_nsec;
    114     } else {
    115         rv.tv_nsec = (second->tv_nsec + nSecsPerSec) - first->tv_nsec;
    116         rv.tv_sec--;
    117     }
    118 
    119     return rv;
    120 }
    121 
    122 // Delta (difference) between two struct timeval.
    123 // It is expected that the time given by the structure pointed to by
    124 // second, is later than the time pointed to by first.
    125 struct timeval tvDelta(const struct timeval *first,
    126                        const struct timeval *second)
    127 {
    128     struct timeval rv;
    129 
    130     assert(first != NULL);
    131     assert(second != NULL);
    132     assert(first->tv_usec >= 0 && first->tv_usec < uSecsPerSec);
    133     assert(second->tv_usec >= 0 && second->tv_usec < uSecsPerSec);
    134     rv.tv_sec = second->tv_sec - first->tv_sec;
    135     if (second->tv_usec >= first->tv_usec) {
    136         rv.tv_usec = second->tv_usec - first->tv_usec;
    137     } else {
    138         rv.tv_usec = (second->tv_usec + uSecsPerSec) - first->tv_usec;
    139         rv.tv_sec--;
    140     }
    141 
    142     return rv;
    143 }
    144 
    145 void testPrint(FILE *stream, const char *fmt, ...)
    146 {
    147     char line[MAXSTR];
    148     va_list args;
    149 
    150     va_start(args, fmt);
    151     vsnprintf(line, sizeof(line), fmt, args);
    152     if (stream == stderr) {
    153         ALOG(LOG_ERROR, logCatTag, "%s", line);
    154     } else {
    155         ALOG(LOG_INFO, logCatTag, "%s", line);
    156     }
    157     vfprintf(stream, fmt, args);
    158     fputc('\n', stream);
    159 }
    160 
    161 // Set tag used while logging to the logcat error interface
    162 void testSetLogCatTag(const char *tag)
    163 {
    164     logCatTag = tag;
    165 }
    166 
    167 // Obtain pointer to current log to logcat error interface tag
    168 const char * testGetLogCatTag(void)
    169 {
    170     return logCatTag;
    171 }
    172 
    173 /*
    174  * Random
    175  *
    176  * Returns a pseudo random number in the range [0:2^32-1].
    177  *
    178  * Precondition: srand48() called to set the seed of
    179  *   the pseudo random number generator.
    180  */
    181 uint32_t testRand(void)
    182 {
    183     uint32_t val;
    184 
    185     // Use lrand48() to obtain 31 bits worth
    186     // of randomness.
    187     val = lrand48();
    188 
    189     // Make an additional lrand48() call and merge
    190     // the randomness into the most significant bits.
    191     val ^= lrand48() << 1;
    192 
    193     return val;
    194 }
    195 
    196 /*
    197  * Random Modulus
    198  *
    199  * Pseudo randomly returns unsigned integer in the range [0, mod).
    200  *
    201  * Precondition: srand48() called to set the seed of
    202  *   the pseudo random number generator.
    203  */
    204 uint32_t testRandMod(uint32_t mod)
    205 {
    206     // Obtain the random value
    207     // Use lrand48() when it would produce a sufficient
    208     // number of random bits, otherwise use testRand().
    209     const uint32_t lrand48maxVal = ((uint32_t) 1 << 31) - 1;
    210     uint32_t val = (mod <= lrand48maxVal) ? (uint32_t) lrand48() : testRand();
    211 
    212     /*
    213      * The contents of individual bytes tend to be less than random
    214      * across different seeds.  For example, srand48(x) and
    215      * srand48(x + n * 4) cause lrand48() to return the same sequence of
    216      * least significant bits.  For small mod values this can produce
    217      * noticably non-random sequnces.  For mod values of less than 2
    218      * bytes, will use the randomness from all the bytes.
    219      */
    220     if (mod <= 0x10000) {
    221         val = (val & 0xffff) ^ (val >> 16);
    222 
    223         // If mod less than a byte, can further combine down to
    224         // a single byte.
    225         if (mod <= 0x100) {
    226             val = (val & 0xff) ^ (val >> 8);
    227         }
    228     }
    229 
    230     return val % mod;
    231 }
    232 
    233 /*
    234  * Random Boolean
    235  *
    236  * Pseudo randomly returns 0 (false) or 1 (true).
    237  *
    238  * Precondition: srand48() called to set the seed of
    239  *   the pseudo random number generator.
    240  */
    241 int testRandBool(void)
    242 {
    243     return (testRandMod(2));
    244 }
    245 
    246 /*
    247  * Random Fraction
    248  *
    249  * Pseudo randomly return a value in the range [0.0, 1.0).
    250  *
    251  * Precondition: srand48() called to set the seed of
    252  *   the pseudo random number generator.
    253  */
    254 double testRandFract(void)
    255 {
    256     return drand48();
    257 }
    258 
    259 // Delays for the number of seconds specified by amt or a greater amount.
    260 // The amt variable is of type float and thus non-integer amounts
    261 // of time can be specified.  This function automatically handles cases
    262 // where nanosleep(2) returns early due to reception of a signal.
    263 void testDelay(float amt)
    264 {
    265     struct timespec   start, current, delta;
    266     struct timespec   remaining;
    267 
    268     // Get the time at which we started
    269     clock_gettime(CLOCK_MONOTONIC, &start);
    270 
    271     do {
    272         // Get current time
    273         clock_gettime(CLOCK_MONOTONIC, &current);
    274 
    275         // How much time is left
    276         delta = tsDelta(&start, &current);
    277         if (ts2double(&delta) > amt) { break; }
    278 
    279         // Request to sleep for the remaining time
    280         remaining = double2ts(amt - ts2double(&delta));
    281         (void) nanosleep(&remaining, NULL);
    282     } while (true);
    283 }
    284 
    285 // Delay spins for the number of seconds specified by amt or a greater
    286 // amount.  The amt variable is of type float and thus non-integer amounts
    287 // of time can be specified.  Differs from testDelay() in that
    288 // testDelaySpin() performs a spin loop, instead of using nanosleep().
    289 void testDelaySpin(float amt)
    290 {
    291     struct timespec   start, current, delta;
    292 
    293     // Get the time at which we started
    294     clock_gettime(CLOCK_MONOTONIC, &start);
    295 
    296     do {
    297         // Get current time
    298         clock_gettime(CLOCK_MONOTONIC, &current);
    299 
    300         // How much time is left
    301         delta = tsDelta(&start, &current);
    302         if (ts2double(&delta) > amt) { break; }
    303     } while (true);
    304 }
    305 
    306 /*
    307  * Hex Dump
    308  *
    309  * Displays in hex the contents of the memory starting at the location
    310  * pointed to by buf, for the number of bytes given by size.
    311  * Each line of output is indented by a number of spaces that
    312  * can be set by calling xDumpSetIndent().  It is also possible
    313  * to offset the displayed address by an amount set by calling
    314  * xDumpSetOffset.
    315  */
    316 static uint8_t     xDumpIndent;
    317 static uint64_t    xDumpOffset;
    318 void
    319 testXDump(const void *buf, size_t size)
    320 {
    321     const unsigned int bytesPerLine = 16;
    322     int rv;
    323     char line[MAXSTR];
    324     const unsigned char *ptr = buf, *start = buf;
    325     size_t num = size;
    326     char *linep = line;
    327 
    328     while (num) {
    329         if (((ptr - start) % bytesPerLine) == 0) {
    330             if (linep != line) {
    331                 testPrintE("%s", line);
    332             }
    333             linep = line;
    334             rv = snprintf(linep, ALEN(line) - (linep - line),
    335                 "%*s%06llx:", xDumpIndent, "",
    336                 (long long) (ptr - start) + xDumpOffset);
    337             linep += rv;
    338         }
    339 
    340         // Check that there is at least room for 4
    341         // more characters.  The 4 characters being
    342         // a space, 2 hex digits and the terminating
    343         // '\0'.
    344         assert((ALEN(line) - 4) >= (linep - line));
    345         rv = snprintf(linep, ALEN(line) - (linep - line),
    346             " %02x", *ptr++);
    347         linep += rv;
    348         num--;
    349     }
    350     if (linep != line) {
    351         testPrintE("%s", line);
    352     }
    353 }
    354 
    355 // Set an indent of spaces for each line of hex dump output
    356 void
    357 testXDumpSetIndent(uint8_t indent)
    358 {
    359     xDumpIndent = indent;
    360 }
    361 
    362 // Obtain the current hex dump indent amount
    363 uint8_t
    364 testXDumpGetIndent(void)
    365 {
    366     return xDumpIndent;
    367 }
    368 
    369 // Set the hex dump address offset amount
    370 void
    371 testXDumpSetOffset(uint64_t offset)
    372 {
    373     xDumpOffset = offset;
    374 }
    375 
    376 // Get the current hex dump address offset amount
    377 uint64_t
    378 testXDumpGetOffset(void)
    379 {
    380     return xDumpOffset;
    381 }
    382 
    383 /*
    384  * Execute Command
    385  *
    386  * Executes the command pointed to by cmd.  Output from the
    387  * executed command is captured and sent to LogCat Info.  Once
    388  * the command has finished execution, it's exit status is captured
    389  * and checked for an exit status of zero.  Any other exit status
    390  * causes diagnostic information to be printed and an immediate
    391  * testcase failure.
    392  */
    393 void testExecCmd(const char *cmd)
    394 {
    395     FILE *fp;
    396     int rv;
    397     int status;
    398     char str[MAXSTR];
    399 
    400     // Display command to be executed
    401     testPrintI("cmd: %s", cmd);
    402 
    403     // Execute the command
    404     fflush(stdout);
    405     if ((fp = popen(cmd, "r")) == NULL) {
    406         testPrintE("execCmd popen failed, errno: %i", errno);
    407         exit(100);
    408     }
    409 
    410     // Obtain and display each line of output from the executed command
    411     while (fgets(str, sizeof(str), fp) != NULL) {
    412         if ((strlen(str) > 1) && (str[strlen(str) - 1] == '\n')) {
    413             str[strlen(str) - 1] = '\0';
    414         }
    415         testPrintI(" out: %s", str);
    416     }
    417 
    418     // Obtain and check return status of executed command.
    419     // Fail on non-zero exit status
    420     status = pclose(fp);
    421     if (!(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) {
    422         testPrintE("Unexpected command failure");
    423         testPrintE("  status: %#x", status);
    424         if (WIFEXITED(status)) {
    425             testPrintE("WEXITSTATUS: %i", WEXITSTATUS(status));
    426         }
    427         if (WIFSIGNALED(status)) {
    428             testPrintE("WTERMSIG: %i", WTERMSIG(status));
    429         }
    430         exit(101);
    431     }
    432 }
    433