diff options
author | Jean-Baptiste Queru <jbq@google.com> | 2009-07-25 17:48:03 -0700 |
---|---|---|
committer | Jean-Baptiste Queru <jbq@google.com> | 2009-07-25 17:48:03 -0700 |
commit | e92807b964bef9b003f39ae1c3be6bf379f148dd (patch) | |
tree | 7897f601a22692f33a69ff9ce9f5fbd07b27dc91 | |
parent | 1f6b24cf6ead1186657d5fe93e88eb868f8a7bcc (diff) | |
parent | 360efc12dcfece46e5999505bd8042cba56a4289 (diff) | |
download | extras-e92807b964bef9b003f39ae1c3be6bf379f148dd.tar.gz |
Merge korg/donut into korg/master
42 files changed, 3987 insertions, 38 deletions
diff --git a/backup/Android.mk b/backup/Android.mk index 6a3d3fee..b5803905 100644 --- a/backup/Android.mk +++ b/backup/Android.mk @@ -7,7 +7,7 @@ LOCAL_SRC_FILES:= backup.cpp LOCAL_SHARED_LIBRARIES := libcutils libc -LOCAL_MODULE:= backup +LOCAL_MODULE:= rawbu LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) LOCAL_MODULE_TAGS := debug diff --git a/backup/backup.cpp b/backup/backup.cpp index 48f64eec..22c016d7 100644 --- a/backup/backup.cpp +++ b/backup/backup.cpp @@ -591,10 +591,21 @@ done: static void show_help(const char *cmd) { - fprintf(stderr,"Usage: %s [options] [backup-file-path]\n", cmd); + fprintf(stderr,"Usage: %s COMMAND [options] [backup-file-path]\n", cmd); + fprintf(stderr, "commands are:\n" + " help Show this help text.\n" + " backup Perform a backup of /data.\n" + " restore Perform a restore of /data.\n"); fprintf(stderr, "options include:\n" - " -r Perform restore of previous backup.\n"); + " -h Show this help text.\n"); + fprintf(stderr, "\nThe %s command allows you to perform low-level\n" + "backup and restore of the /data partition. This is\n" + "where all user data is kept, allowing for a fairly\n" + "complete restore of a device's state. Note that\n" + "because this is low-level, it will only work across\n" + "builds of the same (or very similar) device software.\n", + cmd); } } /* namespace android */ @@ -607,24 +618,39 @@ int main (int argc, char **argv) fprintf(stderr, "error -- %s must run as root\n", argv[0]); exit(-1); } - - if (argc == 2 && 0 == strcmp(argv[1], "--help")) { + + if (argc < 2) { + fprintf(stderr, "No command specified.\n"); + android::show_help(argv[0]); + exit(-1); + } + + if (0 == strcmp(argv[1], "restore")) { + restore = 1; + } else if (0 == strcmp(argv[1], "help")) { android::show_help(argv[0]); exit(0); + } else if (0 != strcmp(argv[1], "backup")) { + fprintf(stderr, "Unknown command: %s\n", argv[1]); + android::show_help(argv[0]); + exit(-1); } + optind = 2; + for (;;) { int ret; - ret = getopt(argc, argv, "r"); + ret = getopt(argc, argv, "h"); if (ret < 0) { break; } switch(ret) { - case 'r': - restore = 1; + case 'h': + android::show_help(argv[0]); + exit(0); break; default: diff --git a/showmap/showmap.c b/showmap/showmap.c index 4abd56a8..2a028eea 100644 --- a/showmap/showmap.c +++ b/showmap/showmap.c @@ -77,8 +77,11 @@ again: if(sscanf(line, "Private_Clean: %d kB", &mi->private_clean) != 1) goto oops; if(fgets(line, 1024, fp) == 0) goto oops; if(sscanf(line, "Private_Dirty: %d kB", &mi->private_dirty) != 1) goto oops; - if(fgets(line, 1024, fp) == 0) goto oops; - if(fgets(line, 1024, fp) == 0) goto oops; + + if(fgets(line, 1024, fp) == 0) goto oops; // Referenced + if(fgets(line, 1024, fp) == 0) goto oops; // Swap + if(fgets(line, 1024, fp) == 0) goto oops; // KernelPageSize + if(fgets(line, 1024, fp) == 0) goto oops; // MMUPageSize if(skip) { free(mi); diff --git a/sound/Android.mk b/sound/Android.mk index 7a58998b..62174ccf 100644 --- a/sound/Android.mk +++ b/sound/Android.mk @@ -3,6 +3,6 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := sound LOCAL_SRC_FILES := playwav.c -LOCAL_MODULE_TAGS := tests +LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) diff --git a/tests/bionic/libc/Android.mk b/tests/bionic/libc/Android.mk index 89d9ade2..4e4bcc64 100644 --- a/tests/bionic/libc/Android.mk +++ b/tests/bionic/libc/Android.mk @@ -30,6 +30,7 @@ define device-test $(eval include $(CLEAR_VARS)) \ $(eval LOCAL_SRC_FILES := $(file)) \ $(eval LOCAL_MODULE := $(notdir $(file:%.c=%))) \ + $(eval LOCAL_MODULE := $(LOCAL_MODULE:%.cpp=%)) \ $(eval $(info LOCAL_MODULE=$(LOCAL_MODULE))) \ $(eval LOCAL_CFLAGS += $(EXTRA_CFLAGS)) \ $(eval LOCAL_MODULE_TAGS := tests) \ @@ -46,6 +47,7 @@ define host-test $(eval include $(CLEAR_VARS)) \ $(eval LOCAL_SRC_FILES := $(file)) \ $(eval LOCAL_MODULE := $(notdir $(file:%.c=%))) \ + $(eval LOCAL_MODULE := $(LOCAL_MODULE:%.cpp=%)) \ $(eval $(info LOCAL_MODULE=$(LOCAL_MODULE) file=$(file))) \ $(eval LOCAL_CFLAGS += $(EXTRA_CFLAGS)) \ $(eval LOCAL_LDLIBS += $(EXTRA_LDLIBS)) \ @@ -59,6 +61,7 @@ endef # First, the tests in 'common' sources := \ + common/test_getaddrinfo.c \ common/test_gethostbyname.c \ common/test_gethostname.c \ common/test_pthread_cleanup_push.c \ @@ -127,6 +130,23 @@ LOCAL_MODULE := test_relocs LOCAL_SHARED_LIBRARIES := libtest_relocs include $(BUILD_EXECUTABLE) +# This test tries to see if the static constructors in a +# shared library are only called once. We thus need to +# build a shared library, then call it from another +# program. +# +include $(CLEAR_VARS) +LOCAL_SRC_FILES := bionic/lib_static_init.cpp +LOCAL_MODULE := libtest_static_init +LOCAL_PRELINK_MODULE := false +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := bionic/test_static_init.cpp +LOCAL_MODULE := test_static_init +LOCAL_SHARED_LIBRARIES := libtest_static_init +include $(BUILD_EXECUTABLE) + # TODO: Add a variety of GLibc test programs too... # Hello World to test libstdc++ support diff --git a/tests/bionic/libc/README.TXT b/tests/bionic/libc/README.TXT index 5576b77b..7618f2b7 100644 --- a/tests/bionic/libc/README.TXT +++ b/tests/bionic/libc/README.TXT @@ -7,7 +7,7 @@ GNU Lesser General Public License (LGPL) You must define the BIONIC_TESTS environment variable to build these test programs. For example, do: - cd system/bionic-tests/ + cd system/extras/tests/bionic/libc mm BIONIC_TESTS=1 All test programs, except those in the 'other' directory, should exit diff --git a/tests/bionic/libc/bionic/lib_static_init.cpp b/tests/bionic/libc/bionic/lib_static_init.cpp new file mode 100644 index 00000000..d847110a --- /dev/null +++ b/tests/bionic/libc/bionic/lib_static_init.cpp @@ -0,0 +1,18 @@ +#include "lib_static_init.h" +#include <stdio.h> + +Foo::Foo() +{ + /* increment the static variable */ + value = ++Foo::counter; + fprintf(stderr, "Foo::Foo for this=%p called (counter = %d)\n", this, counter); +} + +int Foo::getValue() +{ + return value; +} + +int Foo::counter; + +Foo theFoo; diff --git a/tests/bionic/libc/bionic/lib_static_init.h b/tests/bionic/libc/bionic/lib_static_init.h new file mode 100644 index 00000000..f455de8e --- /dev/null +++ b/tests/bionic/libc/bionic/lib_static_init.h @@ -0,0 +1,15 @@ +#ifndef _lib_static_init_h +#define _lib_static_init_h + +class Foo { +private: + int value; + static int counter; +public: + virtual int getValue(); + Foo(); +}; + +extern Foo theFoo; + +#endif /* _lib_static_init_h */ diff --git a/tests/bionic/libc/bionic/test_static_init.cpp b/tests/bionic/libc/bionic/test_static_init.cpp new file mode 100644 index 00000000..cbc4a59d --- /dev/null +++ b/tests/bionic/libc/bionic/test_static_init.cpp @@ -0,0 +1,30 @@ +#include <stdlib.h> +#include <stdio.h> +#include "lib_static_init.h" + +Foo theFoo2; + +int main(int argc, char** argv) +{ + int c = theFoo.getValue(); + + /* check the counter on the library object + * it must have been called first, and only once + */ + if (c != 1) { + printf("KO (counter(shared) == %d, expected 1)\n", c); + return 1; + } + + /* check the counter on the executable object, + * it must have been called second, and only once + */ + c = theFoo2.getValue(); + if (c != 2) { + printf("KO (counter(executable) == %d, expected 2)\n", c); + return 1; + } + + printf("OK\n"); + return 0; +} diff --git a/tests/bionic/libc/common/test_getaddrinfo.c b/tests/bionic/libc/common/test_getaddrinfo.c new file mode 100644 index 00000000..444bef8e --- /dev/null +++ b/tests/bionic/libc/common/test_getaddrinfo.c @@ -0,0 +1,44 @@ +/* this program is used to test that getaddrinfo() works correctly + * without a 'hints' argument + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> + +#include <stdio.h> /* for printf */ +#include <string.h> /* for memset */ +#include <netinet/in.h> /* for IPPROTO_TCP */ + +#define SERVER_NAME "www.android.com" +#define PORT_NUMBER "9999" + +int main(void) +{ + struct addrinfo hints; + struct addrinfo* res; + int ret; + + /* first, try without any hints */ + ret = getaddrinfo( SERVER_NAME, PORT_NUMBER, NULL, &res); + if (ret != 0) { + printf("first getaddrinfo returned error: %s\n", gai_strerror(ret)); + return 1; + } + + freeaddrinfo(res); + + /* now try with the hints */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + ret = getaddrinfo( SERVER_NAME, PORT_NUMBER, &hints, &res ); + if (ret != 0) { + printf("second getaddrinfo returned error: %s\n", gai_strerror(ret)); + return 1; + } + + return 0; +} diff --git a/tests/bionic/libstdc++/Android.mk b/tests/bionic/libstdc++/Android.mk new file mode 100644 index 00000000..103b3274 --- /dev/null +++ b/tests/bionic/libstdc++/Android.mk @@ -0,0 +1,80 @@ +# Copyright (C) 2009 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Build control file for Bionic's test programs +# define the BIONIC_TESTS environment variable to build the test programs +# + +ifdef BIONIC_TESTS + +LOCAL_PATH:= $(call my-dir) + +# used to define a simple test program and build it as a standalone +# device executable. +# +# you can use EXTRA_CFLAGS to indicate additional CFLAGS to use +# in the build. the variable will be cleaned on exit +# +define device-test + $(foreach file,$(1), \ + $(eval include $(CLEAR_VARS)) \ + $(eval LOCAL_SRC_FILES := $(file)) \ + $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ + $(eval $(info LOCAL_MODULE=$(LOCAL_MODULE))) \ + $(eval LOCAL_CFLAGS += $(EXTRA_CFLAGS)) \ + $(eval LOCAL_MODULE_TAGS := tests) \ + $(eval include $(BUILD_EXECUTABLE)) \ + ) \ + $(eval EXTRA_CFLAGS :=) +endef + +# same as 'device-test' but builds a host executable instead +# you can use EXTRA_LDLIBS to indicate additional linker flags +# +define host-test + $(foreach file,$(1), \ + $(eval include $(CLEAR_VARS)) \ + $(eval LOCAL_SRC_FILES := $(file)) \ + $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ + $(eval $(info LOCAL_MODULE=$(LOCAL_MODULE) file=$(file))) \ + $(eval LOCAL_CFLAGS += $(EXTRA_CFLAGS)) \ + $(eval LOCAL_LDLIBS += $(EXTRA_LDLIBS)) \ + $(eval LOCAL_MODULE_TAGS := tests) \ + $(eval include $(BUILD_HOST_EXECUTABLE)) \ + ) \ + $(eval EXTRA_CFLAGS :=) \ + $(eval EXTRA_LDLIBS :=) +endef + +sources := \ + test_cassert.cpp \ + test_cctype.cpp \ + test_climits.cpp \ + test_cmath.cpp \ + test_csetjmp.cpp \ + test_csignal.cpp \ + test_cstddef.cpp \ + test_cstdint.cpp \ + test_cstdio.cpp \ + test_cstdlib.cpp \ + test_cstring.cpp \ + test_ctime.cpp + +EXTRA_CFLAGS := -I bionic/libstdc++/include +$(call host-test, $(sources)) + +EXTRA_CFLAGS := -I bionic/libstdc++/include +$(call device-test, $(sources)) + +endif # BIONIC_TESTS diff --git a/tests/bionic/libstdc++/README.TXT b/tests/bionic/libstdc++/README.TXT new file mode 100644 index 00000000..aa7f8a46 --- /dev/null +++ b/tests/bionic/libstdc++/README.TXT @@ -0,0 +1,19 @@ +This directory contains a set of tests for Android's Bionic Standard C++ library. + +You must define the BIONIC_TESTS environment variable to build these +test programs. For example, do: + + cd system/extras/tests/bionic/libstdc++ + mm BIONIC_TESTS=1 + +Preferably, to build and run you can use this: + + runtest_py libstdcpp + +All test programs should exit with a status code of 0 in case of success, and 1 +in case of failure. + +The directory layout is currently flat because there is one Bionic test. If you +want to add GNU STDC++ or benchmark tests, look in tests/bionic/libc as an +example how to structure your files. + diff --git a/tests/bionic/libstdc++/test_cassert.cpp b/tests/bionic/libstdc++/test_cassert.cpp new file mode 100644 index 00000000..67c96deb --- /dev/null +++ b/tests/bionic/libstdc++/test_cassert.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include <cassert> +#ifndef BIONIC_LIBSTDCPP_INCLUDE_CASSERT__ +#error "Wrong header file included!!" +#endif + +namespace { +const int kPassed = 0; +} // anonymous namespace + +namespace android +{ +#ifndef assert +#error "assert must be a macro" +#endif +} // android namespace + +int main(int argc, char **argv) +{ + return kPassed; +} diff --git a/tests/bionic/libstdc++/test_cctype.cpp b/tests/bionic/libstdc++/test_cctype.cpp new file mode 100644 index 00000000..bedb77fb --- /dev/null +++ b/tests/bionic/libstdc++/test_cctype.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <cctype> +#ifndef BIONIC_LIBSTDCPP_INCLUDE_CCTYPE__ +#error "Wrong header file included!!" +#endif + + +namespace { +const int kPassed = 0; +} // anonymous namespace + +namespace android +{ +#ifdef isalnum +#error "should be a real function" +#endif +#ifdef isalpha +#error "should be a real function" +#endif +#ifdef iscntrl +#error "should be a real function" +#endif +#ifdef isdigit +#error "should be a real function" +#endif +#ifdef isgraph +#error "should be a real function" +#endif +#ifdef islower +#error "should be a real function" +#endif +#ifdef isprint +#error "should be a real function" +#endif +#ifdef ispunct +#error "should be a real function" +#endif +#ifdef isspace +#error "should be a real function" +#endif +#ifdef isupper +#error "should be a real function" +#endif +#ifdef isxdigit +#error "should be a real function" +#endif +#ifdef tolower +#error "should be a real function" +#endif +#ifdef toupper +#error "should be a real function" +#endif + +using std::isalnum; +using std::isdigit; +using std::isprint; +using std::isupper; +using std::tolower; +using std::isalpha; +using std::isgraph; +using std::ispunct; +using std::isxdigit; +using std::toupper; +using std::iscntrl; +using std::islower; +using std::isspace; + +} // namespace android + +int main(int argc, char **argv) +{ + return kPassed; +} diff --git a/tests/bionic/libstdc++/test_climits.cpp b/tests/bionic/libstdc++/test_climits.cpp new file mode 100644 index 00000000..f3ce0232 --- /dev/null +++ b/tests/bionic/libstdc++/test_climits.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include <climits> +#ifndef BIONIC_LIBSTDCPP_INCLUDE_CLIMITS__ +#error "Wrong header file included!!" +#endif + + +namespace { +const int kPassed = 0; +const int kFailed = 1; +#define FAIL_UNLESS(f) if (!android::f()) return kFailed; +} // anonymous namespace + +namespace android +{ +bool testLimits() +{ + // char + volatile char c1 = CHAR_BIT; + volatile char c2 = CHAR_MAX; + volatile char c3 = CHAR_MIN; + + // int + volatile int i1 = INT_MAX; + volatile int i2 = INT_MIN; + + // short + volatile short s1 = SHRT_MAX; + volatile short s2 = SHRT_MIN; + + // long + volatile long l1 = LONG_MAX; + volatile long l2 = LONG_MIN; + + // long long + volatile long long ll1 = LLONG_MAX; + volatile long long ll2 = LLONG_MIN; + + volatile unsigned long mb = MB_LEN_MAX; + + // signed char + volatile signed char sc1 = SCHAR_MIN; + volatile signed char sc2 = SCHAR_MAX; + + // unsigned + volatile unsigned int ui = UINT_MAX; + volatile unsigned short us = USHRT_MAX; + volatile unsigned long ul = ULONG_MAX; + volatile unsigned long long ull = ULLONG_MAX; + + return true; +} + +} // namespace android + +int main(int argc, char **argv) +{ + FAIL_UNLESS(testLimits); + return kPassed; +} diff --git a/tests/bionic/libstdc++/test_cmath.cpp b/tests/bionic/libstdc++/test_cmath.cpp new file mode 100644 index 00000000..438fb649 --- /dev/null +++ b/tests/bionic/libstdc++/test_cmath.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <cmath> +#ifndef BIONIC_LIBSTDCPP_INCLUDE_CMATH__ +#error "Wrong header file included!!" +#endif + + +namespace { +const int kPassed = 0; +const int kFailed = 1; +#define FAIL_UNLESS(f) if (!android::f()) return kFailed; +} // anonymous namespace + +namespace android +{ +using ::cos; +using ::sin; +using ::tan; +using ::acos; +using ::asin; +using ::atan; +using ::atan2; + +using ::cosh; +using ::sinh; +using ::tanh; + +using ::exp; +using ::frexp; +using ::ldexp; +using ::log; +using ::log10; +using ::modf; + +using ::pow; +using ::sqrt; + +using ::ceil; +using ::fabs; +using ::floor; +using ::fmod; + +} // namespace android + +int main(int argc, char **argv) +{ + return kPassed; +} diff --git a/tests/bionic/libstdc++/test_csetjmp.cpp b/tests/bionic/libstdc++/test_csetjmp.cpp new file mode 100644 index 00000000..9b314909 --- /dev/null +++ b/tests/bionic/libstdc++/test_csetjmp.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <csetjmp> +#ifndef BIONIC_LIBSTDCPP_INCLUDE_CSETJMP__ +#error "Wrong header file included!!" +#endif + + +namespace { +const int kPassed = 0; +const int kFailed = 1; +#define FAIL_UNLESS(f) if (!android::f()) return kFailed; +} // anonymous namespace + +namespace android +{ +#ifdef longjmp +#error "longjmp must not be a macro" +#endif + +#ifndef setjmp +#error "setjmp must be a macro" +#endif + +using std::longjmp; + +bool testJmpbuf() +{ + volatile std::jmp_buf jmpbuf; + return true; +} + +} // namespace android + +int main(int argc, char **argv) +{ + FAIL_UNLESS(testJmpbuf); + return kPassed; +} diff --git a/tests/bionic/libstdc++/test_csignal.cpp b/tests/bionic/libstdc++/test_csignal.cpp new file mode 100644 index 00000000..22fa946f --- /dev/null +++ b/tests/bionic/libstdc++/test_csignal.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <csignal> +#ifndef BIONIC_LIBSTDCPP_INCLUDE_CSIGNAL__ +#error "Wrong header file included!!" +#endif + +namespace { +const int kPassed = 0; +const int kFailed = 1; +#define FAIL_UNLESS(f) if (!android::f()) return kFailed; +} // anonymous namespace + +namespace android +{ +#ifdef raise +#error "raise must not be a macro" +#endif + +#ifndef SIGABRT +#error "SIGABRT must be a macro" +#endif + +#ifndef SIGILL +#error "SIGILL must be a macro" +#endif + +using std::raise; +using std::signal; +bool testSigAtomicT() +{ + volatile std::sig_atomic_t s; + return true; +} + +} // namespace android + +int main(int argc, char **argv) +{ + FAIL_UNLESS(testSigAtomicT); + return kPassed; +} diff --git a/tests/bionic/libstdc++/test_cstddef.cpp b/tests/bionic/libstdc++/test_cstddef.cpp new file mode 100644 index 00000000..19f9d422 --- /dev/null +++ b/tests/bionic/libstdc++/test_cstddef.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <cstddef> +#ifndef BIONIC_LIBSTDCPP_INCLUDE_CSTDDEF__ +#error "Wrong header file included!!" +#endif + + +namespace { +const int kPassed = 0; +const int kFailed = 1; +#define FAIL_UNLESS(f) if (!android::f()) return kFailed; +} // anonymous namespace + +namespace android { +// Dummy struct used to calculate offset of some of its fields. +struct Foo +{ + char field1; + char field2; +}; + +// Check various types are declared in the std namespace. +bool testTypesStd() +{ + // size_t should be defined in both namespaces + volatile ::size_t size_t_in_top_ns = 0; + volatile ::std::size_t size_t_in_std_ns = 0; + + if (sizeof(::size_t) != sizeof(::std::size_t)) + { + return false; + } + + // ptrdiff_t should be defined in both namespaces + volatile ::ptrdiff_t ptrdiff_t_in_top_ns = 0; + volatile ::std::ptrdiff_t ptrdiff_t_in_std_ns = 0; + + if (sizeof(::ptrdiff_t) != sizeof(::std::ptrdiff_t)) + { + return false; + } + // NULL is only in the top namespace + volatile int *null_is_defined = NULL; + return true; +} + +bool testOffsetOf() +{ +#ifndef offsetof +#error "offsetof is not a macro" +#endif + + // offsetof is only in the top namespace + volatile size_t offset = offsetof(struct Foo, field2); + return offset == 1; +} + +bool testNull() +{ +#ifndef NULL +#error "NULL is not a macro" +#endif + // If NULL is void* this will issue a warning. + volatile int null_is_not_void_star = NULL; + return true; +} + +} // android namespace + +int main(int argc, char **argv) +{ + FAIL_UNLESS(testTypesStd); + FAIL_UNLESS(testOffsetOf); + FAIL_UNLESS(testNull); + return kPassed; +} diff --git a/tests/bionic/libstdc++/test_cstdint.cpp b/tests/bionic/libstdc++/test_cstdint.cpp new file mode 100644 index 00000000..8753cf7d --- /dev/null +++ b/tests/bionic/libstdc++/test_cstdint.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <cstdint> +#ifndef BIONIC_LIBSTDCPP_INCLUDE_CSTDINT__ +#error "Wrong header file included!!" +#endif + +namespace { +const int kPassed = 0; +} // anonymous namespace + +namespace android +{ +} // namespace android + +int main(int argc, char **argv) +{ + return kPassed; +} diff --git a/tests/bionic/libstdc++/test_cstdio.cpp b/tests/bionic/libstdc++/test_cstdio.cpp new file mode 100644 index 00000000..573746dc --- /dev/null +++ b/tests/bionic/libstdc++/test_cstdio.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <cstdio> +#ifndef BIONIC_LIBSTDCPP_INCLUDE_CSTDIO__ +#error "Wrong header file included!!" +#endif + +namespace { +const int kPassed = 0; +const int kFailed = 1; +#define FAIL_UNLESS(f) if (!android::f()) return kFailed; +} // anonymous namespace + +namespace android +{ +#ifndef BUFSIZ +#error "BUFSIZ must be a macro" +#endif + +#ifndef EOF +#error "EOF must be a macro" +#endif + +#ifndef FILENAME_MAX +#error "FILENAME_MAX must be a macro" +#endif + +#ifndef FOPEN_MAX +#error "FOPEN_MAX must be a macro" +#endif + +#ifndef L_tmpnam +#error "L_tmpnam must be a macro" +#endif + +#ifndef NULL +#error "NULL must be a macro" +#endif + +#ifndef SEEK_CUR +#error "SEEK_CUR must be a macro" +#endif + +#ifndef SEEK_END +#error "SEEK_END must be a macro" +#endif +#ifndef SEEK_SET +#error "SEEK_SET must be a macro" +#endif + +#ifndef TMP_MAX +#error "TMP_MAX must be a macro" +#endif + +#ifndef _IOFBF +#error "_IOFBF must be a macro" +#endif + +#ifndef _IOLBF +#error "_IOLBF must be a macro" +#endif + +#ifndef _IONBF +#error "_IONBF must be a macro" +#endif + +#ifndef stderr +#error "stderr must be a macro" +#endif + +#ifndef stdin +#error "stdin must be a macro" +#endif + +#ifndef stdout +#error "stdout must be a macro" +#endif + +using std::clearerr; +using std::fclose; +using std::feof; +using std::ferror; +using std::fflush; +using std::fgetc; +using std::fgetpos; +using std::fgets; +using std::fopen; +using std::fprintf; +using std::fputc; +using std::fputs; +using std::fread; +using std::freopen; +using std::fscanf; +using std::fseek; +using std::fsetpos; +using std::ftell; +using std::fwrite; +using std::getc; +using std::getchar; +using std::gets; +using std::perror; +using std::printf; +using std::putc; +using std::putchar; +using std::puts; +using std::remove; +using std::rename; +using std::rewind; +using std::scanf; +using std::setbuf; +using std::setvbuf; +using std::sprintf; +using std::sscanf; +using std::tmpfile; +using std::tmpnam; +using std::ungetc; +using std::vfprintf; +using std::vprintf; +using std::vsprintf; + +using std::snprintf; +using std::vfscanf; +using std::vscanf; +using std::vsnprintf; +using std::vsscanf; + +bool testTypesStd() +{ + volatile std::size_t size; + volatile std::FILE file; + volatile std::fpos_t fpos_t; + return true; +} +} // namespace android + +int main(int argc, char **argv) +{ + FAIL_UNLESS(testTypesStd); + return kPassed; +} diff --git a/tests/bionic/libstdc++/test_cstdlib.cpp b/tests/bionic/libstdc++/test_cstdlib.cpp new file mode 100644 index 00000000..c5c914c4 --- /dev/null +++ b/tests/bionic/libstdc++/test_cstdlib.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <cstdlib> +#ifndef BIONIC_LIBSTDCPP_INCLUDE_CSTDLIB__ +#error "Wrong header file included!!" +#endif + + +namespace { +const int kPassed = 0; +const int kFailed = 1; +#define FAIL_UNLESS(f) if (!android::f()) return kFailed; +} // anonymous namespace + +namespace android +{ +} // namespace android + +int main(int argc, char **argv) +{ + // FAIL_UNLESS(testTypesStd); + return kPassed; +} diff --git a/tests/bionic/libstdc++/test_cstring.cpp b/tests/bionic/libstdc++/test_cstring.cpp new file mode 100644 index 00000000..eab64a1e --- /dev/null +++ b/tests/bionic/libstdc++/test_cstring.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <cstring> +#ifndef BIONIC_LIBSTDCPP_INCLUDE_CSTRING__ +#error "Wrong header file included!!" +#endif + +namespace { +const int kPassed = 0; +const int kFailed = 1; +#define FAIL_UNLESS(f) if (!android::f()) return kFailed; +} // anonymous namespace + +namespace android +{ +using std::memchr; +using std::memcmp; +using std::memcpy; +using std::memmove; +using std::memset; +using std::strcat; +using std::strchr; +using std::strcmp; +using std::strcoll; +using std::strcpy; +using std::strcspn; +using std::strerror; +using std::strlen; +using std::strncat; +using std::strncmp; +using std::strncpy; +using std::strpbrk; +using std::strrchr; +using std::strspn; +using std::strstr; +using std::strtok; +using std::strxfrm; + +#ifndef NULL +#error "NULL must be a macro" +#endif + +volatile std::size_t size; + +} // namespace android + +int main(int argc, char **argv) +{ + return kPassed; +} diff --git a/tests/bionic/libstdc++/test_ctime.cpp b/tests/bionic/libstdc++/test_ctime.cpp new file mode 100644 index 00000000..72a13cb9 --- /dev/null +++ b/tests/bionic/libstdc++/test_ctime.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <ctime> +#ifndef BIONIC_LIBSTDCPP_INCLUDE_CTIME__ +#error "Wrong header file included!!" +#endif + + +namespace { +const int kPassed = 0; +const int kFailed = 1; +#define FAIL_UNLESS(f) if (!android::f()) return kFailed; +} // anonymous namespace + +namespace android +{ +#ifndef CLOCKS_PER_SEC +#error "CLOCKS_PER_SEC must be a macro" +#endif + +#ifdef clock +#error "should be a real function" +#endif +#ifdef difftime +#error "should be a real function" +#endif +#ifdef mktime +#error "should be a real function" +#endif +#ifdef time +#error "should be a real function" +#endif +#ifdef asctime +#error "should be a real function" +#endif +#ifdef ctime +#error "should be a real function" +#endif +#ifdef gmtime +#error "should be a real function" +#endif +#ifdef localtime +#error "should be a real function" +#endif +#ifdef strftime +#error "should be a real function" +#endif + +using std::clock; +using std::difftime; +using std::mktime; +using std::time; +using std::asctime; +using std::ctime; +using std::gmtime; +using std::localtime; +using std::strftime; + +// Check various types are declared in the std namespace. +// This is a compilation test. +bool testTypesStd() +{ + volatile std::clock_t clock; + volatile std::time_t time; + volatile std::tm better_time; + return true; +} + +bool testGetClock() +{ + volatile std::clock_t clock1 = std::clock(); + volatile std::clock_t clock2 = std::clock(); + if (clock2 < clock1) return false; + return true; +} + +} // namespace android + +int main(int argc, char **argv) +{ + FAIL_UNLESS(testTypesStd); + FAIL_UNLESS(testGetClock); + return kPassed; +} diff --git a/tests/framebuffer/Android.mk b/tests/framebuffer/Android.mk index d6a8537d..4f789b9e 100644 --- a/tests/framebuffer/Android.mk +++ b/tests/framebuffer/Android.mk @@ -9,7 +9,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE:= test-fb-refresh -LOCAL_MODULE_TAGS := tests +LOCAL_MODULE_TAGS := optional ifeq ($(TARGET_SIMULATOR),true) ifeq ($(HOST_OS),linux) @@ -26,7 +26,7 @@ ifneq ($(TARGET_SIMULATOR),true) include $(CLEAR_VARS) LOCAL_SRC_FILES := fb_test.c LOCAL_MODULE = test-fb-simple -LOCAL_MODULE_TAGS := tests +LOCAL_MODULE_TAGS := optional LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_STATIC_LIBRARIES := libc include $(BUILD_EXECUTABLE) diff --git a/tests/framebuffer/fb_test.c b/tests/framebuffer/fb_test.c index 6fdbf3b3..3bd7e8e5 100644 --- a/tests/framebuffer/fb_test.c +++ b/tests/framebuffer/fb_test.c @@ -59,9 +59,12 @@ static int get_framebuffer(GGLSurface *fb) void *bits; fd = open("/dev/graphics/fb0", O_RDWR); - if(fd < 0) { - perror("cannot open fb0"); - return -1; + if (fd < 0) { + printf("cannot open /dev/graphics/fb0, retrying with /dev/fb0\n"); + if ((fd = open("/dev/fb0", O_RDWR)) < 0) { + perror("cannot open /dev/fb0"); + return -1; + } } if(ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) { @@ -127,22 +130,26 @@ static void dumpinfo(struct fb_fix_screeninfo *fi, struct fb_var_screeninfo *vi) int gr_init(void) { - int fd; - + int fd = -1; - fd = open("/dev/tty0", O_RDWR | O_SYNC); - if(fd < 0) return -1; + if (!access("/dev/tty0", F_OK)) { + fd = open("/dev/tty0", O_RDWR | O_SYNC); + if(fd < 0) + return -1; - if(ioctl(fd, KDSETMODE, (void*) KD_GRAPHICS)) { - close(fd); - return -1; + if(ioctl(fd, KDSETMODE, (void*) KD_GRAPHICS)) { + close(fd); + return -1; + } } gr_fb_fd = get_framebuffer(gr_framebuffer); if(gr_fb_fd < 0) { - ioctl(fd, KDSETMODE, (void*) KD_TEXT); - close(fd); + if (fd >= 0) { + ioctl(fd, KDSETMODE, (void*) KD_TEXT); + close(fd); + } return -1; } @@ -160,9 +167,11 @@ void gr_exit(void) close(gr_fb_fd); gr_fb_fd = -1; - ioctl(gr_vt_fd, KDSETMODE, (void*) KD_TEXT); - close(gr_vt_fd); - gr_vt_fd = -1; + if (gr_vt_fd >= 0) { + ioctl(gr_vt_fd, KDSETMODE, (void*) KD_TEXT); + close(gr_vt_fd); + gr_vt_fd = -1; + } } int gr_fb_width(void) diff --git a/tests/fstest/Android.mk b/tests/fstest/Android.mk index bf4f17c3..14c32aa0 100644 --- a/tests/fstest/Android.mk +++ b/tests/fstest/Android.mk @@ -22,7 +22,7 @@ LOCAL_SHARED_LIBRARIES := libc LOCAL_MODULE := perm_checker -LOCAL_MODULE_TAGS := tests +LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) @@ -32,7 +32,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := perm_checker.conf -LOCAL_MODULE_TAGS := tests +LOCAL_MODULE_TAGS := optional LOCAL_MODULE_CLASS := ETC diff --git a/tests/fstest/perm_checker.conf b/tests/fstest/perm_checker.conf index fe253d7b..15485b84 100644 --- a/tests/fstest/perm_checker.conf +++ b/tests/fstest/perm_checker.conf @@ -60,7 +60,7 @@ /dev/pmem 660 660 system system graphics graphics /dev/pmem_adsp 660 660 system system audio audio /dev/pmem_camera 600 660 root system root camera -/dev/ppp 600 600 root root root root +/dev/ppp 660 660 radio radio vpn vpn /dev/psaux 600 600 root root root root /dev/ptmx 666 666 root root root root /dev/random 666 666 root root root root @@ -140,10 +140,8 @@ /system/etc/init.gprs-pppd 500 550 root root root shell /system/etc/init.testmenu 500 550 root root root root /system/etc/perm_checker.conf 000 777 root shell root shell -/system/etc/ppp/ 755 775 root system root system -/system/etc/ppp/chap-secrets 600 660 root system root system -/system/etc/ppp/ip-down 500 550 root system root system -/system/etc/ppp/ip-up 500 550 root system root system +/system/etc/ppp/ 755 755 root root root root +/system/etc/ppp/* 555 555 root root root root /system/etc/security/ 755 755 root root root root /system/etc/wifi/ 750 755 root system root system /system/lib/ 755 755 root root root root diff --git a/tests/icachetest/Android.mk b/tests/icachetest/Android.mk index fca07ee1..39d0016f 100644 --- a/tests/icachetest/Android.mk +++ b/tests/icachetest/Android.mk @@ -9,6 +9,6 @@ LOCAL_SHARED_LIBRARIES := libc LOCAL_MODULE:= icache -LOCAL_MODULE_TAGS := tests +LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) diff --git a/tests/memtest/Android.mk b/tests/memtest/Android.mk index 36f233c7..06e2304d 100644 --- a/tests/memtest/Android.mk +++ b/tests/memtest/Android.mk @@ -11,7 +11,7 @@ LOCAL_SHARED_LIBRARIES := libc LOCAL_MODULE:= memtest -LOCAL_MODULE_TAGS := tests +LOCAL_MODULE_TAGS := optional ## LOCAL_CFLAGS += -fstack-protector-all LOCAL_CFLAGS += -fomit-frame-pointer diff --git a/tests/sdcard/Android.mk b/tests/sdcard/Android.mk new file mode 100644 index 00000000..d1e06f25 --- /dev/null +++ b/tests/sdcard/Android.mk @@ -0,0 +1,37 @@ +# Copyright (C) 2009 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Build control file for Bionic's test programs +# define the BIONIC_TESTS environment variable to build the test programs +# + +ifdef SDCARD_TESTS + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES = \ + stopwatch.cpp \ + sysutil.cpp \ + sdcard_perf_test.cpp \ + testcase.cpp + +LOCAL_MODULE := sdcard_perf_test +LOCAL_MODULE_TAGS := eng tests +LOCAL_SHARED_LIBRARIES := libutils libhardware_legacy + +include $(BUILD_EXECUTABLE) + +endif # SDCARD_TESTS diff --git a/tests/sdcard/plot_sdcard.py b/tests/sdcard/plot_sdcard.py new file mode 100755 index 00000000..19b83c3c --- /dev/null +++ b/tests/sdcard/plot_sdcard.py @@ -0,0 +1,331 @@ +#!/usr/bin/python2.5 +# +# Copyright 2009, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +"""plot_sdcard: A module to plot the results of an sdcard perf test. + +Requires Gnuplot python v 1.8 + +Typical usage: + -t x axis is time + -i x axis is iteration + -p profile data generated by profile_sdcard.sh + +./plot_sdcard.py -t /tmp/data.txt +./plot_sdcard.py -i /tmp/data.txt +./plot_sdcard.py -p + +python interpreter +>>> import plot_sdcard as p +>>> (metadata, data) = p.Parse('/tmp/data.txt') +>>> p.PlotIterations(metadata, data) +>>> p.PlotTimes(metadata, data) + +""" + +import getopt +from itertools import izip +import re +import sys +import Gnuplot +import numpy + + +class DataSet(object): + """Dataset holds the summary and data (time,value pairs).""" + + def __init__(self, line): + res = re.search(('# StopWatch ([\w]+) total/cumulative ' + 'duration ([0-9.]+). Samples: ([0-9]+)'), line) + self.time = [] + self.data = [] + self.name = res.group(1) + self.duration = float(res.group(2)) + self.iteration = int(res.group(3)) + self.summary = re.match('([a-z_]+)_total', self.name) + + def __repr__(self): + return str(zip(self.time, self.data)) + + def Add(self, time, value): + self.time.append(time) + self.data.append(value) + + def RescaleTo(self, length): + factor = len(self.data) / length + + if factor > 1: + new_time = [] + new_data = [] + accum = 0.0 + idx = 1 + for t, d in izip(self.time, self.data): + accum += d + if idx % factor == 0: + new_time.append(t) + new_data.append(accum / factor) + accum = 0 + idx += 1 + self.time = new_time + self.data = new_data + + +class Metadata(object): + def __init__(self): + self.kernel = '' + self.command_line = '' + self.sched = '' + self.name = '' + self.fadvise = '' + self.iterations = 0 + self.duration = 0.0 + self.complete = False + + def Parse(self, line): + if line.startswith('# Kernel:'): + self.kernel = re.search('Linux version ([0-9.]+-[0-9]+)', line).group(1) + elif line.startswith('# Command:'): + self.command_line = re.search('# Command: [/\w_]+ (.*)', line).group(1) + self.command_line = self.command_line.replace(' --', '-') + self.command_line = self.command_line.replace(' -d', '') + self.command_line = self.command_line.replace('--test=', '') + elif line.startswith('# Iterations'): + self.iterations = int(re.search('# Iterations: ([0-9]+)', line).group(1)) + elif line.startswith('# Fadvise'): + self.fadvise = re.search('# Fadvise: ([\w]+)', line).group(1) + elif line.startswith('# Sched'): + self.sched = re.search('# Sched features: ([\w]+)', line).group(1) + self.complete = True + + def AsTitle(self): + return '%s-duration:%f\\n-%s\\n%s' % ( + self.kernel, self.duration, self.command_line, self.sched) + + def UpdateWith(self, dataset): + self.duration = max(self.duration, dataset.duration) + self.name = dataset.name + + +def Parse(filename): + """Parse a file with the collected data. + + The data must be in 2 rows (x,y). + + Args: + filename: Full path to the file. + """ + + f = open(filename, 'r') + + metadata = Metadata() + data = [] # array of dataset + dataset = None + + for num, line in enumerate(f): + try: + line = line.strip() + if not line: continue + + if not metadata.complete: + metadata.Parse(line) + continue + + if re.match('[a-z_]', line): + continue + + if line.startswith('# StopWatch'): # Start of a new dataset + if dataset: + if dataset.summary: + metadata.UpdateWith(dataset) + else: + data.append(dataset) + + dataset = DataSet(line) + continue + + if line.startswith('#'): + continue + + # must be data at this stage + try: + (time, value) = line.split(None, 1) + except ValueError: + print 'skipping line %d: %s' % (num, line) + continue + + if dataset and not dataset.summary: + dataset.Add(float(time), float(value)) + + except Exception: + print 'Error parsing line %d' % num, sys.exc_info()[0] + raise + data.append(dataset) + if not metadata.complete: + print """Error missing metadata. Did you mount debugfs? + [adb shell mount -t debugfs none /sys/kernel/debug]""" + sys.exit(1) + return (metadata, data) + + +def PlotIterations(metadata, data): + """Plot the duration of the ops against iteration. + + If you are plotting data with widely different runtimes you probably want to + use PlotTimes instead. + + For instance when readers and writers are in the same mix, the + readers will go thru 100 iterations much faster than the + writers. The load test tries to be smart about that but the final + iterations of the writers will likely be done w/o any influence from + the readers. + + Args: + metadata: For the graph's title. + data: pair of to be plotted. + """ + + gp = Gnuplot.Gnuplot(persist=1) + gp('set data style lines') + gp.clear() + gp.xlabel('iterations') + gp.ylabel('duration in second') + gp.title(metadata.AsTitle()) + styles = {} + line_style = 1 + + for dataset in data: + dataset.RescaleTo(metadata.iterations) + x = numpy.arange(len(dataset.data), dtype='int_') + if not dataset.name in styles: + styles[dataset.name] = line_style + line_style += 1 + d = Gnuplot.Data(x, dataset.data, + title=dataset.name, + with_='lines ls %d' % styles[dataset.name]) + else: # no need to repeat a title that exists already. + d = Gnuplot.Data(x, dataset.data, + with_='lines ls %d' % styles[dataset.name]) + + gp.replot(d) + gp.hardcopy('/tmp/%s-%s-%f.png' % + (metadata.name, metadata.kernel, metadata.duration), + terminal='png') + + +def PlotTimes(metadata, data): + """Plot the duration of the ops against time elapsed. + + Args: + metadata: For the graph's title. + data: pair of to be plotted. + """ + + gp = Gnuplot.Gnuplot(persist=1) + gp('set data style impulses') + gp('set xtics 1') + gp.clear() + gp.xlabel('seconds') + gp.ylabel('duration in second') + gp.title(metadata.AsTitle()) + styles = {} + line_style = 1 + + for dataset in data: + x = numpy.array(dataset.time, dtype='float_') + if not dataset.name in styles: + styles[dataset.name] = line_style + line_style += 1 + d = Gnuplot.Data(x, dataset.data, + title=dataset.name, + with_='impulses ls %d' % styles[dataset.name]) + else: # no need to repeat a title that exists already. + d = Gnuplot.Data(x, dataset.data, + with_='impulses ls %d' % styles[dataset.name]) + + gp.replot(d) + gp.hardcopy('/tmp/%s-%s-%f.png' % + (metadata.name, metadata.kernel, metadata.duration), + terminal='png') + + +def PlotProfile(): + """Plot the time of a run against the number of processes.""" + (metadata, data) = Parse('/tmp/sdcard-scalability.txt') + gp = Gnuplot.Gnuplot(persist=1) + gp('set data style impulses') + gp('set xtics 1') + gp('set pointsize 2') + gp.clear() + gp.xlabel('writer process') + gp.ylabel('duration in second') + gp.title(metadata.AsTitle()) + + dataset = data[0] + x = numpy.array(dataset.time, dtype='int_') + d = Gnuplot.Data(x, dataset.data, + title=dataset.name, + with_='linespoints') + gp.replot(d) + gp.hardcopy('/tmp/%s-%s-%f.png' % + (metadata.name, metadata.kernel, metadata.duration), + terminal='png') + + +def Usage(): + """Print this module's usage.""" + print """ + To plot the result using the iter number of the x axis: + + plot_sdcard.py -i /tmp/data.txt + + To plot the result using time for the x axis: + + plot_sdcard.py -t /tmp/data.txt + + To plot the result from the profiler: + + profile_sdcard.sh + plot_sdcard.py -p + + """ + sys.exit(2) + + +def main(argv): + try: + (optlist, args) = getopt.getopt(argv[1:], + 'itp', ['iteration', 'time', 'profile']) + except getopt.GetoptError, err: + print str(err) + Usage() + + for flag, val in optlist: + if flag in ('-i', '--iteration'): + (metadata, data) = Parse(args[0]) + PlotIterations(metadata, data) + sys.exit(0) + elif flag in ('-t', '--time'): + (metadata, data) = Parse(args[0]) + PlotTimes(metadata, data) + sys.exit(0) + elif flag in ('-p', '--profile'): + PlotProfile() + sys.exit(0) + Usage() + + +if __name__ == '__main__': + main(sys.argv) diff --git a/tests/sdcard/profile_sdcard.sh b/tests/sdcard/profile_sdcard.sh new file mode 100755 index 00000000..4629c910 --- /dev/null +++ b/tests/sdcard/profile_sdcard.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# Copyright 2009, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Run a bunch of test on the sdcard to establish a performance profile. + +print_kernel() { + adb shell cat /proc/version +} +print_sched_features() { + adb shell cat /sys/kernel/debug/sched_features +} + +# Use dd to get the raw speed of the card +block_level() { + true +} + +# Time to run a test vs number of processes +scalability() { + local file="/tmp/sdcard-scalability.txt" + rm -f ${file} + echo "# Scalability tests" | tee -a ${file} + echo "# Kernel: $(print_kernel)" | tee -a ${file} + echo "# Sched features: $(print_sched_features)" | tee -a ${file} + echo "# StopWatch scalability total/cumulative duration 0.0 Samples: 1" | tee -a ${file} + echo "# Process Time" | tee -a ${file} + for p in $(seq 1 8); do + adb shell sdcard_perf_test --test=write --procnb=${p} --size=1000 --chunk-size=100 --iterations=50 >/tmp/tmp-sdcard.txt + local t=$(grep 'write_total' /tmp/tmp-sdcard.txt | tail -n 1 | cut -f 6 -d ' ') + echo "$p $t" | tee -a ${file} + done + +} + +# Readers and writers should not starve each others. +fairness() { + # Check readers finished before writers. + # Find the time of the last read op. + # Count how many writes and how many read happend + # during that period, do the ratio. + true +} + +####################################################################### +# MAIN + +echo "Make sure debugfs is mounted on the device." +block_level +scalability +fairness + + diff --git a/tests/sdcard/sdcard_perf_test.cpp b/tests/sdcard/sdcard_perf_test.cpp new file mode 100644 index 00000000..28069b9a --- /dev/null +++ b/tests/sdcard/sdcard_perf_test.cpp @@ -0,0 +1,607 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <cstdio> +#include <cstdlib> +#include <ctime> +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <limits.h> +#include <string.h> +#include <sys/stat.h> +#include <linux/fadvise.h> +#include <unistd.h> + +#include "stopwatch.h" +#include "sysutil.h" +#include "testcase.h" + +// Stress test for the sdcard. Use this to generate some load on the +// sdcard and collect performance statistics. The ouput is either a +// human readable report or the raw timing samples that can be +// processed using another tool. +// +// Needs debugfs: +// adb root; +// adb shell mount -t debugfs none /sys/kernel/debug +// +// The following tests are defined (value of the --test flag): +// write: Open a file write some random data and close. +// read: Open a file read it and close. +// read_write: Combine readers and writers. +// open_create: Open|create an non existing file. +// +// For each run you can control how many processes will run the test in +// parallel to simulate a real load (--procnb flag) +// +// For each process, the test selected will be executed many time to +// get a meaningful average/min/max (--iterations flag) +// +// Use --dump to also get the raw data. +// +// For read/write tests, size is the number of Kbytes to use. +// +// To build: mmm system/extras/tests/sdcard/Android.mk SDCARD_TESTS=1 +// +// Examples: +// adb shell /system/bin/sdcard_perf_test --test=read --size=1000 --chunk-size=100 --procnb=1 --iterations=10 --dump > /tmp/data.txt +// adb shell /system/bin/sdcard_perf_test --test=write --size=1000 --chunk-size=100 --procnb=1 --iterations=100 --dump > /tmp/data.txt +// +// To watch the memory: cat /proc/meminfo +// If the phone crashes, look at /proc/last_kmsg on reboot. +// +// TODO: It would be cool if we could play with various fadvise() +// strategies in here to see how tweaking read-ahead changes things. +// + +extern char *optarg; +extern int optind, opterr, optopt; + +// TODO: No clue where fadvise is. Disabled for now. +#define FADVISE(fd, off, len, advice) (void)0 + +#ifndef min +#define min(a,b) (((a)>(b))?(b):(a)) +#endif + +namespace { +using android::kernelVersion; +using android::kMinKernelVersionBufferSize; +using android::schedFeatures; +using android::kMinSchedFeaturesBufferSize; +using android_test::StopWatch; +using android::writePidAndWaitForReply; +using android::waitForChildrenAndSignal; +using android::waitForChildrenOrExit; +using android_test::TestCase; + +const char *kAppName = "sdcard_perf_test"; +const char *kTestDir = "/sdcard/perf"; +const bool kVerbose = false; + +// Used by getopt to parse the command line. +struct option long_options[] = { + {"size", required_argument, 0, 's'}, + {"chunk-size", required_argument, 0, 'S'}, + {"iterations", required_argument, 0, 'i'}, + {"procnb", required_argument, 0, 'p'}, + {"test", required_argument, 0, 't'}, + {"dump", no_argument, 0, 'd'}, + {"cpu-scaling", no_argument, 0, 'c'}, + {"sync", required_argument, 0, 'f'}, + {"truncate", no_argument, 0, 'e'}, + {"no-new-fair-sleepers", no_argument, 0, 'z'}, + {"no-normalized-sleepers", no_argument, 0, 'Z'}, + {"fadvise", required_argument, 0, 'a'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}, +}; + +void usage() +{ + printf("sdcard_perf_test --test=write|read|read_write|open_create [options]\n\n" + " -t --test: Select the test.\n" + " -s --size: Size in kbytes of the data.\n" + " -S --chunk-size: Size of a chunk. Default to size ie 1 chunk.\n" + " Data will be written/read using that chunk size.\n" + " -i --iterations: Number of time a process should carry its task.\n" + " -p --procnb: Number of processes to use.\n" + " -d --dump: Print the raw timing on stdout.\n" + " -c --cpu-scaling: Enable cpu scaling.\n" + " -s --sync: fsync|sync Use fsync or sync in write test. Default: no sync call.\n" + " -e --truncate: Truncate to size the file on creation.\n" + " -z --no-new-fair-sleepers: Turn them off. You need to mount debugfs.\n" + " -Z --no-normalized-sleepers: Turn them off. You need to mount debugfs.\n" + " -a --fadvise: Specify an fadvise policy (not supported).\n" + ); +} + +// Print command line, pid, kernel version, OOM adj and scheduler. +void printHeader(int argc, char **argv, const TestCase& testCase) +{ + printf("# Command: "); + for (int i = 0; i < argc; ++i) + { + printf("%s ", argv[i]); + } + printf("\n"); + + printf("# Pid: %d\n", getpid()); + + { + char buffer[kMinKernelVersionBufferSize] = {0, }; + if (kernelVersion(buffer, sizeof(buffer)) > 0) + { + printf("# Kernel: %s", buffer); + } + } + + // Earlier on, running this test was crashing the phone. It turned + // out that it was using too much memory but its oom_adj value was + // -17 which means disabled. -16 is the system_server and 0 is + // typically what applications run at. The issue is that adb runs + // at -17 and so is this test. We force oom_adj to 0 unless the + // oom_adj option has been used. + // TODO: We talked about adding an option to control oom_adj, not + // sure if we still need that. + int oomAdj = android::pidOutOfMemoryAdj(); + + printf("# Oom_adj: %d ", oomAdj); + if (oomAdj < 0) + { + android::setPidOutOfMemoryAdj(0); + printf("adjuted to %d", android::pidOutOfMemoryAdj()); + } + printf("\n"); + + { + char buffer[kMinSchedFeaturesBufferSize] = {0, }; + if (schedFeatures(buffer, sizeof(buffer)) > 0) + { + printf("# Sched features: %s", buffer); + } + } + printf("# Fadvise: %s\n", testCase.fadviseAsStr()); +} + +// Remove all the files under kTestDir and clear the caches. +void cleanup() { + android::resetDirectory(kTestDir); + android::syncAndDropCaches(); // don't pollute runs. +} + +// @param argc, argv have a wild guess. +// @param[out] testCase Structure built from the cmd line args. +void parseCmdLine(int argc, char **argv, TestCase *testCase)\ +{ + int c; + + while(true) + { + // getopt_long stores the option index here. + int option_index = 0; + + c = getopt_long (argc, argv, + "hS:s:i:p:t:dcf:ezZa:", + long_options, + &option_index); + // Detect the end of the options. + if (c == -1) break; + + switch (c) + { + case 's': + testCase->setDataSize(atoi(optarg) * 1024); + break; + case 'S': + testCase->setChunkSize(atoi(optarg) * 1024); + break; + case 'i': + testCase->setIter(atoi(optarg)); + printf("# Iterations: %d\n", testCase->iter()); + break; + case 'p': + testCase->setNproc(atoi(optarg)); + printf("# Proc nb: %d\n", testCase->nproc()); + break; + case 't': + testCase->setTypeFromName(optarg); + printf("# Test name %s\n", testCase->name()); + break; + case 'd': + testCase->setDump(); + break; + case 'c': + printf("# Cpu scaling is on\n"); + testCase->setCpuScaling(); + break; + case 'f': + if (strcmp("sync", optarg) == 0) { + testCase->setSync(TestCase::SYNC); + } else if (strcmp("fsync", optarg) == 0) { + testCase->setSync(TestCase::FSYNC); + } + break; + case 'e': // e for empty + printf("# Will truncate to size\n"); + testCase->setTruncateToSize(); + break; + case 'z': // no new fair sleepers + testCase->setNewFairSleepers(false); + break; + case 'Z': // no normalized sleepers + testCase->setNormalizedSleepers(false); + break; + case 'a': // fadvise + testCase->setFadvise(optarg); + break; + case 'h': + usage(); + exit(0); + default: + fprintf(stderr, "Unknown option %s\n", optarg); + exit(EXIT_FAILURE); + } + } +} + +// ---------------------------------------------------------------------- +// READ TEST + +// Read a file. We use a new file each time to avoid any caching +// effect that would happen if we were reading the same file each +// time. +// @param chunk buffer large enough where the chunk read are written. +// @param idx iteration number. +// @param testCase has all the timers and paramters to run the test. + +bool readData(char *const chunk, const int idx, TestCase *testCase) +{ + char filename[80] = {'\0',}; + + sprintf(filename, "%s/file-%d-%d", kTestDir, idx, getpid()); + + testCase->openTimer()->start(); + int fd = open(filename, O_RDONLY); + testCase->openTimer()->stop(); + + if (fd < 0) + { + fprintf(stderr, "Open read only failed."); + return false; + } + FADVISE(fd, 0, 0, testCase->fadvise()); + + size_t left = testCase->dataSize(); + pid_t *pid = (pid_t*)chunk; + while (left > 0) + { + char *dest = chunk; + size_t chunk_size = testCase->chunkSize(); + + if (chunk_size > left) + { + chunk_size = left; + left = 0; + } + else + { + left -= chunk_size; + } + + testCase->readTimer()->start(); + while (chunk_size > 0) + { + ssize_t s = read(fd, dest, chunk_size); + if (s < 0) + { + fprintf(stderr, "Failed to read.\n"); + close(fd); + return false; + } + chunk_size -= s; + dest += s; + } + testCase->readTimer()->stop(); + } + close(fd); + if (testCase->pid() != *pid) + { + fprintf(stderr, "Wrong pid found @ read block %x != %x\n", testCase->pid(), *pid); + return false; + } + else + { + return true; + } +} + + +bool testRead(TestCase *testCase) { + // Setup the testcase by writting some dummy files. + const size_t size = testCase->dataSize(); + size_t chunk_size = testCase->chunkSize(); + char *const chunk = new char[chunk_size]; + + memset(chunk, 0xaa, chunk_size); + *((pid_t *)chunk) = testCase->pid(); // write our pid at the beginning of each chunk + + size_t iter = testCase->iter(); + + // since readers are much faster we increase the number of + // iteration to last longer and have concurrent read/write + // thoughout the whole test. + if (testCase->type() == TestCase::READ_WRITE) + { + iter *= TestCase::kReadWriteFactor; + } + + for (size_t i = 0; i < iter; ++i) + { + char filename[80] = {'\0',}; + + sprintf(filename, "%s/file-%d-%d", kTestDir, i, testCase->pid()); + int fd = open(filename, O_RDWR | O_CREAT); + + size_t left = size; + while (left > 0) + { + if (chunk_size > left) + { + chunk_size = left; + } + ssize_t written = write(fd, chunk, chunk_size); + if (written < 0) + { + fprintf(stderr, "Write failed %d %s.", errno, strerror(errno)); + return false; + } + left -= written; + } + close(fd); + } + if (kVerbose) printf("Child %d all chunk written\n", testCase->pid()); + + android::syncAndDropCaches(); + testCase->signalParentAndWait(); + + // Start the read test. + testCase->testTimer()->start(); + for (size_t i = 0; i < iter; ++i) + { + if (!readData(chunk, i, testCase)) + { + return false; + } + } + testCase->testTimer()->stop(); + + delete [] chunk; + return true; +} + +// ---------------------------------------------------------------------- +// WRITE TEST + +bool writeData(const char *const chunk, const int idx, TestCase *testCase) { + char filename[80] = {'\0',}; + + sprintf(filename, "%s/file-%d-%d", kTestDir, idx, getpid()); + testCase->openTimer()->start(); + int fd = open(filename, O_RDWR | O_CREAT); // no O_TRUNC, see header comment + testCase->openTimer()->stop(); + + if (fd < 0) + { + fprintf(stderr, "Open write failed."); + return false; + } + FADVISE(fd, 0, 0, testCase->fadvise()); + + if (testCase->truncateToSize()) + { + testCase->truncateTimer()->start(); + ftruncate(fd, testCase->dataSize()); + testCase->truncateTimer()->stop(); + } + + size_t left = testCase->dataSize(); + while (left > 0) + { + const char *dest = chunk; + size_t chunk_size = testCase->chunkSize(); + + if (chunk_size > left) + { + chunk_size = left; + left = 0; + } + else + { + left -= chunk_size; + } + + + testCase->writeTimer()->start(); + while (chunk_size > 0) + { + ssize_t s = write(fd, dest, chunk_size); + if (s < 0) + { + fprintf(stderr, "Failed to write.\n"); + close(fd); + return false; + } + chunk_size -= s; + dest += s; + } + testCase->writeTimer()->stop(); + } + + if (TestCase::FSYNC == testCase->sync()) + { + testCase->syncTimer()->start(); + fsync(fd); + testCase->syncTimer()->stop(); + } + else if (TestCase::SYNC == testCase->sync()) + { + testCase->syncTimer()->start(); + sync(); + testCase->syncTimer()->stop(); + } + close(fd); + return true; +} + +bool testWrite(TestCase *testCase) +{ + const size_t size = testCase->dataSize(); + size_t chunk_size = testCase->chunkSize(); + char *data = new char[chunk_size]; + + memset(data, 0xaa, chunk_size); + // TODO: write the pid at the beginning like in the write + // test. Have a mode where we check the write was correct. + testCase->signalParentAndWait(); + + testCase->testTimer()->start(); + for (size_t i = 0; i < testCase->iter(); ++i) + { + if (!writeData(data, i, testCase)) + { + return false; + } + } + testCase->testTimer()->stop(); + delete [] data; + return true; +} + + +// ---------------------------------------------------------------------- +// READ WRITE + +// Mix of read and write test. Even PID run the write test. Odd PID +// the read test. Not fool proof but work most of the time. +bool testReadWrite(TestCase *testCase) +{ + if (getpid() & 0x1) { + return testRead(testCase); + } else { + return testWrite(testCase); + } +} + +// ---------------------------------------------------------------------- +// OPEN CREATE TEST + +bool testOpenCreate(TestCase *testCase) +{ + char filename[80] = {'\0',}; + + testCase->signalParentAndWait(); + testCase->testTimer()->start(); + + for (size_t i = 0; i < testCase->iter(); ++i) + { + sprintf(filename, "%s/file-%d-%d", kTestDir, i, testCase->pid()); + + int fd = open(filename, O_RDWR | O_CREAT); + FADVISE(fd, 0, 0, testCase->fadvise()); + + if (testCase->truncateToSize()) + { + ftruncate(fd, testCase->dataSize()); + } + if (fd < 0) + { + return false; + } + close(fd); + } + testCase->testTimer()->stop(); + return true; +} + +} // anonymous namespace + +int main(int argc, char **argv) +{ + android_test::TestCase testCase(kAppName); + + cleanup(); + + parseCmdLine(argc, argv, &testCase); + printHeader(argc, argv, testCase); + + printf("# File size %d kbytes\n", testCase.dataSize() / 1024); + printf("# Chunk size %d kbytes\n", testCase.chunkSize() / 1024); + printf("# Sync: %s\n", testCase.syncAsStr()); + + if (!testCase.cpuScaling()) + { + android::disableCpuScaling(); + } + + switch(testCase.type()) { + case TestCase::WRITE: + testCase.mTestBody = testWrite; + break; + case TestCase::READ: + testCase.mTestBody = testRead; + break; + case TestCase::OPEN_CREATE: + testCase.mTestBody = testOpenCreate; + break; + case TestCase::READ_WRITE: + testCase.mTestBody = testReadWrite; + break; + default: + fprintf(stderr, "Unknown test type %s", testCase.name()); + exit(EXIT_FAILURE); + } + + testCase.createTimers(); + + bool ok; + + ok = testCase.runTest(); + + cleanup(); + if (!ok) + { + printf("error %d %s", errno, strerror(errno)); + exit(EXIT_FAILURE); + } + else + { + exit(EXIT_SUCCESS); + } +} diff --git a/tests/sdcard/stopwatch.cpp b/tests/sdcard/stopwatch.cpp new file mode 100644 index 00000000..8207430d --- /dev/null +++ b/tests/sdcard/stopwatch.cpp @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include <malloc.h> +#include <stdio.h> +#include <time.h> +#include "stopwatch.h" + +#define SNPRINTF_OR_RETURN(str, size, format, ...) { \ + int len = snprintf((str), (size), (format), ## __VA_ARGS__); \ + if (len < 0) return; \ + if (len > static_cast<int>(size)) { \ + fprintf(stderr, "Not enough space\n"); \ + return; \ + } else { \ + (size) -= len; (str) += len; \ + } \ + } + +namespace { +const bool kVerbose = false; +bool printRaw = false; +} + +namespace android_test { + +StopWatch::StopWatch(const char *name, size_t capacity) + : mName(strdup(name)), mNum(0), mData(NULL), mDataLen(0), mCapacity(capacity * 2), + mSizeKbytes(0), mAlreadyPrinted(false), mPrintRaw(false), + mDuration(0.0), + mMinDuration(0.0), mMinIdx(0), + mMaxDuration(0.0), mMaxIdx(0), + mDeltas(NULL), mUsed(false) +{ + mStart.tv_sec = 0; + mStart.tv_nsec = 0; + mData = (Measurement *) malloc(mCapacity * sizeof(Measurement)); +} + +StopWatch::~StopWatch() +{ + if (mUsed && !mAlreadyPrinted) + { + fprintf(stderr, "Discarding data for %s\n", mName); + } + free(mData); + free(mName); + delete [] mDeltas; +} + +void StopWatch::start() +{ + checkCapacity(); + clock_gettime(CLOCK_MONOTONIC, &mData[mDataLen].mTime); + mData[mDataLen].mIsStart = true; + if (!mUsed) + { + mStart = mData[mDataLen].mTime; // mDataLen should be 0 + mUsed = true; + } + ++mNum; + ++mDataLen; +} + +void StopWatch::stop() +{ + checkCapacity(); + clock_gettime(CLOCK_MONOTONIC, &mData[mDataLen].mTime); + mData[mDataLen].mIsStart = false; + ++mDataLen; +} + +void StopWatch::setPrintRawMode(bool raw) +{ + printRaw = raw; +} + + +void StopWatch::sprint(char **str, size_t *size) +{ + if (kVerbose) fprintf(stderr, "printing\n"); + mAlreadyPrinted = true; + if (0 == mDataLen) + { + return; + } + if (mDataLen > 0 && mData[mDataLen - 1].mIsStart) + { + stop(); + } + if (kVerbose) SNPRINTF_OR_RETURN(*str, *size, "# Got %d samples for %s\n", mDataLen, mName); + processSamples(); + + SNPRINTF_OR_RETURN(*str, *size, "# StopWatch %s total/cumulative duration %f Samples: %d\n", + mName, mDuration, mNum); + printThroughput(str, size); + printAverageMinMax(str, size); + + if (printRaw) + { + // print comment header and summary values. + + SNPRINTF_OR_RETURN(*str, *size, "# Name Iterations Duration Min MinIdx Max MaxIdx SizeMbytes\n"); + SNPRINTF_OR_RETURN(*str, *size, "%s %d %f %f %d %f %d %d\n", mName, mNum, mDuration, + mMinDuration, mMinIdx, mMaxDuration, mMaxIdx, mSizeKbytes); + // print each duration sample + for (size_t i = 0; i < mDataLen / 2; ++i) + { + long second = mData[i * 2].mTime.tv_sec - mStart.tv_sec; + long nano = mData[i * 2].mTime.tv_nsec - mStart.tv_nsec; + + SNPRINTF_OR_RETURN(*str, *size, "%f %f\n", double(second) + double(nano) / 1.0e9, mDeltas[i]); + } + } + +} + +// Normally we should have enough capacity but if we have to +// reallocate the measurement buffer (e.g start and stop called more +// than once in an iteration) we let the user know. She should provide +// a capacity when building the StopWatch. +void StopWatch::checkCapacity() +{ + if (mDataLen >= mCapacity) + { + mCapacity *= 2; + fprintf(stderr, "# Increased capacity to %d for %s. Measurement affected.\n", + mCapacity, mName); + mData = (Measurement *)realloc(mData, mCapacity * sizeof(Measurement)); + } +} + + +// Go over all the samples and compute the diffs between a start and +// stop pair. The diff is accumulated in mDuration and inserted in +// mDeltas. +// The min and max values for a diff are also tracked. +void StopWatch::processSamples() +{ + if (kVerbose) fprintf(stderr, "processing samples\n"); + mDeltas= new double[mDataLen / 2]; + + for (size_t i = 0; i < mDataLen; i += 2) // even: start odd: stop + { + long second = mData[i + 1].mTime.tv_sec - mData[i].mTime.tv_sec; + long nano = mData[i + 1].mTime.tv_nsec - mData[i].mTime.tv_nsec; + + mDeltas[i / 2] = double(second) + double(nano) / 1.0e9; + } + + for (size_t i = 0; i < mDataLen / 2; ++i) + { + if (0 == i) + { + mMinDuration = mMaxDuration = mDeltas[i]; + } + else + { + if (mMaxDuration < mDeltas[i]) + { + mMaxDuration = mDeltas[i]; + mMaxIdx = i; + } + if (mMinDuration > mDeltas[i]) + { + mMinDuration = mDeltas[i]; + mMinIdx = i; + } + } + mDuration += mDeltas[i]; + } +} + +double StopWatch::timespecToDouble(const struct timespec& time) +{ + double val = double(time.tv_nsec) / 1.0e9 + double(time.tv_sec); + return val < 0.0 ? -val : val; // sometimes 0.00 is -0.00 +} + + +// If we have only 2 values, don't bother printing anything. +void StopWatch::printAverageMinMax(char **str, size_t *size) +{ + if (mDataLen > 2) // if there is only one sample, avg, min, max are trivial. + { + SNPRINTF_OR_RETURN(*str, *size, "# Average %s duration %f s/op\n", mName, mDuration / mNum); + SNPRINTF_OR_RETURN(*str, *size, "# Min %s duration %f [%d]\n", mName, mMinDuration, mMinIdx); + SNPRINTF_OR_RETURN(*str, *size, "# Max %s duration %f [%d]\n", mName, mMaxDuration, mMaxIdx); + } +} + +void StopWatch::printThroughput(char **str, size_t *size) +{ + if (0 != mSizeKbytes) + { + SNPRINTF_OR_RETURN(*str, *size, "# Size: %d Kbytes Total: %d\n", mSizeKbytes, mNum); + SNPRINTF_OR_RETURN(*str, *size, "# Speed %f Kbyte/s\n", double(mSizeKbytes) * mNum / mDuration); + } +} +} // namespace android_test diff --git a/tests/sdcard/stopwatch.h b/tests/sdcard/stopwatch.h new file mode 100644 index 00000000..4d1a7949 --- /dev/null +++ b/tests/sdcard/stopwatch.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_STOPWATCH_H_ +#define ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_STOPWATCH_H_ + +#include <stdlib.h> +#include <stdio.h> +#include <time.h> + +namespace android_test { + +// StopWatch class to collect execution statistics. +// +// Once the watch has been created, start and stop can be called to +// capture an event duration. +// +// On completion, use 'sprint' to retrieve the data. +// +// If StopWatch::setPrintRawMode(true) has been called, the raw +// samples also are printed. +// The print method is thread safe to avoid mixing the result of +// watches on different threads. For processes, use different files +// that you concat after the run. +// +// If the time measure is associated with some volume of data, use +// setMbytes, the print method will compute the average throughput +// based on that value. +// +// To capture the time accurately and since the runs are not too long, +// we collect the raw start and stop time in an array that get +// processed once all the measurements have been done. +// +// Typical Usage: +// ============== +// +// StopWatch watch("my name", 20); +// +// for (int i = 0; i < 20; ++i) { +// watch.start(); +// doMyStuff(); +// watch.stop(); +// } +// char buffer[4096]; +// char *str = buffer; +// size_t size = sizeof(buffer); +// watch.sprint(&str, &size); +// + +class StopWatch { + public: + // Time of the snapshot and its nature (start of the interval or end of it). + struct Measurement { + struct timespec mTime; + bool mIsStart; + }; + static const size_t kUseDefaultCapacity = 20; + + // Create a stop watch. Default capacity == 2 * interval_nb + // @param name To be used when the results are displayed. No + // spaces, use _ instead. + // @param capacity Hint about the number of sampless that will be + // measured (1 sample == 1 start + 1 stop). Used + // to size the internal storage, when the capacity + // is reached, it is doubled. + StopWatch(const char *name, size_t capacity = kUseDefaultCapacity); + ~StopWatch(); + + // A StopWatch instance measures time intervals. Use setDataSize + // if some volume of data is processed during these intervals, to + // get the average throughput (in kbytes/s) printed. + void setDataSize(size_t size_in_bytes) { mSizeKbytes = size_in_bytes / 1000; } + + // Starts and stops the timer. The time between the 2 calls is an + // interval whose duration will be reported in sprint. + void start(); + void stop(); + + // Print a summary of the measurement and optionaly the raw data. + // The summary is commented out using a leading '#'. The raw data + // is a pair (time, duration). The 1st sample is always at time + // '0.0'. + // @param str[inout] On entry points to the begining of a buffer + // where to write the data. On exit points pass the last byte + // written. + // @param size[inout] On entry points to the size of the buffer + // pointed by *str. On exit *size is the amount of free space left + // in the buffer. If there was not enough space the data is truncated + // and a warning is printed. + void sprint(char **str, size_t *size); + + // @return true if at least one interval was timed. + bool used() const { return mUsed; } + + // Affects all the timers. Instructs all the timers to print the + // raw data as well as the summary. + static void setPrintRawMode(bool printRaw); + + private: + void checkCapacity(); + double timespecToDouble(const struct timespec& time); + void printAverageMinMax(char **str, size_t *size); + void printThroughput(char **str, size_t *size); + // Allocate mDeltas and fill it in. Search for the min and max. + void processSamples(); + + char *const mName; // Name of the test. + struct timespec mStart; + size_t mNum; // # of intervals == # of start() calls. + struct Measurement *mData; + size_t mDataLen; + size_t mCapacity; + int mSizeKbytes; + + bool mAlreadyPrinted; + bool mPrintRaw; + + double mDuration; + double mMinDuration; + size_t mMinIdx; + double mMaxDuration; + size_t mMaxIdx; + double *mDeltas; + + bool mUsed; +}; + +} // namespace android_test + +#endif // ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_STOPWATCH_H_ diff --git a/tests/sdcard/sysutil.cpp b/tests/sdcard/sysutil.cpp new file mode 100644 index 00000000..0182590a --- /dev/null +++ b/tests/sdcard/sysutil.cpp @@ -0,0 +1,604 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include "sysutil.h" + +namespace { +const int kError = -1; +// Max number of retries on EAGAIN and EINTR. Totally arbitrary. +const int kMaxAttempts = 8; + +// How long to wait after a cache purge. A few seconds (arbitrary). +const int kCachePurgeSleepDuration = 2; // seconds + +const bool kSilentIfMissing = false; + +const char *kKernelVersion = "/proc/version"; +const char *kScalingGovernorFormat = "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor"; +const char *kDropCaches = "/proc/sys/vm/drop_caches"; +const char *kSchedFeatures = "/sys/kernel/debug/sched_features"; +const char *kNewFairSleepers = "NEW_FAIR_SLEEPERS"; +const char *kNoNewFairSleepers = "NO_NEW_FAIR_SLEEPERS"; +const char *kNormalizedSleepers = "NORMALIZED_SLEEPER"; // no 's' at the end +const char *kNoNormalizedSleepers = "NO_NORMALIZED_SLEEPER"; + +const char *kDebugfsWarningMsg = "Did you 'adb root; adb shell mount -t debugfs none /sys/kernel/debug' ?"; + +// TODO: Surely these file utility functions must exist already. A +// quick grep did not turn up anything. Look harder later. + +void printErrno(const char *msg, const char *filename) +{ + fprintf(stderr, "# %s %s %d %s\n", msg, filename, errno, strerror(errno)); +} + +// Read a C-string from a file. If the buffer is too short, an error +// message will be printed on stderr. +// @param filename Of the file to read. +// @param start Buffer where the data should be written to. +// @param size The size of the buffer pointed by str. Must be >= 1. +// @return The number of characters read (not including the trailing'\0' used +// to end the string) or -1 if there was an error. +int readStringFromFile(const char *filename, char *const start, size_t size, bool must_exist=true) +{ + if (NULL == start || size == 0) + { + return 0; + } + char *end = start; + int fd = open(filename, O_RDONLY); + + if (fd < 0) + { + if (ENOENT != errno || must_exist) + { + printErrno("Failed to open", filename); + } + return kError; + } + + bool eof = false; + bool error = false; + int attempts = 0; + + --size; // reserve space for trailing '\0' + + while (size > 0 && !error && !eof && attempts < kMaxAttempts) + { + ssize_t s; + + s = read(fd, end, size); + + if (s < 0) + { + error = EAGAIN != errno && EINTR != errno; + if (error) + { + printErrno("Failed to read", filename); + } + } + else if (0 == s) + { + eof = true; + } + else + { + end += s; + size -= s; + } + ++attempts; + } + + close(fd); + + if (error) + { + return kError; + } + else + { + *end = '\0'; + if (!eof) + { + fprintf(stderr, "Buffer too small for %s\n", filename); + } + return end - start; + } +} + +// Write a C string ('\0' terminated) to a file. +// +int writeStringToFile(const char *filename, const char *start, bool must_exist=true) +{ + int fd = open(filename, O_WRONLY); + + + if (fd < 0) + { + if (ENOENT != errno || must_exist) + { + printErrno("Failed to open", filename); + } + return kError; + } + + const size_t len = strlen(start); + size_t size = len; + bool error = false; + int attempts = 0; + + while (size > 0 && !error && attempts < kMaxAttempts) + { + ssize_t s = write(fd, start, size); + + if (s < 0) + { + error = EAGAIN != errno && EINTR != errno; + if (error) + { + printErrno("Failed to write", filename); + } + } + else + { + start += s; + size -= s; + } + ++attempts; + } + close(fd); + + if (error) + { + return kError; + } + else + { + if (size > 0) + { + fprintf(stderr, "Partial write to %s (%d out of %d)\n", + filename, size, len); + } + return len - size; + } +} + +int writeIntToFile(const char *filename, long value) +{ + char buffer[16] = {0,}; + sprintf(buffer, "%ld", value); + return writeStringToFile(filename, buffer); +} + +// @return a message describing the reason why the child exited. The +// message is in a shared buffer, not thread safe, erased by +// subsequent calls. +const char *reasonChildExited(int status) +{ + static char buffer[80]; + + if (WIFEXITED(status)) + { + snprintf(buffer, sizeof(buffer), "ok (%d)", WEXITSTATUS(status)); + } + else if (WIFSIGNALED(status)) + { + snprintf(buffer, sizeof(buffer), "signaled (%d %s)", WTERMSIG(status), strsignal(WTERMSIG(status))); + } + else + { + snprintf(buffer, sizeof(buffer), "stopped?"); + } + return buffer; +} + + +} // anonymous namespace + +namespace android { + +int kernelVersion(char *str, size_t size) +{ + return readStringFromFile(kKernelVersion, str, size); +} + +int pidOutOfMemoryAdj() +{ + char filename[FILENAME_MAX]; + + snprintf(filename, sizeof(filename), "/proc/%d/oom_adj", getpid()); + + char value[16]; + if (readStringFromFile(filename, value, sizeof(value)) == -1) + { + return -127; + } + else + { + return atoi(value); + } +} + +void setPidOutOfMemoryAdj(int level) +{ + char filename[FILENAME_MAX]; + + snprintf(filename, sizeof(filename), "/proc/%d/oom_adj", getpid()); + writeIntToFile(filename, level); +} + +void disableCpuScaling() +{ + for (int cpu = 0; cpu < 16; ++cpu) // 16 cores mobile phones, abestos pockets recommended. + { + char governor[FILENAME_MAX]; + sprintf(governor, kScalingGovernorFormat, cpu); + + if (writeStringToFile(governor, "performance", kSilentIfMissing) < 0) + { + if (cpu > 0 && errno == ENOENT) + { + break; // cpu1 or above not found, ok since we have cpu0. + } + fprintf(stderr, "Failed to write to scaling governor file for cpu %d: %d %s", + cpu, errno, strerror(errno)); + break; + } + } +} + +int schedFeatures(char *str, size_t size) +{ + return readStringFromFile(kSchedFeatures, str, size); +} + +bool newFairSleepers() +{ + char value[256] = {0,}; + + if (readStringFromFile(kSchedFeatures, value, sizeof(value)) == -1) + { + printErrno(kDebugfsWarningMsg, kSchedFeatures); + return false; + } + return strstr(value, "NO_NEW_FAIR_SLEEPERS") == NULL; +} + +void setNewFairSleepers(bool on) +{ + int retcode; + + if (on) + { + retcode = writeStringToFile(kSchedFeatures, kNewFairSleepers); + } + else + { + retcode = writeStringToFile(kSchedFeatures, kNoNewFairSleepers); + } + if (retcode < 0) + { + fprintf(stderr, "# %s\n", kDebugfsWarningMsg); + } +} + +bool normalizedSleepers() +{ + char value[256] = {0,}; + + if (readStringFromFile(kSchedFeatures, value, sizeof(value)) == -1) + { + printErrno(kDebugfsWarningMsg, kSchedFeatures); + return false; + } + return strstr(value, "NO_NEW_FAIR_SLEEPERS") == NULL; +} + +void setNormalizedSleepers(bool on) +{ + int retcode; + + if (on) + { + retcode = writeStringToFile(kSchedFeatures, kNormalizedSleepers); + } + else + { + retcode = writeStringToFile(kSchedFeatures, kNoNormalizedSleepers); + } + if (retcode < 0) + { + fprintf(stderr, "# %s\n", kDebugfsWarningMsg); + } +} + +pid_t forkOrExit() +{ + pid_t childpid = fork(); + + if (-1 == childpid) + { + fprintf(stderr, "Fork failed: %d %s", errno, strerror(errno)); + exit(EXIT_FAILURE); + } + return childpid; +} + +void waitForChildrenOrExit(int num) +{ + while (num > 0) + { + int status; + pid_t pid = wait(&status); + if (-1 == pid) + { + fprintf(stderr, "Wait failed\n"); + } + else + { + if (!WIFEXITED(status)) + { + fprintf(stderr, "Child pid %d did not exit cleanly %s\n", + pid, reasonChildExited(status)); + exit(EXIT_FAILURE); + } + } + --num; + } +} + +// Sync and cache cleaning functions. In the old hpux days I was told +// to always call *sync twice. The same advice seems to be still true +// today so *sync is called twice. +// Also we wait 'a little' to give a chance to background threads to +// purge their caches. +void syncAndDropCaches(int code) +{ + sync(); + sync(); + writeIntToFile(kDropCaches, code); + sleep(kCachePurgeSleepDuration); +} + + +void fsyncAndDropCaches(int fd, int code) +{ + fsync(fd); + fsync(fd); + writeIntToFile(kDropCaches, code); + sleep(kCachePurgeSleepDuration); +} + + +void resetDirectory(const char *directory) +{ + DIR *dir = opendir(directory); + + if (NULL != dir) + { + struct dirent *entry; + char name_buffer[PATH_MAX]; + + while((entry = readdir(dir))) + { + if (0 == strcmp(entry->d_name, ".") + || 0 == strcmp(entry->d_name, "..") + || 0 == strcmp(entry->d_name, "lost+found")) + { + continue; + } + strcpy(name_buffer, directory); + strcat(name_buffer, "/"); + strcat(name_buffer, entry->d_name); + unlink(name_buffer); + } + closedir(dir); + } else { + mkdir(directory, S_IRWXU); + } +} + + +// IPC +bool writePidAndWaitForReply(int writefd, int readfd) +{ + if (writefd > readfd) + { + fprintf(stderr, "Called with args in wrong order!!\n"); + return false; + } + pid_t pid = getpid(); + char *start = reinterpret_cast<char *>(&pid); + size_t size = sizeof(pid); + bool error = false; + int attempts = 0; + + while (size > 0 && !error && attempts < kMaxAttempts) + { + ssize_t s = write(writefd, start, size); + + if (s < 0) + { + error = EAGAIN != errno && EINTR != errno; + if (error) + { + printErrno("Failed to write", "parent"); + } + } + else + { + start += s; + size -= s; + } + ++attempts; + } + + if (error || 0 != size) + { + return false; + } + + bool eof = false; + char dummy; + size = sizeof(dummy); + error = false; + attempts = 0; + + while (size > 0 && !error && !eof && attempts < kMaxAttempts) + { + ssize_t s; + + s = read(readfd, &dummy, size); + + if (s < 0) + { + error = EAGAIN != errno && EINTR != errno; + if (error) + { + printErrno("Failed to read", "parent"); + } + } + else if (0 == s) + { + eof = true; + } + else + { + size -= s; + } + ++attempts; + } + if (error || 0 != size) + { + return false; + } + return true; +} + + + +bool waitForChildrenAndSignal(int mProcessNb, int readfd, int writefd) +{ + if (readfd > writefd) + { + fprintf(stderr, "Called with args in wrong order!!\n"); + return false; + } + + bool error; + int attempts; + size_t size; + + for (int p = 0; p < mProcessNb; ++p) + { + bool eof = false; + pid_t pid; + char *end = reinterpret_cast<char *>(&pid); + + error = false; + attempts = 0; + size = sizeof(pid); + + while (size > 0 && !error && !eof && attempts < kMaxAttempts) + { + ssize_t s; + + s = read(readfd, end, size); + + if (s < 0) + { + error = EAGAIN != errno && EINTR != errno; + if (error) + { + printErrno("Failed to read", "child"); + } + } + else if (0 == s) + { + eof = true; + } + else + { + end += s; + size -= s; + } + ++attempts; + } + + if (error || 0 != size) + { + return false; + } + } + + for (int p = 0; p < mProcessNb; ++p) + { + char dummy; + + error = false; + attempts = 0; + size = sizeof(dummy); + + while (size > 0 && !error && attempts < kMaxAttempts) + { + ssize_t s = write(writefd, &dummy, size); + + if (s < 0) + { + error = EAGAIN != errno && EINTR != errno; + if (error) + { + printErrno("Failed to write", "child"); + } + } + else + { + size -= s; + } + ++attempts; + } + + if (error || 0 != size) + { + return false; + } + } + return true; +} + +} // namespace android diff --git a/tests/sdcard/sysutil.h b/tests/sdcard/sysutil.h new file mode 100644 index 00000000..3df79c12 --- /dev/null +++ b/tests/sdcard/sysutil.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_SYSUTIL_H_ +#define ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_SYSUTIL_H_ + +#include <stdlib.h> +namespace android { + +// Collection of functions to access the system: +// .kernelVersion Retrieve the full kernel description. +// .pidOutOfMemoryAdj Get and set the OOM adj value. +// .setPidOutOfMemoryAdj +// .schedFeatures Manipulate the scheduler using debugfs. +// .newFairSleepers +// .setNewFairSleepers +// .disableCpuScaling Set cpu scaling to 'performance'. +// .forkOrExit Fork a child or exit. +// .syncAnddropCaches Call sync an drop page/dentries/inodes caches. +// .fsyncAnddropCaches Call fsync an drop page/dentries/inodes caches. +// .resetDirectory Delete (non-recursive) files in a directory. +// +// IPC function to synchonize a processes with their parent. +// .writePidAndWaitForReply To instruct the parent the child is ready. +// Blocks until the parent signals back. +// .waitForChildrenAndSignal Blocks until all the children have called +// writePidAndWaitForReply. +// Then unblock all the children. +// .waitForChildrenOrExit Wait and exit if a child exit with errors. +// + +// Minimum size for the buffer to retrieve the kernel version. +static const size_t kMinKernelVersionBufferSize = 256; + +// @param str points to the buffer where the kernel version should be +// added. Must be at least kMinKernelVersionBufferSize chars. +// @param size of the buffer pointed by str. +// @return If successful the number of characters inserted in the +// buffer (not including the trailing '\0' byte). -1 otherwise. +int kernelVersion(char *str, size_t size); + + +// Return the out of memory adj for this process. /proc/<pid>/oom_adj. +// @return the oom_adj of the current process. Typically: +// 0: a regular process. Should die on OOM. +// -16: system_server level. +// -17: disable, this process will never be killed. +// -127: error. +int pidOutOfMemoryAdj(); +void setPidOutOfMemoryAdj(int level); + +// Disable cpu scaling. +void disableCpuScaling(); + + +// Minimum size for the buffer to retrieve the sched features. +static const size_t kMinSchedFeaturesBufferSize = 256; + +// @param str points to the buffer where the sched features should be +// added. Must be at least kMinSchedFeaturesBufferSize chars. +// @param size of the buffer pointed by str. +// @return If successful the number of characters inserted in the +// buffer (not including the trailing '\0' byte). -1 otherwise. +int schedFeatures(char *str, size_t size); + +// @return true if NEW_FAIR_SLEEPERS is set, false if NO_NEW_FAIR_SLEEPERS is set. +bool newFairSleepers(); + +// Turns NEW_FAIR_SLEEPERS on or off. +void setNewFairSleepers(bool on); + +// @return true if NORMALIZED_SLEEPERS is set, false if NO_NORMALIZED_SLEEPERS is set. +bool normalizedSleepers(); + +// Turns NORMALIZED_SLEEPERS on or off. +void setNormalizedSleepers(bool on); + +// Filesystem + +// Sync and drop caches. Sync is needed because dirty objects are not +// freable. +// @param code: +// * 1 To free pagecache. +// * 2 To free dentries and inodes. +// * 3 To free pagecache, dentries and inodes. +void syncAndDropCaches(int code = 3); + +// Fsync the given fd and drop caches. Fsync is needed because dirty +// objects are not freable. +// @param code: +// * 1 To free pagecache. +// * 2 To free dentries and inodes. +// * 3 To free pagecache, dentries and inodes. +void fsyncAndDropCaches(int fd, int code = 3); + +// Delete all the files in the given directory. If the directory does +// not exist, it is created. Use this at the beginning of a test to +// make sure you have a clean existing directory, previous run may +// have crashed and left clutter around. +void resetDirectory(const char *directory); + +// IPC + +// Try to fork. exit on failure. +pid_t forkOrExit(); + +// Signal our parent we are alive and ready by sending our pid. +// Then do a blocking read for parent's reply. +bool writePidAndWaitForReply(int writefd, int readfd); + +// Wait for all the children to report their pids. +// Then unblock them. +bool waitForChildrenAndSignal(int mProcessNb, int readfd, int writefd); + +// Wait for 'num' children to complete. +// If a child did not exit cleanly, exit. +void waitForChildrenOrExit(int num); + +} // namespace android + +#endif // ANDROID_NATIVETEST_SYSTEM_EXTRAS_TESTS_SDCARD_SYSUTIL_H_ diff --git a/tests/sdcard/testcase.cpp b/tests/sdcard/testcase.cpp new file mode 100644 index 00000000..0de436f7 --- /dev/null +++ b/tests/sdcard/testcase.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "testcase.h" +#include <hardware_legacy/power.h> // wake lock +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <linux/fadvise.h> + +namespace { +const bool kVerbose = false; +} + +namespace android_test { + +TestCase::TestCase(const char *appName) + : mTestBody(NULL), mAppName(appName), mDataSize(1000 * 1000), + mChunkSize(mDataSize), mIter(20), mNproc(1), + mType(UNKNOWN_TEST), mDump(false), mCpuScaling(false), + mSync(NO_SYNC), mFadvice(POSIX_FADV_NORMAL), mTruncateToSize(false), + mTestTimer(NULL) +{ + // Make sure the cpu and phone are fully awake. The + // FULL_WAKE_LOCK was used by java apps and don't do + // anything. Also the partial wake lock is a nop if the phone + // is plugged in via USB. + acquire_wake_lock(PARTIAL_WAKE_LOCK, mAppName); + mPid = getpid(); + setNewFairSleepers(true); + setNormalizedSleepers(true); + if (pipe(mIpc) < 0) + { + fprintf(stderr, "pipe failed\n"); + exit(1); + } + if (pipe(mIpc + 2) < 0) + { + fprintf(stderr, "pipe failed\n"); + exit(1); + } +} + +TestCase::~TestCase() +{ + release_wake_lock(mAppName); + for (int i = 0; i < 4; ++i) close(mIpc[i]); + delete mTestTimer; + delete mOpenTimer; +} + + +bool TestCase::runTest() +{ + if (UNKNOWN_TEST == mType) + { + fprintf(stderr, "No test set."); + return false; + } + for (size_t p = 0; p < mNproc; ++p) + { + pid_t childpid = android::forkOrExit(); + + if (0 == childpid) { // I am a child, run the test. + mPid = getpid(); + close(mIpc[READ_FROM_CHILD]); + close(mIpc[WRITE_TO_CHILD]); + + if (kVerbose) printf("Child pid: %d\n", mPid); + if (!mTestBody(this)) { + printf("Test failed\n"); + } + char buffer[32000] = {0,}; + char *str = buffer; + size_t size_left = sizeof(buffer); + + testTimer()->sprint(&str, &size_left); + if(openTimer()->used()) openTimer()->sprint(&str, &size_left); + if(readTimer()->used()) readTimer()->sprint(&str, &size_left); + if(writeTimer()->used()) writeTimer()->sprint(&str, &size_left); + if(syncTimer()->used()) syncTimer()->sprint(&str, &size_left); + if(truncateTimer()->used()) truncateTimer()->sprint(&str, &size_left); + + write(mIpc[TestCase::WRITE_TO_PARENT], buffer, str - buffer); + + + close(mIpc[WRITE_TO_PARENT]); + close(mIpc[READ_FROM_PARENT]); + exit(EXIT_SUCCESS); + } + } + // I am the parent process + close(mIpc[WRITE_TO_PARENT]); + close(mIpc[READ_FROM_PARENT]); + + // Block until all the children have reported for + // duty. Unblock them so they start the work. + if (!android::waitForChildrenAndSignal(mNproc, mIpc[READ_FROM_CHILD], mIpc[WRITE_TO_CHILD])) + { + exit(1); + } + + // Process the output of each child. + // TODO: handle EINTR + char buffer[32000] = {0,}; + while(read(mIpc[READ_FROM_CHILD], buffer, sizeof(buffer)) != 0) + { + printf("%s", buffer); + fflush(stdout); + memset(buffer, 0, sizeof(buffer)); + } + // Parent is waiting for children to exit. + android::waitForChildrenOrExit(mNproc); + return true; +} + +void TestCase::setIter(size_t iter) +{ + mIter = iter; +} + +void TestCase::createTimers() +{ + char total_time[80]; + + snprintf(total_time, sizeof(total_time), "%s_total", mName); + mTestTimer = new StopWatch(total_time, 1); + mTestTimer->setDataSize(dataSize()); + + mOpenTimer = new StopWatch("open", iter() * kReadWriteFactor); + + mReadTimer = new StopWatch("read", iter() * dataSize() / chunkSize() * kReadWriteFactor); + mReadTimer->setDataSize(dataSize()); + + mWriteTimer = new StopWatch("write", iter() * dataSize() / chunkSize()); + mWriteTimer->setDataSize(dataSize()); + + mSyncTimer = new StopWatch("sync", iter()); + + mTruncateTimer = new StopWatch("truncate", iter()); +} + +bool TestCase::setTypeFromName(const char *test_name) +{ + strcpy(mName, test_name); + if (strcmp(mName, "write") == 0) mType = WRITE; + if (strcmp(mName, "read") == 0) mType = READ; + if (strcmp(mName, "read_write") == 0) mType = READ_WRITE; + if (strcmp(mName, "open_create") == 0) mType = OPEN_CREATE; + + return UNKNOWN_TEST != mType; +} + +void TestCase::setSync(Sync s) +{ + mSync = s; +} + +const char *TestCase::syncAsStr() const +{ + return mSync == NO_SYNC ? "disabled" : (mSync == FSYNC ? "fsync" : "sync"); +} + +void TestCase::setFadvise(const char *advice) +{ + mFadvice = POSIX_FADV_NORMAL; + if (strcmp(advice, "sequential") == 0) + { + mFadvice = POSIX_FADV_SEQUENTIAL; + } + else if (strcmp(advice, "random") == 0) + { + mFadvice = POSIX_FADV_RANDOM; + } + else if (strcmp(advice, "noreuse") == 0) + { + mFadvice = POSIX_FADV_NOREUSE; + } + else if (strcmp(advice, "willneed") == 0) + { + mFadvice = POSIX_FADV_WILLNEED; + } + else if (strcmp(advice, "dontneed") == 0) + { + mFadvice = POSIX_FADV_DONTNEED; + } +} + +const char *TestCase::fadviseAsStr() const +{ + switch (mFadvice) { + case POSIX_FADV_NORMAL: return "fadv_normal"; + case POSIX_FADV_SEQUENTIAL: return "fadv_sequential"; + case POSIX_FADV_RANDOM: return "fadv_random"; + case POSIX_FADV_NOREUSE: return "fadv_noreuse"; + case POSIX_FADV_WILLNEED: return "fadv_willneed"; + case POSIX_FADV_DONTNEED: return "fadv_dontneed"; + default: return "fadvice_unknown"; + } +} + + +} // namespace android_test diff --git a/tests/sdcard/testcase.h b/tests/sdcard/testcase.h new file mode 100644 index 00000000..66af9d63 --- /dev/null +++ b/tests/sdcard/testcase.h @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef SYSTEM_EXTRAS_TESTS_SDCARD_TESTCASE_H_ +#define SYSTEM_EXTRAS_TESTS_SDCARD_TESTCASE_H_ + +#include <stdlib.h> +#include "stopwatch.h" +#include "sysutil.h" + +namespace android_test { + +// Class to group test parameters and implementation. +// Takes care of forking child processes and wait for them. + +class TestCase { + public: + enum Type {UNKNOWN_TEST, WRITE, READ, OPEN_CREATE, READ_WRITE}; + enum Pipe {READ_FROM_CHILD = 0, WRITE_TO_PARENT, READ_FROM_PARENT, WRITE_TO_CHILD}; + enum Sync {NO_SYNC, FSYNC, SYNC}; + + // Reads takes less time than writes. This is a basic + // approximation of how much longer the read tasks must run to + // terminate roughly at the same time as the write tasks. + const static int kReadWriteFactor = 5; + + TestCase(const char *appName); + + ~TestCase(); + + size_t iter() const { return mIter; } + void setIter(size_t iter); + + size_t nproc() const { return mNproc; } + void setNproc(size_t val) { mNproc = val; } + + size_t dataSize() const { return mDataSize; } + void setDataSize(size_t val) { mDataSize = val; } + + size_t chunkSize() const { return mChunkSize; } + void setChunkSize(size_t val) { mChunkSize = val; } + + bool newFairSleepers() const { return mNewFairSleepers; } + void setNewFairSleepers(bool val) { + mNewFairSleepers = val; + android::setNewFairSleepers(val); + } + + bool normalizedSleepers() const { return mNormalizedSleepers; } + void setNormalizedSleepers(bool val) { + mNormalizedSleepers = val; + android::setNormalizedSleepers(val); + } + + Sync sync() const { return mSync; } + void setSync(Sync s); + const char *syncAsStr() const; + + bool cpuScaling() const { return mCpuScaling; } + void setCpuScaling() { mCpuScaling = true; } + + bool truncateToSize() const { return mTruncateToSize; } + void setTruncateToSize() { mTruncateToSize = true; } + + int fadvise() { return mFadvice; } + void setFadvise(const char *advice); + const char *fadviseAsStr() const; + + // Print the samples. + void setDump() { StopWatch::setPrintRawMode(true); } + + StopWatch *testTimer() { return mTestTimer; } + StopWatch *openTimer() { return mOpenTimer; } + StopWatch *readTimer() { return mReadTimer; } + StopWatch *writeTimer() { return mWriteTimer; } + StopWatch *syncTimer() { return mSyncTimer; } + StopWatch *truncateTimer() { return mTruncateTimer; } + + // Fork the children, run the test and wait for them to complete. + bool runTest(); + + void signalParentAndWait() { + if (!android::writePidAndWaitForReply(mIpc[WRITE_TO_PARENT], mIpc[READ_FROM_PARENT])) { + exit(1); + } + } + + void createTimers(); + bool setTypeFromName(const char *test_name); + Type type() const { return mType; } + pid_t pid() const { return mPid; } + const char *name() const { return mName; } + + // This is set to the function that will actually do the test when + // the command line arguments have been parsed. The function will + // be run in one or more child(ren) process(es). + bool (*mTestBody)(TestCase *); +private: + const char *mAppName; + size_t mDataSize; + size_t mChunkSize; + size_t mIter; + size_t mNproc; + pid_t mPid; + char mName[80]; + Type mType; + + bool mDump; // print the raw values instead of a human friendly report. + bool mCpuScaling; // true, do not turn off cpu scaling. + Sync mSync; + int mFadvice; + // When new files are created, truncate them to the final size. + bool mTruncateToSize; + + bool mNewFairSleepers; + bool mNormalizedSleepers; + + // IPC + // Parent Child(ren) + // --------------------------------------- + // 0: read from child closed + // 1: closed write to parent + // 2: closed read from parent + // 3: write to child closed + int mIpc[4]; + + StopWatch *mTestTimer; // Used to time the test overall. + StopWatch *mOpenTimer; // Used to time the open calls. + StopWatch *mReadTimer; // Used to time the read calls. + StopWatch *mWriteTimer; // Used to time the write calls. + StopWatch *mSyncTimer; // Used to time the sync/fsync calls. + StopWatch *mTruncateTimer; // Used to time the ftruncate calls. +}; + +} // namespace android_test + +#endif // SYSTEM_EXTRAS_TESTS_SDCARD_TESTCASE_H_ diff --git a/tests/timetest/Android.mk b/tests/timetest/Android.mk new file mode 100644 index 00000000..05e21fbe --- /dev/null +++ b/tests/timetest/Android.mk @@ -0,0 +1,19 @@ +# Copyright 2006 The Android Open Source Project + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= timetest.c + +LOCAL_MODULE:= timetest + +LOCAL_MODULE_TAGS := optional + +LOCAL_FORCE_STATIC_EXECUTABLE := true +LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN) +LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED) + +LOCAL_STATIC_LIBRARIES := libc + +include $(BUILD_EXECUTABLE) + diff --git a/tests/timetest/timetest.c b/tests/timetest/timetest.c new file mode 100644 index 00000000..baba36e2 --- /dev/null +++ b/tests/timetest/timetest.c @@ -0,0 +1,113 @@ +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/limits.h> +#include <sys/time.h> +#include <time.h> +#include <errno.h> + +#include <string.h> + + + +long long nanotime(void) +{ + struct timespec t; + + if(clock_gettime(CLOCK_MONOTONIC, &t)) { + fprintf(stderr,"clock failure\n"); + exit(1); + } + + return (((long long) t.tv_sec) * 1000000000LL) + + ((long long) t.tv_nsec); +} + +static struct timespec ts_sub(struct timespec a, struct timespec b) +{ + struct timespec r; + r.tv_sec = a.tv_sec - b.tv_sec; + r.tv_nsec = a.tv_nsec - b.tv_nsec; + if(r.tv_nsec < 0) { + r.tv_sec--; + r.tv_nsec += 1000 * 1000 * 1000; + } + if(r.tv_sec < 0 && r.tv_nsec > 0) { + r.tv_sec++; + r.tv_nsec -= 1000 * 1000 * 1000; + } + return r; +} + +static struct timespec ts_min(struct timespec a, struct timespec b) +{ + if(a.tv_sec < b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_nsec < b.tv_nsec)) + return a; + else + return b; +} + +static struct timespec ts_max(struct timespec a, struct timespec b) +{ + if(a.tv_sec < b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_nsec < b.tv_nsec)) + return b; + else + return a; +} + +int main(int argc, char **argv) +{ + long long tnow, tlast; + struct timespec t1, dtmin, dtminp, dtmax; + int print_interval = 50000; + int print_countdown = 1; + int clock_id = CLOCK_MONOTONIC; + dtmin.tv_sec = INT_MAX; + dtmin.tv_nsec = 0; + dtminp.tv_sec = INT_MAX; + dtminp.tv_nsec = 0; + dtmax.tv_sec = 0; + dtmax.tv_nsec = 0; + tlast = 0; + + if(argc == 2) { + clock_id = atoi(argv[1]); + printf("using clock %d\n", clock_id); + } + clock_gettime(clock_id, &t1); + + for(;;) { + struct timespec t, dt; + clock_gettime(clock_id, &t); + dt = ts_sub(t, t1); + t1 = t; + dtmin = ts_min(dtmin, dt); + if(dt.tv_sec > 0 || dt.tv_nsec > 0) + dtminp = ts_min(dtminp, dt); + if(print_countdown != print_interval) + dtmax = ts_max(dtmax, dt); + if(--print_countdown == 0) { + fprintf(stderr,"%09ld.%09ld, dt %ld.%09ld, min %ld.%09ld, minp %ld.%09ld, max %ld.%09ld\n", + t.tv_sec, t.tv_nsec, dt.tv_sec, dt.tv_nsec, + dtmin.tv_sec, dtmin.tv_nsec, dtminp.tv_sec, dtminp.tv_nsec, + dtmax.tv_sec, dtmax.tv_nsec); + print_countdown = print_interval; + } + } + for(;;) { + tnow = nanotime(); + if(tnow < tlast) { +#if 0 + fprintf(stderr,"time went backwards: %lld -> %lld\n", + tlast, tnow); + exit(1); +#endif + fprintf(stderr,"%lld ROLLBACK\n", tnow); + } else { + fprintf(stderr,"%lld\n", tnow); + } + tlast = tnow; + } + + return 0; +} |