• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
ts2double(const struct timespec * val)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
tv2double(const struct timeval * val)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
double2ts(double amt)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
double2tv(double amt)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.
tsDelta(const struct timespec * first,const struct timespec * second)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.
tvDelta(const struct timeval * first,const struct timeval * second)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  
testPrint(FILE * stream,const char * fmt,...)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
testSetLogCatTag(const char * tag)162  void testSetLogCatTag(const char *tag)
163  {
164      logCatTag = tag;
165  }
166  
167  // Obtain pointer to current log to logcat error interface tag
testGetLogCatTag(void)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   */
testRand(void)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   */
testRandMod(uint32_t mod)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   */
testRandBool(void)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   */
testRandFract(void)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.
testDelay(float amt)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().
testDelaySpin(float amt)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
testXDump(const void * buf,size_t size)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
testXDumpSetIndent(uint8_t indent)357  testXDumpSetIndent(uint8_t indent)
358  {
359      xDumpIndent = indent;
360  }
361  
362  // Obtain the current hex dump indent amount
363  uint8_t
testXDumpGetIndent(void)364  testXDumpGetIndent(void)
365  {
366      return xDumpIndent;
367  }
368  
369  // Set the hex dump address offset amount
370  void
testXDumpSetOffset(uint64_t offset)371  testXDumpSetOffset(uint64_t offset)
372  {
373      xDumpOffset = offset;
374  }
375  
376  // Get the current hex dump address offset amount
377  uint64_t
testXDumpGetOffset(void)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   */
testExecCmd(const char * cmd)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