commit | 79249b0897016cdcd1344f4c5e8876fbf433de3e | [log] [tgz] |
---|---|---|
author | Mark Salyzyn <salyzyn@google.com> | Tue Nov 07 08:19:20 2017 -0800 |
committer | Mark Salyzyn <salyzyn@google.com> | Thu Dec 07 09:41:48 2017 -0800 |
tree | 6b7a479b3a82507a0070777d1be3e6fa73b78cc3 | |
parent | 6f9c35ded294ca7b0b8f9042f705cbfca1ec8518 [diff] |
bionic: add vdso clock_getres clock_getres() should not be a hot call, nevertheless it is ~6-7 times faster for supported clock ids if it uses __vdso_clock_getres if available. There is a 3% performance penalty for unsupported clock ids via __vdso_clock_getres with respect to a direct syscall. [TL;DR] w/vdso32 kernel patches, locked cores to MAX, little cores only. BEFORE: hikey960 vdso (aarch64): ---------------------------------------------------------------------- Benchmark Time CPU Iterations ---------------------------------------------------------------------- BM_time_clock_getres 126 ns 126 ns 5577874 BM_time_clock_getres_syscall 127 ns 127 ns 5505016 BM_time_clock_getres_REALTIME 126 ns 126 ns 5574682 BM_time_clock_getres_BOOTTIME 126 ns 126 ns 5575237 BM_time_clock_getres_TAI 126 ns 126 ns 5576810 BM_time_clock_getres_unsupported 128 ns 128 ns 5480189 hikey960 vdso32 (aarch32): ---------------------------------------------------------------------- Benchmark Time CPU Iterations ---------------------------------------------------------------------- BM_time_clock_getres 199 ns 199 ns 3508708 BM_time_clock_getres_syscall 220 ns 220 ns 3184676 BM_time_clock_getres_REALTIME 199 ns 199 ns 3509697 BM_time_clock_getres_BOOTTIME 199 ns 199 ns 3513551 BM_time_clock_getres_TAI 200 ns 199 ns 3512412 BM_time_clock_getres_unsupported 196 ns 196 ns 3575609 x86_64 (glibc): --------------------------------------------------------------------- Benchmark Time CPU Iterations --------------------------------------------------------------------- BM_time_clock_getres 252 ns 252 ns 2370263 BM_time_clock_getres_syscall 215 ns 215 ns 3287497 BM_time_clock_getres_REALTIME 214 ns 214 ns 3294228 BM_time_clock_getres_BOOTTIME 213 ns 213 ns 3277519 BM_time_clock_getres_TAI 213 ns 213 ns 3294991 BM_time_clock_getres_unsupported 206 ns 206 ns 3450654 imx7d_pico IOT nyc (w/arm,cpu-registers-not-fw-configured) (armv7a): (Virtual Timers) Benchmark Time(ns) CPU(ns) Iterations ------------------------------------------------------------------ BM_time_clock_getres 16 345 2000000 BM_time_clock_getres_syscall 16 339 2121212 BM_time_clock_getres_REALTIME 17 350 2058824 BM_time_clock_getres_BOOTTIME 17 345 2000000 BM_time_clock_getres_TAI 16 350 2000000 BM_time_clock_getres_unsupported 13 284 2500000 AFTER: hikey960 vdso (aarch64): --------------------------------------------------------------------- Benchmark Time CPU Iterations --------------------------------------------------------------------- BM_time_clock_getres 18 ns 18 ns 37880389 BM_time_clock_getres_syscall 127 ns 127 ns 5520029 BM_time_clock_getres_REALTIME 18 ns 18 ns 37879962 BM_time_clock_getres_BOOTTIME 19 ns 18 ns 37878361 BM_time_clock_getres_TAI 131 ns 131 ns 5368484 BM_time_clock_getres_unsupported 97 ns 97 ns 7182864 hikey960 vdso32 (aarch32): --------------------------------------------------------------------- Benchmark Time CPU Iterations --------------------------------------------------------------------- BM_time_clock_getres 36 ns 36 ns 19205240 BM_time_clock_getres_syscall 212 ns 212 ns 3297100 BM_time_clock_getres_REALTIME 36 ns 36 ns 19219109 BM_time_clock_getres_BOOTTIME 36 ns 36 ns 19222490 BM_time_clock_getres_TAI 206 ns 206 ns 3402868 BM_time_clock_getres_unsupported 159 ns 159 ns 4409492 imx7d_pico IOT nyc (wo/arm,cpu-registers-not-fw-configured) (armv7a): (Physical Timers) Benchmark Time(ns) CPU(ns) Iterations ------------------------------------------------------------------ BM_time_clock_getres 2 48 14000000 BM_time_clock_getres_syscall 14 335 2058824 BM_time_clock_getres_REALTIME 2 49 14583333 BM_time_clock_getres_BOOTTIME 2 48 14000000 BM_time_clock_getres_TAI 14 350 2058824 BM_time_clock_getres_unsupported 8 203 3500000 Test: taskset F \ /data/benchmarktest{64}/bionic-benchmarks/bionic-benchmarks \ --bionic_xml=vdso.xml --benchmark_filter=BM_time_clock_getres* Bug: 63737556 Change-Id: I80c0a5106625d76720287f715fcf145d2aad1705
See the additional documentation.
The C library. Stuff like fopen(3)
and kill(2)
.
The math library. Traditionally Unix systems kept stuff like sin(3)
and cos(3)
in a separate library to save space in the days before shared libraries.
The dynamic linker interface library. This is actually just a bunch of stubs that the dynamic linker replaces with pointers to its own implementation at runtime. This is where stuff like dlopen(3)
lives.
The C++ ABI support functions. The C++ compiler doesn't know how to implement thread-safe static initialization and the like, so it just calls functions that are supplied by the system. Stuff like __cxa_guard_acquire
and __cxa_pure_virtual
live here.
The dynamic linker. When you run a dynamically-linked executable, its ELF file has a DT_INTERP
entry that says "use the following program to start me". On Android, that's either linker
or linker64
(depending on whether it's a 32-bit or 64-bit executable). It's responsible for loading the ELF executable into memory and resolving references to symbols (so that when your code tries to jump to fopen(3)
, say, it lands in the right place).
The tests/
directory contains unit tests. Roughly arranged as one file per publicly-exported header file.
The benchmarks/
directory contains benchmarks, with its own documentation.
Adding a system call usually involves:
./libc/tools/genversion-scripts.py
.As mentioned above, this is currently a two-step process:
Note that if you're actually just trying to expose device-specific headers to build your device drivers, you shouldn't modify bionic. Instead use TARGET_DEVICE_KERNEL_HEADERS
and friends described in config.mk.
This is fully automated (and these days handled by the libcore team, because they own icu, and that needs to be updated in sync with bionic):
If you make a change that is likely to have a wide effect on the tree (such as a libc header change), you should run make checkbuild
. A regular make
will not build the entire tree; just the minimum number of projects that are required for the device. Tests, additional developer tools, and various other modules will not be built. Note that make checkbuild
will not be complete either, as make tests
covers a few additional modules, but generally speaking make checkbuild
is enough.
The tests are all built from the tests/ directory.
$ mma # In $ANDROID_ROOT/bionic. $ adb root && adb remount && adb sync $ adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests $ adb shell \ /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static # Only for 64-bit targets $ adb shell /data/nativetest64/bionic-unit-tests/bionic-unit-tests $ adb shell \ /data/nativetest64/bionic-unit-tests-static/bionic-unit-tests-static
Note that we use our own custom gtest runner that offers a superset of the options documented at https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#running-test-programs-advanced-options, in particular for test isolation and parallelism (both on by default).
Most of the unit tests are executed by CTS. By default, CTS runs as a non-root user, so the unit tests must also pass when not run as root. Some tests cannot do any useful work unless run as root. In this case, the test should check getuid() == 0
and do nothing otherwise (typically we log in this case to prevent accidents!). Obviously, if the test can be rewritten to not require root, that's an even better solution.
Currently, the list of bionic CTS tests is generated at build time by running a host version of the test executable and dumping the list of all tests. In order for this to continue to work, all architectures must have the same number of tests, and the host version of the executable must also have the same number of tests.
Running the gtests directly is orders of magnitude faster than using CTS, but in cases where you really have to run CTS:
$ make cts # In $ANDROID_ROOT. $ adb unroot # Because real CTS doesn't run as root. # This will sync any *test* changes, but not *code* changes: $ cts-tradefed \ run singleCommand cts --skip-preconditions -m CtsBionicTestCases
The host tests require that you have lunch
ed either an x86 or x86_64 target. Note that due to ABI limitations (specifically, the size of pthread_mutex_t), 32-bit bionic requires PIDs less than 65536. To enforce this, set /proc/sys/kernel/pid_max to 65536.
$ ./tests/run-on-host.sh 32 $ ./tests/run-on-host.sh 64 # For x86_64-bit *targets* only.
You can supply gtest flags as extra arguments to this script.
As a way to check that our tests do in fact test the correct behavior (and not just the behavior we think is correct), it is possible to run the tests against the host's glibc.
$ ./tests/run-on-host.sh glibc
For either host or target coverage, you must first:
$ export NATIVE_COVERAGE=true
bionic_coverage=true
in libc/Android.mk
and libm/Android.mk
.$ mma $ adb sync $ adb shell \ GCOV_PREFIX=/data/local/tmp/gcov \ GCOV_PREFIX_STRIP=`echo $ANDROID_BUILD_TOP | grep -o / | wc -l` \ /data/nativetest/bionic-unit-tests/bionic-unit-tests $ acov
acov
will pull all coverage information from the device, push it to the right directories, run lcov
, and open the coverage report in your browser.
First, build and run the host tests as usual (see above).
$ croot $ lcov -c -d $ANDROID_PRODUCT_OUT -o coverage.info $ genhtml -o covreport coverage.info # or lcov --list coverage.info
The coverage report is now available at covreport/index.html
.
Bionic's test runner will run each test in its own process by default to prevent tests failures from impacting other tests. This also has the added benefit of running them in parallel, so they are much faster.
However, this also makes it difficult to run the tests under GDB. To prevent each test from being forked, run the tests with the flag --no-isolate
.
See 32-bit ABI bugs.