summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Baptiste Queru <jbq@google.com>2009-07-25 17:48:03 -0700
committerJean-Baptiste Queru <jbq@google.com>2009-07-25 17:48:03 -0700
commite92807b964bef9b003f39ae1c3be6bf379f148dd (patch)
tree7897f601a22692f33a69ff9ce9f5fbd07b27dc91
parent1f6b24cf6ead1186657d5fe93e88eb868f8a7bcc (diff)
parent360efc12dcfece46e5999505bd8042cba56a4289 (diff)
downloadextras-e92807b964bef9b003f39ae1c3be6bf379f148dd.tar.gz
Merge korg/donut into korg/master
-rw-r--r--backup/Android.mk2
-rw-r--r--backup/backup.cpp40
-rw-r--r--showmap/showmap.c7
-rw-r--r--sound/Android.mk2
-rw-r--r--tests/bionic/libc/Android.mk20
-rw-r--r--tests/bionic/libc/README.TXT2
-rw-r--r--tests/bionic/libc/bionic/lib_static_init.cpp18
-rw-r--r--tests/bionic/libc/bionic/lib_static_init.h15
-rw-r--r--tests/bionic/libc/bionic/test_static_init.cpp30
-rw-r--r--tests/bionic/libc/common/test_getaddrinfo.c44
-rw-r--r--tests/bionic/libstdc++/Android.mk80
-rw-r--r--tests/bionic/libstdc++/README.TXT19
-rw-r--r--tests/bionic/libstdc++/test_cassert.cpp49
-rw-r--r--tests/bionic/libstdc++/test_cctype.cpp100
-rw-r--r--tests/bionic/libstdc++/test_climits.cpp88
-rw-r--r--tests/bionic/libstdc++/test_cmath.cpp75
-rw-r--r--tests/bionic/libstdc++/test_csetjmp.cpp65
-rw-r--r--tests/bionic/libstdc++/test_csignal.cpp68
-rw-r--r--tests/bionic/libstdc++/test_cstddef.cpp103
-rw-r--r--tests/bionic/libstdc++/test_cstdint.cpp45
-rw-r--r--tests/bionic/libstdc++/test_cstdio.cpp166
-rw-r--r--tests/bionic/libstdc++/test_cstdlib.cpp49
-rw-r--r--tests/bionic/libstdc++/test_cstring.cpp76
-rw-r--r--tests/bionic/libstdc++/test_ctime.cpp110
-rw-r--r--tests/framebuffer/Android.mk4
-rw-r--r--tests/framebuffer/fb_test.c39
-rw-r--r--tests/fstest/Android.mk4
-rw-r--r--tests/fstest/perm_checker.conf8
-rw-r--r--tests/icachetest/Android.mk2
-rw-r--r--tests/memtest/Android.mk2
-rw-r--r--tests/sdcard/Android.mk37
-rwxr-xr-xtests/sdcard/plot_sdcard.py331
-rwxr-xr-xtests/sdcard/profile_sdcard.sh64
-rw-r--r--tests/sdcard/sdcard_perf_test.cpp607
-rw-r--r--tests/sdcard/stopwatch.cpp226
-rw-r--r--tests/sdcard/stopwatch.h155
-rw-r--r--tests/sdcard/sysutil.cpp604
-rw-r--r--tests/sdcard/sysutil.h146
-rw-r--r--tests/sdcard/testcase.cpp228
-rw-r--r--tests/sdcard/testcase.h163
-rw-r--r--tests/timetest/Android.mk19
-rw-r--r--tests/timetest/timetest.c113
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;
+}