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