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, &current);
245
246        // How much time is left
247        delta = tsDelta(&start, &current);
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