Project import
diff --git a/tests/Android.mk b/tests/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/tests/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/tests/NOTICE b/tests/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/tests/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/tests/audio/Android.mk b/tests/audio/Android.mk
new file mode 100644
index 0000000..f69a2fc
--- /dev/null
+++ b/tests/audio/Android.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2013 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.
+#
+
+include $(call all-subdir-makefiles)
diff --git a/tests/audio/alsa/Android.mk b/tests/audio/alsa/Android.mk
new file mode 100644
index 0000000..c6e5a8a
--- /dev/null
+++ b/tests/audio/alsa/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2013 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := pcmtest
+LOCAL_SRC_FILES := pcmtest.cpp
+LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libtinyalsa
+LOCAL_STATIC_LIBRARIES += libtestUtil
+LOCAL_C_INCLUDES += system/extras/tests/include external/tinyalsa/include
+
+include $(BUILD_NATIVE_TEST)
diff --git a/tests/audio/alsa/pcmtest.cpp b/tests/audio/alsa/pcmtest.cpp
new file mode 100644
index 0000000..7233e10
--- /dev/null
+++ b/tests/audio/alsa/pcmtest.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2013 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 requied 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.
+ *
+ */
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <gtest/gtest.h>
+#include <linux/ioctl.h>
+#define __force
+#define __bitwise
+#define __user
+#include <sound/asound.h>
+#include <sys/types.h>
+#include <tinyalsa/asoundlib.h>
+
+#define LOG_TAG "pcmtest"
+#include <utils/Log.h>
+#include <testUtil.h>
+
+#define PCM_PREFIX "pcm"
+#define MIXER_PREFIX "control"
+#define TIMER_PREFIX "timer"
+
+const char kSoundDir[] = "/dev/snd";
+
+typedef struct PCM_NODE {
+ unsigned int card;
+ unsigned int device;
+ unsigned int flags;
+} pcm_node_t;
+
+static pcm_node_t *pcmnodes;
+
+static unsigned int pcms;
+static unsigned int cards;
+static unsigned int mixers;
+static unsigned int timers;
+
+unsigned int getPcmNodes(void)
+{
+ DIR *d;
+ struct dirent *de;
+ unsigned int pcount = 0;
+
+ d = opendir(kSoundDir);
+ if (d == 0)
+ return 0;
+ while ((de = readdir(d)) != NULL) {
+ if (de->d_name[0] == '.')
+ continue;
+ if (strstr(de->d_name, PCM_PREFIX))
+ pcount++;
+ }
+ closedir(d);
+ return pcount;
+}
+
+int getSndDev(unsigned int pcmdevs)
+{
+ DIR *d;
+ struct dirent *de;
+ unsigned int prevcard = -1;
+
+ d = opendir(kSoundDir);
+ if (d == 0)
+ return -ENXIO;
+ pcmnodes = (pcm_node_t *)malloc(pcmdevs * sizeof(pcm_node_t));
+ if (!pcmnodes)
+ return -ENOMEM;
+ pcms = 0;
+ while ((de = readdir(d)) != NULL) {
+ if (de->d_name[0] == '.')
+ continue;
+ /* printf("%s\n", de->d_name); */
+ if (strstr(de->d_name, PCM_PREFIX)) {
+ char flags;
+
+ EXPECT_LE(pcms, pcmdevs) << "Too many PCMs";
+ if (pcms >= pcmdevs)
+ continue;
+ sscanf(de->d_name, PCM_PREFIX "C%uD%u", &(pcmnodes[pcms].card),
+ &(pcmnodes[pcms].device));
+ flags = de->d_name[strlen(de->d_name)-1];
+ if (flags == 'c') {
+ pcmnodes[pcms].flags = PCM_IN;
+ } else if(flags == 'p') {
+ pcmnodes[pcms].flags = PCM_OUT;
+ } else {
+ pcmnodes[pcms].flags = -1;
+ testPrintI("Unknown PCM type = %c", flags);
+ }
+ if (prevcard != pcmnodes[pcms].card)
+ cards++;
+ prevcard = pcmnodes[pcms].card;
+ pcms++;
+ continue;
+ }
+ if (strstr(de->d_name, MIXER_PREFIX)) {
+ unsigned int mixer = -1;
+ sscanf(de->d_name, MIXER_PREFIX "C%u", &mixer);
+ mixers++;
+ continue;
+ }
+ if (strstr(de->d_name, TIMER_PREFIX)) {
+ timers++;
+ continue;
+ }
+ }
+ closedir(d);
+ return 0;
+}
+
+int getPcmParams(unsigned int i)
+{
+ struct pcm_params *params;
+ unsigned int min;
+ unsigned int max;
+
+ params = pcm_params_get(pcmnodes[i].card, pcmnodes[i].device,
+ pcmnodes[i].flags);
+ if (params == NULL)
+ return -ENODEV;
+
+ min = pcm_params_get_min(params, PCM_PARAM_RATE);
+ max = pcm_params_get_max(params, PCM_PARAM_RATE);
+ EXPECT_LE(min, max);
+ /* printf(" Rate:\tmin=%uHz\tmax=%uHz\n", min, max); */
+ min = pcm_params_get_min(params, PCM_PARAM_CHANNELS);
+ max = pcm_params_get_max(params, PCM_PARAM_CHANNELS);
+ EXPECT_LE(min, max);
+ /* printf(" Channels:\tmin=%u\t\tmax=%u\n", min, max); */
+ min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS);
+ max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS);
+ EXPECT_LE(min, max);
+ /* printf(" Sample bits:\tmin=%u\t\tmax=%u\n", min, max); */
+ min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE);
+ max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE);
+ EXPECT_LE(min, max);
+ /* printf(" Period size:\tmin=%u\t\tmax=%u\n", min, max); */
+ min = pcm_params_get_min(params, PCM_PARAM_PERIODS);
+ max = pcm_params_get_max(params, PCM_PARAM_PERIODS);
+ EXPECT_LE(min, max);
+ /* printf("Period count:\tmin=%u\t\tmax=%u\n", min, max); */
+
+ pcm_params_free(params);
+ return 0;
+}
+
+TEST(pcmtest, CheckAudioDir) {
+ pcms = getPcmNodes();
+ ASSERT_GT(pcms, 0U);
+}
+
+TEST(pcmtest, GetSoundDevs) {
+ int err = getSndDev(pcms);
+ testPrintI(" DEVICES = PCMS:%u CARDS:%u MIXERS:%u TIMERS:%u",
+ pcms, cards, mixers, timers);
+ ASSERT_EQ(0, err);
+}
+
+TEST(pcmtest, CheckPcmSanity0) {
+ ASSERT_NE(0U, pcms);
+}
+
+TEST(pcmtest, CheckPcmSanity1) {
+ EXPECT_NE(1U, pcms % 2);
+}
+
+TEST(pcmtests, CheckMixerSanity) {
+ ASSERT_NE(0U, mixers);
+ ASSERT_EQ(mixers, cards);
+}
+
+TEST(pcmtest, CheckTimesSanity0) {
+ ASSERT_NE(0U, timers);
+}
+
+TEST(pcmtest, CheckTimesSanity1) {
+ EXPECT_EQ(1U, timers);
+}
+
+TEST(pcmtest, CheckPcmDevices) {
+ for (unsigned int i = 0; i < pcms; i++) {
+ EXPECT_EQ(0, getPcmParams(i));
+ }
+ free(pcmnodes);
+}
+
+TEST(pcmtest, CheckMixerDevices) {
+ struct mixer *mixer;
+ for (unsigned int i = 0; i < mixers; i++) {
+ mixer = mixer_open(i);
+ EXPECT_TRUE(mixer != NULL);
+ if (mixer)
+ mixer_close(mixer);
+ }
+}
+
+TEST(pcmtest, CheckTimer) {
+ int ver = 0;
+ int fd = open("/dev/snd/timer", O_RDWR | O_NONBLOCK);
+ ASSERT_GE(fd, 0);
+ int ret = ioctl(fd, SNDRV_TIMER_IOCTL_PVERSION, &ver);
+ EXPECT_EQ(0, ret);
+ testPrintI(" Timer Version = 0x%x", ver);
+ close(fd);
+}
diff --git a/tests/binder/Android.mk b/tests/binder/Android.mk
new file mode 100644
index 0000000..4343259
--- /dev/null
+++ b/tests/binder/Android.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2010 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.
+#
+
+include $(call all-subdir-makefiles)
diff --git a/tests/binder/benchmarks/Android.mk b/tests/binder/benchmarks/Android.mk
new file mode 100644
index 0000000..eb2ead2
--- /dev/null
+++ b/tests/binder/benchmarks/Android.mk
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2010 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_MODULE_TAGS := eng tests
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativebenchmark
+
+LOCAL_STATIC_LIBRARIES += \
+ libtestUtil
+
+LOCAL_SHARED_LIBRARIES += \
+ libutils \
+ liblog \
+ libbinder
+
+LOCAL_C_INCLUDES += \
+ system/extras/tests/include \
+ frameworks/base/include
+
+LOCAL_MODULE := binderAddInts
+LOCAL_SRC_FILES := binderAddInts.cpp
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/binder/benchmarks/binderAddInts.cpp b/tests/binder/benchmarks/binderAddInts.cpp
new file mode 100644
index 0000000..f061f7c
--- /dev/null
+++ b/tests/binder/benchmarks/binderAddInts.cpp
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2010 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.
+ *
+ */
+
+/*
+ * Binder add integers benchmark
+ *
+ * Measures the rate at which a short binder IPC operation can be
+ * performed. The operation consists of the client sending a parcel
+ * that contains two integers. For each parcel that the server
+ * receives, it adds the two integers and sends the sum back to
+ * the client.
+ *
+ * This benchmark supports the following command-line options:
+ *
+ * -c cpu - bind client to specified cpu (default: unbound)
+ * -s cpu - bind server to specified cpu (default: unbound)
+ * -n num - perform IPC operation num times (default: 1000)
+ * -d time - delay specified amount of seconds after each
+ * IPC operation. (default 1e-3)
+ */
+
+#include <cerrno>
+#include <grp.h>
+#include <iostream>
+#include <libgen.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+#include <testUtil.h>
+
+using namespace android;
+using namespace std;
+
+const int unbound = -1; // Indicator for a thread not bound to a specific CPU
+
+String16 serviceName("test.binderAddInts");
+
+struct options {
+ int serverCPU;
+ int clientCPU;
+ unsigned int iterations;
+ float iterDelay; // End of iteration delay in seconds
+} options = { // Set defaults
+ unbound, // Server CPU
+ unbound, // Client CPU
+ 1000, // Iterations
+ 1e-3, // End of iteration delay
+};
+
+class AddIntsService : public BBinder
+{
+ public:
+ explicit AddIntsService(int cpu = unbound);
+ virtual ~AddIntsService() {}
+
+ enum command {
+ ADD_INTS = 0x120,
+ };
+
+ virtual status_t onTransact(uint32_t code,
+ const Parcel& data, Parcel* reply,
+ uint32_t flags = 0);
+
+ private:
+ int cpu_;
+};
+
+// File scope function prototypes
+static void server(void);
+static void client(void);
+static void bindCPU(unsigned int cpu);
+static ostream &operator<<(ostream &stream, const String16& str);
+static ostream &operator<<(ostream &stream, const cpu_set_t& set);
+
+int main(int argc, char *argv[])
+{
+ int rv;
+
+ // Determine CPUs available for use.
+ // This testcase limits its self to using CPUs that were
+ // available at the start of the benchmark.
+ cpu_set_t availCPUs;
+ if ((rv = sched_getaffinity(0, sizeof(availCPUs), &availCPUs)) != 0) {
+ cerr << "sched_getaffinity failure, rv: " << rv
+ << " errno: " << errno << endl;
+ exit(1);
+ }
+
+ // Parse command line arguments
+ int opt;
+ while ((opt = getopt(argc, argv, "s:c:n:d:?")) != -1) {
+ char *chptr; // character pointer for command-line parsing
+
+ switch (opt) {
+ case 'c': // client CPU
+ case 's': { // server CPU
+ // Parse the CPU number
+ int cpu = strtoul(optarg, &chptr, 10);
+ if (*chptr != '\0') {
+ cerr << "Invalid cpu specified for -" << (char) opt
+ << " option of: " << optarg << endl;
+ exit(2);
+ }
+
+ // Is the CPU available?
+ if (!CPU_ISSET(cpu, &availCPUs)) {
+ cerr << "CPU " << optarg << " not currently available" << endl;
+ cerr << " Available CPUs: " << availCPUs << endl;
+ exit(3);
+ }
+
+ // Record the choice
+ *((opt == 'c') ? &options.clientCPU : &options.serverCPU) = cpu;
+ break;
+ }
+
+ case 'n': // iterations
+ options.iterations = strtoul(optarg, &chptr, 10);
+ if (*chptr != '\0') {
+ cerr << "Invalid iterations specified of: " << optarg << endl;
+ exit(4);
+ }
+ if (options.iterations < 1) {
+ cerr << "Less than 1 iteration specified by: "
+ << optarg << endl;
+ exit(5);
+ }
+ break;
+
+ case 'd': // Delay between each iteration
+ options.iterDelay = strtod(optarg, &chptr);
+ if ((*chptr != '\0') || (options.iterDelay < 0.0)) {
+ cerr << "Invalid delay specified of: " << optarg << endl;
+ exit(6);
+ }
+ break;
+
+ case '?':
+ default:
+ cerr << basename(argv[0]) << " [options]" << endl;
+ cerr << " options:" << endl;
+ cerr << " -s cpu - server CPU number" << endl;
+ cerr << " -c cpu - client CPU number" << endl;
+ cerr << " -n num - iterations" << endl;
+ cerr << " -d time - delay after operation in seconds" << endl;
+ exit(((optopt == 0) || (optopt == '?')) ? 0 : 7);
+ }
+ }
+
+ // Display selected options
+ cout << "serverCPU: ";
+ if (options.serverCPU == unbound) {
+ cout << " unbound";
+ } else {
+ cout << options.serverCPU;
+ }
+ cout << endl;
+ cout << "clientCPU: ";
+ if (options.clientCPU == unbound) {
+ cout << " unbound";
+ } else {
+ cout << options.clientCPU;
+ }
+ cout << endl;
+ cout << "iterations: " << options.iterations << endl;
+ cout << "iterDelay: " << options.iterDelay << endl;
+
+ // Fork client, use this process as server
+ fflush(stdout);
+ switch (pid_t pid = fork()) {
+ case 0: // Child
+ client();
+ return 0;
+
+ default: // Parent
+ server();
+
+ // Wait for all children to end
+ do {
+ int stat;
+ rv = wait(&stat);
+ if ((rv == -1) && (errno == ECHILD)) { break; }
+ if (rv == -1) {
+ cerr << "wait failed, rv: " << rv << " errno: "
+ << errno << endl;
+ perror(NULL);
+ exit(8);
+ }
+ } while (1);
+ return 0;
+
+ case -1: // Error
+ exit(9);
+ }
+
+ return 0;
+}
+
+static void server(void)
+{
+ int rv;
+
+ // Add the service
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm = defaultServiceManager();
+ if ((rv = sm->addService(serviceName,
+ new AddIntsService(options.serverCPU))) != 0) {
+ cerr << "addService " << serviceName << " failed, rv: " << rv
+ << " errno: " << errno << endl;
+ }
+
+ // Start threads to handle server work
+ proc->startThreadPool();
+}
+
+static void client(void)
+{
+ int rv;
+ sp<IServiceManager> sm = defaultServiceManager();
+ double min = FLT_MAX, max = 0.0, total = 0.0; // Time in seconds for all
+ // the IPC calls.
+
+ // If needed bind to client CPU
+ if (options.clientCPU != unbound) { bindCPU(options.clientCPU); }
+
+ // Attach to service
+ sp<IBinder> binder;
+ do {
+ binder = sm->getService(serviceName);
+ if (binder != 0) break;
+ cout << serviceName << " not published, waiting..." << endl;
+ usleep(500000); // 0.5 s
+ } while(true);
+
+ // Perform the IPC operations
+ for (unsigned int iter = 0; iter < options.iterations; iter++) {
+ Parcel send, reply;
+
+ // Create parcel to be sent. Will use the iteration cound
+ // and the iteration count + 3 as the two integer values
+ // to be sent.
+ int val1 = iter;
+ int val2 = iter + 3;
+ int expected = val1 + val2; // Expect to get the sum back
+ send.writeInt32(val1);
+ send.writeInt32(val2);
+
+ // Send the parcel, while timing how long it takes for
+ // the answer to return.
+ struct timespec start;
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ if ((rv = binder->transact(AddIntsService::ADD_INTS,
+ send, &reply)) != 0) {
+ cerr << "binder->transact failed, rv: " << rv
+ << " errno: " << errno << endl;
+ exit(10);
+ }
+ struct timespec current;
+ clock_gettime(CLOCK_MONOTONIC, ¤t);
+
+ // Calculate how long this operation took and update the stats
+ struct timespec deltaTimespec = tsDelta(&start, ¤t);
+ double delta = ts2double(&deltaTimespec);
+ min = (delta < min) ? delta : min;
+ max = (delta > max) ? delta : max;
+ total += delta;
+ int result = reply.readInt32();
+ if (result != (int) (iter + iter + 3)) {
+ cerr << "Unexpected result for iteration " << iter << endl;
+ cerr << " result: " << result << endl;
+ cerr << "expected: " << expected << endl;
+ }
+
+ if (options.iterDelay > 0.0) { testDelaySpin(options.iterDelay); }
+ }
+
+ // Display the results
+ cout << "Time per iteration min: " << min
+ << " avg: " << (total / options.iterations)
+ << " max: " << max
+ << endl;
+}
+
+AddIntsService::AddIntsService(int cpu): cpu_(cpu) {
+ if (cpu != unbound) { bindCPU(cpu); }
+}
+
+// Server function that handles parcels received from the client
+status_t AddIntsService::onTransact(uint32_t code, const Parcel &data,
+ Parcel* reply, uint32_t /* flags */) {
+ int val1, val2;
+ status_t rv(0);
+ int cpu;
+
+ // If server bound to a particular CPU, check that
+ // were executing on that CPU.
+ if (cpu_ != unbound) {
+ cpu = sched_getcpu();
+ if (cpu != cpu_) {
+ cerr << "server onTransact on CPU " << cpu << " expected CPU "
+ << cpu_ << endl;
+ exit(20);
+ }
+ }
+
+ // Perform the requested operation
+ switch (code) {
+ case ADD_INTS:
+ val1 = data.readInt32();
+ val2 = data.readInt32();
+ reply->writeInt32(val1 + val2);
+ break;
+
+ default:
+ cerr << "server onTransact unknown code, code: " << code << endl;
+ exit(21);
+ }
+
+ return rv;
+}
+
+static void bindCPU(unsigned int cpu)
+{
+ int rv;
+ cpu_set_t cpuset;
+
+ CPU_ZERO(&cpuset);
+ CPU_SET(cpu, &cpuset);
+ rv = sched_setaffinity(0, sizeof(cpuset), &cpuset);
+
+ if (rv != 0) {
+ cerr << "bindCPU failed, rv: " << rv << " errno: " << errno << endl;
+ perror(NULL);
+ exit(30);
+ }
+}
+
+static ostream &operator<<(ostream &stream, const String16& str)
+{
+ for (unsigned int n1 = 0; n1 < str.size(); n1++) {
+ if ((str[n1] > 0x20) && (str[n1] < 0x80)) {
+ stream << (char) str[n1];
+ } else {
+ stream << '~';
+ }
+ }
+
+ return stream;
+}
+
+static ostream &operator<<(ostream &stream, const cpu_set_t& set)
+{
+ for (unsigned int n1 = 0; n1 < CPU_SETSIZE; n1++) {
+ if (CPU_ISSET(n1, &set)) {
+ if (n1 != 0) { stream << ' '; }
+ stream << n1;
+ }
+ }
+
+ return stream;
+}
diff --git a/tests/bootloader/bootctl.py b/tests/bootloader/bootctl.py
new file mode 100644
index 0000000..7a69a8c
--- /dev/null
+++ b/tests/bootloader/bootctl.py
@@ -0,0 +1,61 @@
+# Copyright (C) 2016 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.
+
+class Bootctl(object):
+ def __init__(self, device):
+ self.device = device
+ self.base = ["bootctl"]
+
+ def _exec(self, cmd):
+ return self.device.shell_nocheck(self.base + [cmd])
+
+ def get_number_slots(self):
+ """returns number of slots"""
+
+ return int(self._exec("get-number-slots")[1])
+
+ def get_current_slot(self):
+ """returns current slot number"""
+
+ return int(self._exec("get-current-slot")[1])
+
+ def mark_boot_successful(self):
+ """returns true on success, false on failure"""
+
+ return self._exec("mark-boot-successful")[0] == 0
+
+ def set_active_boot_slot(self, slot):
+ """returns true on success, false on failure"""
+
+ return self._exec("set-active-boot-slot " + str(slot))[0] == 0
+
+ def set_slot_as_unbootable_slot(self, slot):
+ """returns true on success, false on failure"""
+
+ return self._exec("set-slot-as-unbootable " + str(slot))[0] == 0
+
+ def is_slot_bootable(self, slot):
+ """Returns true if slot is bootable"""
+
+ return self._exec("is-slot-bootable " + str(slot))[0] == 0
+
+ def is_slot_marked_successful(self, slot):
+ """returns true on success, false on failure"""
+
+ return self._exec("is-slot-marked-successful " + str(slot))[0] == 0
+
+ def get_suffix(self, slot):
+ """returns suffix string for specified slot number"""
+
+ return self._exec("get-suffix " + str(slot))[1].strip()
diff --git a/tests/bootloader/haltest.py b/tests/bootloader/haltest.py
new file mode 100644
index 0000000..41252c3
--- /dev/null
+++ b/tests/bootloader/haltest.py
@@ -0,0 +1,116 @@
+# Copyright (C) 2016 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.
+
+import bootctl
+import shelltest
+import sys
+import unittest
+
+# Note: In order to run these tests, the device must be able to boot
+# from all slots on the device.
+class HalTest(shelltest.ShellTest):
+ def __init__(self, *args, **kwargs):
+ super(HalTest, self).__init__(*args, **kwargs)
+ self.bootctl = bootctl.Bootctl(self.device)
+
+ def test_slots(self):
+ """Test that all slots are reported and named uniquely."""
+
+ self.device.root()
+ self.device.wait()
+ num_slots = self.bootctl.get_number_slots()
+ suffixes = dict()
+ for slot in range(num_slots):
+ suffix = self.bootctl.get_suffix(slot)
+ self.assertNotEqual(suffix, "(null)")
+ suffixes[suffix] = slot
+ self.assertEqual(len(suffixes), num_slots)
+
+ def test_mark_successful(self):
+ """Ensure mark successful works, and persists on reboot.
+
+ Ensure that mark_successful will mark the slot as
+ successful, and that the HAL sees this. First resets
+ slot-successful by setting the active slot to the current one."""
+
+ self.device.root()
+ self.device.wait()
+ slot = self.bootctl.get_current_slot()
+ self.assertTrue(self.bootctl.set_active_boot_slot(slot))
+ self.assertFalse(self.bootctl.is_slot_marked_successful(slot))
+ self.assertTrue(self.bootctl.mark_boot_successful())
+ self.assertTrue(self.bootctl.is_slot_marked_successful(slot))
+ self.device.reboot()
+ self.device.wait()
+ self.device.root()
+ self.device.wait()
+ self.assertTrue(self.bootctl.is_slot_marked_successful(slot))
+
+ def test_switch_slots(self):
+ """Test that setActiveBootSlot works and persists
+
+ Ensure switching slots works, and that setting the slot does not
+ change the reported slot until the reboot."""
+
+ # Cycle through all slots once
+ num_slots = self.bootctl.get_number_slots()
+ for i in range(num_slots):
+ self.device.root()
+ self.device.wait()
+ slot = self.bootctl.get_current_slot()
+ new_slot = (slot + 1) % num_slots
+ self.assertTrue(self.bootctl.set_active_boot_slot(new_slot))
+ slot2 = self.bootctl.get_current_slot()
+ self.assertEqual(slot, slot2)
+ self.device.reboot()
+ self.device.wait()
+ self.device.root()
+ self.device.wait()
+ self.assertEqual(new_slot, self.bootctl.get_current_slot())
+
+ def test_unbootable(self):
+ """Test setSlotAsUnbootable
+
+ Test that the device will attempt to roll back to a valid slot if
+ the current slot is unbootable."""
+
+ # Cycle through all slots once
+ num_slots = self.bootctl.get_number_slots()
+ for i in range(num_slots):
+ self.device.root()
+ self.device.wait()
+ slot = self.bootctl.get_current_slot()
+ new_slot = (slot + 1) % num_slots
+ self.device.root()
+ self.device.wait()
+ self.assertTrue(self.bootctl.set_active_boot_slot(new_slot))
+ self.assertTrue(self.bootctl.is_slot_bootable(new_slot))
+ self.assertTrue(self.bootctl.set_slot_as_unbootable_slot(new_slot))
+ self.assertFalse(self.bootctl.is_slot_bootable(new_slot))
+ self.device.reboot()
+ self.device.wait()
+ self.device.root()
+ self.device.wait()
+ self.assertEqual(slot, self.bootctl.get_current_slot())
+ self.assertFalse(self.bootctl.is_slot_bootable(new_slot))
+ self.assertTrue(self.bootctl.set_active_boot_slot(new_slot))
+ self.assertTrue(self.bootctl.is_slot_bootable(new_slot))
+ self.device.reboot()
+ self.device.wait()
+ self.device.root()
+ self.device.wait()
+ self.assertEqual(new_slot, self.bootctl.get_current_slot());
+
+if __name__ == '__main__':
+ unittest.main(verbosity=3)
diff --git a/tests/bootloader/shelltest.py b/tests/bootloader/shelltest.py
new file mode 100644
index 0000000..d9fbba1
--- /dev/null
+++ b/tests/bootloader/shelltest.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2016 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.
+
+import adb
+import os
+import unittest
+
+class ShellTest(unittest.TestCase):
+ def __init__(self, *args, **kwargs):
+ super(ShellTest, self).__init__(*args, **kwargs)
+ self.device = adb.get_device(os.getenv("BOOTLOADER_TEST_SERIAL"));
diff --git a/tests/cpueater/Android.mk b/tests/cpueater/Android.mk
new file mode 100644
index 0000000..0bb08d9
--- /dev/null
+++ b/tests/cpueater/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2008 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.
+# Copyright The Android Open Source Project
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := cpueater
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_SRC_FILES := cpueater.c
+LOCAL_CFLAGS := -Wno-unused-parameter
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := daemonize
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_SRC_FILES := daemonize.c
+LOCAL_SHARED_LIBRARIES := libhardware_legacy
+include $(BUILD_EXECUTABLE)
+
diff --git a/tests/cpueater/NOTICE b/tests/cpueater/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/tests/cpueater/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/tests/cpueater/cpueater.c b/tests/cpueater/cpueater.c
new file mode 100644
index 0000000..c791139
--- /dev/null
+++ b/tests/cpueater/cpueater.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2008 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.
+ *
+ * Simple cpu eater busy loop. Runs as a daemon. prints the child PID to
+ * std so you can easily kill it later.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+int main(int argc, char *argv[])
+{
+ pid_t pid;
+ int life_universe_and_everything;
+ int fd;
+
+ switch(fork()) {
+ case -1:
+ perror(argv[0]);
+ exit(1);
+ break;
+ case 0: /* child */
+ chdir("/");
+ umask(0);
+ setpgrp();
+ setsid();
+ /* fork again to fully detach from controlling terminal. */
+ switch(pid = fork()) {
+ case -1:
+ break;
+ case 0: /* second child */
+ /* redirect to /dev/null */
+ close(0);
+ open("/dev/null", 0);
+ close(1);
+ if(open("/dev/null", O_WRONLY) < 0) {
+ perror("/dev/null");
+ exit(1);
+ }
+ fflush(stdout);
+ close(2);
+ dup(1);
+ for (fd = 3; fd < 256; fd++) {
+ close(fd);
+ }
+ /* busy looper */
+ while (1) {
+ life_universe_and_everything = 42 * 2;
+ }
+ default:
+ /* so caller can easily kill it later. */
+ printf("%d\n", pid);
+ exit(0);
+ break;
+ }
+ break;
+ default:
+ exit(0);
+ break;
+ }
+ return 0;
+}
+
+
+/* vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab */
+
diff --git a/tests/cpueater/daemonize.c b/tests/cpueater/daemonize.c
new file mode 100644
index 0000000..e9b39b5
--- /dev/null
+++ b/tests/cpueater/daemonize.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2008 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.
+ *
+ */
+
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+
+#include "hardware_legacy/power.h"
+
+
+int main(int argc, char **argv)
+{
+ int pid, fd, mode;
+ unsigned int delay = 0;
+ int status = 0;
+ char *file = 0;
+ char lockid[32];
+
+ if (argc < 2) {
+ printf("Usage: %s [-f logfile] [-a] [-d delay] <program>\n", argv[0]);
+ exit(1);
+ }
+ close(0); open("/dev/null", 0);
+ close(1);
+
+ mode = O_TRUNC;
+
+ while(**++argv == '-') {
+ while(*++*argv) {
+ switch(**argv) {
+ case 'f':
+ if(*++*argv)
+ file = *argv;
+ else
+ file = *++argv;
+ goto next_arg;
+ case 'd':
+ if(*++*argv)
+ delay = atoi(*argv);
+ else
+ delay = atoi(*++argv);
+ goto next_arg;
+ case 'a':
+ mode = O_APPEND;
+ break;
+ }
+ }
+next_arg: ;
+ }
+
+ if (file) {
+ if(open(file, O_WRONLY|mode|O_CREAT, 0666) < 0) {
+ perror(file);
+ exit(1);
+ }
+ }
+ else {
+ if(open("/dev/null", O_WRONLY) < 0) {
+ perror("/dev/null");
+ exit(1);
+ }
+ }
+
+ switch(pid = fork()) {
+ case -1:
+ perror(argv[0]);
+ exit(1);
+ break;
+ case 0:
+ fflush(stdout);
+ close(2); dup(1); /* join stdout and stderr */
+ chdir("/");
+ umask(0);
+ setpgrp();
+ setsid();
+ for (fd = 3; fd < 256; fd++) {
+ close(fd);
+ }
+ if(delay) {
+ snprintf(lockid, 32, "daemonize%d", (int) getpid());
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, lockid);
+ }
+
+ switch(pid = fork()) {
+ case -1:
+ break;
+ case 0:
+ if(delay) {
+ sleep(delay);
+ }
+ execv(argv[0], argv);
+ execvp(argv[0], argv);
+ perror(argv[0]);
+ break;
+ default:
+ if(delay) {
+ waitpid(pid, &status, 0);
+ release_wake_lock(lockid);
+ }
+ _exit(0);
+ }
+ _exit(1);
+ break;
+ default:
+ exit(0);
+ break;
+ }
+}
+
+/* vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab */
diff --git a/tests/crypto/Android.mk b/tests/crypto/Android.mk
new file mode 100644
index 0000000..e118e5d
--- /dev/null
+++ b/tests/crypto/Android.mk
@@ -0,0 +1,11 @@
+# Copyright 2013 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= get_dm_versions.c
+LOCAL_MODULE:= get_dm_versions
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Wno-unused-parameter
+include $(BUILD_EXECUTABLE)
diff --git a/tests/crypto/get_dm_versions.c b/tests/crypto/get_dm_versions.c
new file mode 100644
index 0000000..8ffe0a1
--- /dev/null
+++ b/tests/crypto/get_dm_versions.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/dm-ioctl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define DM_CRYPT_BUF_SIZE 4096
+
+static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags)
+{
+ memset(io, 0, dataSize);
+ io->data_size = dataSize;
+ io->data_start = sizeof(struct dm_ioctl);
+ io->version[0] = 4;
+ io->version[1] = 0;
+ io->version[2] = 0;
+ io->flags = flags;
+ if (name) {
+ strncpy(io->name, name, sizeof(io->name));
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ char buffer[DM_CRYPT_BUF_SIZE];
+ struct dm_ioctl *io;
+ struct dm_target_versions *v;
+ int i;
+ int fd;
+
+ fd = open("/dev/device-mapper", O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot open /dev/device-mapper\n");
+ exit(1);
+ }
+
+ io = (struct dm_ioctl *) buffer;
+
+ ioctl_init(io, DM_CRYPT_BUF_SIZE, NULL, 0);
+
+ if (ioctl(fd, DM_LIST_VERSIONS, io)) {
+ fprintf(stderr, "ioctl(DM_LIST_VERSIONS) returned an error\n");
+ exit(1);
+ }
+
+ /* Iterate over the returned versions, and print each subsystem's version */
+ v = (struct dm_target_versions *) &buffer[sizeof(struct dm_ioctl)];
+ while (v->next) {
+ printf("%s: %d.%d.%d\n", v->name, v->version[0], v->version[1], v->version[2]);
+ v = (struct dm_target_versions *)(((char *)v) + v->next);
+ }
+
+ close(fd);
+ exit(0);
+}
+
diff --git a/tests/directiotest/Android.mk b/tests/directiotest/Android.mk
new file mode 100644
index 0000000..fb5f12a
--- /dev/null
+++ b/tests/directiotest/Android.mk
@@ -0,0 +1,8 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := directiotest
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_SRC_FILES := directiotest.c
+include $(BUILD_EXECUTABLE)
diff --git a/tests/directiotest/directiotest.c b/tests/directiotest/directiotest.c
new file mode 100644
index 0000000..6ed8bda
--- /dev/null
+++ b/tests/directiotest/directiotest.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2010 by Garmin Ltd. or its subsidiaries
+ *
+ * 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.
+ *
+ * Performs a simple write/readback test to verify correct functionality
+ * of direct i/o on a block device node.
+ */
+
+/* For large-file support */
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+/* For O_DIRECT */
+#define _GNU_SOURCE
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/fs.h>
+
+#define NUM_TEST_BLKS 128
+
+/*
+ * Allocate page-aligned memory. Could use posix_memalign(3), but some
+ * systems don't support it. Also pre-faults memory since we'll be using
+ * it all right away anyway.
+ */
+static void *pagealign_alloc(size_t size)
+{
+ void *ret = mmap(NULL, size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_LOCKED,
+ -1, 0);
+ if (ret == MAP_FAILED) {
+ perror("mmap");
+ ret = NULL;
+ }
+ return ret;
+}
+
+static void pagealign_free(void *addr, size_t size)
+{
+ int ret = munmap(addr, size);
+ if (ret == -1)
+ perror("munmap");
+}
+
+static ssize_t do_read(int fd, void *buf, off64_t start, size_t count)
+{
+ ssize_t ret;
+ size_t bytes_read = 0;
+
+ lseek64(fd, start, SEEK_SET);
+
+ do {
+ ret = read(fd, (char *)buf + bytes_read, count - bytes_read);
+ if (ret == -1) {
+ perror("read");
+ return -1;
+ } else if (ret == 0) {
+ fprintf(stderr, "Unexpected end-of-file\n");
+ return -1;
+ }
+ bytes_read += ret;
+ } while (bytes_read < count);
+
+ return bytes_read;
+}
+
+static ssize_t do_write(int fd, const void *buf, off64_t start, size_t count)
+{
+ ssize_t ret;
+ size_t bytes_out = 0;
+
+ lseek64(fd, start, SEEK_SET);
+
+ do {
+ ret = write(fd, (char *)buf + bytes_out, count - bytes_out);
+ if (ret == -1) {
+ perror("write");
+ return -1;
+ } else if (ret == 0) {
+ fprintf(stderr, "write returned 0\n");
+ return -1;
+ }
+ bytes_out += ret;
+ } while (bytes_out < count);
+
+ return bytes_out;
+}
+
+/*
+ * Initializes test buffer with locally-unique test pattern. High 16-bits of
+ * each 32-bit word contain first disk block number of the test area, low
+ * 16-bits contain word offset into test area. The goal is that a given test
+ * area should never contain the same data as a nearby test area, and that the
+ * data for a given test area be easily reproducable given the start block and
+ * test area size.
+ */
+static void init_test_buf(void *buf, uint64_t start_blk, size_t len)
+{
+ uint32_t *data = buf;
+ size_t i;
+
+ len /= sizeof(uint32_t);
+ for (i = 0; i < len; i++)
+ data[i] = (start_blk & 0xFFFF) << 16 | (i & 0xFFFF);
+}
+
+static void dump_hex(const void *buf, int len)
+{
+ const uint8_t *data = buf;
+ int i;
+ char ascii_buf[17];
+
+ ascii_buf[16] = '\0';
+
+ for (i = 0; i < len; i++) {
+ int val = data[i];
+ int off = i % 16;
+
+ if (off == 0)
+ printf("%08x ", i);
+ printf("%02x ", val);
+ ascii_buf[off] = isprint(val) ? val : '.';
+ if (off == 15)
+ printf(" %-16s\n", ascii_buf);
+ }
+
+ i %= 16;
+ if (i) {
+ ascii_buf[i] = '\0';
+ while (i++ < 16)
+ printf(" ");
+ printf(" %-16s\n", ascii_buf);
+ }
+}
+
+static void update_progress(int current, int total)
+{
+ double pct_done = (double)current * 100 / total;
+ printf("Testing area %d/%d (%6.2f%% complete)\r", current, total,
+ pct_done);
+ fflush(stdout);
+}
+
+int main(int argc, const char *argv[])
+{
+ int ret = 1;
+ const char *path;
+ int fd;
+ struct stat stat;
+ void *read_buf = NULL, *write_buf = NULL;
+ int blk_size;
+ uint64_t num_blks;
+ size_t test_size;
+ int test_areas, i;
+
+ if (argc != 2) {
+ printf("Usage: directiotest blkdev_path\n");
+ exit(1);
+ }
+
+ path = argv[1];
+ fd = open(path, O_RDWR | O_DIRECT | O_LARGEFILE);
+ if (fd == -1) {
+ perror("open");
+ exit(1);
+ }
+ if (fstat(fd, &stat) == -1) {
+ perror("stat");
+ goto cleanup;
+ } else if (!S_ISBLK(stat.st_mode)) {
+ fprintf(stderr, "%s is not a block device\n", path);
+ goto cleanup;
+ }
+
+ if (ioctl(fd, BLKSSZGET, &blk_size) == -1) {
+ perror("ioctl");
+ goto cleanup;
+ }
+ if (ioctl(fd, BLKGETSIZE64, &num_blks) == -1) {
+ perror("ioctl");
+ goto cleanup;
+ }
+ num_blks /= blk_size;
+
+ test_size = (size_t)blk_size * NUM_TEST_BLKS;
+ read_buf = pagealign_alloc(test_size);
+ write_buf = pagealign_alloc(test_size);
+ if (!read_buf || !write_buf) {
+ fprintf(stderr, "Error allocating test buffers\n");
+ goto cleanup;
+ }
+
+ /*
+ * Start the actual test. Go through the entire device, writing
+ * locally-unique patern to each test block and then reading it
+ * back.
+ */
+ if (num_blks / NUM_TEST_BLKS > INT_MAX) {
+ printf("Warning: Device too large for test variables\n");
+ printf("Entire device will not be tested\n");
+ test_areas = INT_MAX;
+ } else {
+ test_areas = num_blks / NUM_TEST_BLKS;
+ }
+
+ printf("Starting test\n");
+
+ for (i = 0; i < test_areas; i++) {
+ uint64_t cur_blk = (uint64_t)i * NUM_TEST_BLKS;
+
+ update_progress(i + 1, test_areas);
+
+ init_test_buf(write_buf, cur_blk, test_size);
+
+ if (do_write(fd, write_buf, cur_blk * blk_size, test_size) !=
+ (ssize_t)test_size) {
+ fprintf(stderr, "write failed, aborting test\n");
+ goto cleanup;
+ }
+ if (do_read(fd, read_buf, cur_blk * blk_size, test_size) !=
+ (ssize_t)test_size) {
+ fprintf(stderr, "read failed, aborting test\n");
+ goto cleanup;
+ }
+
+ if (memcmp(write_buf, read_buf, test_size)) {
+ printf("Readback verification failed at block %" PRIu64 "\n\n",
+ cur_blk);
+ printf("Written data:\n");
+ dump_hex(write_buf, test_size);
+ printf("\nRead data:\n");
+ dump_hex(read_buf, test_size);
+ goto cleanup;
+ }
+ }
+
+ printf("\nTest complete\n");
+ ret = 0;
+
+cleanup:
+ if (read_buf)
+ pagealign_free(read_buf, test_size);
+ if (write_buf)
+ pagealign_free(write_buf, test_size);
+ close(fd);
+ return ret;
+}
diff --git a/tests/ext4/Android.mk b/tests/ext4/Android.mk
new file mode 100644
index 0000000..bdd4072
--- /dev/null
+++ b/tests/ext4/Android.mk
@@ -0,0 +1,18 @@
+# Copyright 2012 The Android Open Source Project
+
+local_target_dir := $(TARGET_OUT_DATA)/local/tmp
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= rand_emmc_perf.c
+LOCAL_MODULE:= rand_emmc_perf
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32:= rand_emmc_perf
+LOCAL_MODULE_STEM_64:= rand_emmc_perf64
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(local_target_dir)
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_STATIC_LIBRARIES := libm libc
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/tests/ext4/android_emmc_perf_tests.sh b/tests/ext4/android_emmc_perf_tests.sh
new file mode 100755
index 0000000..6464312
--- /dev/null
+++ b/tests/ext4/android_emmc_perf_tests.sh
@@ -0,0 +1,284 @@
+#!/bin/bash
+
+PERF="rand_emmc_perf"
+PERF_LOC=/dev
+STATS_FILE="/data/local/tmp/stats_test"
+STATS_MODE=0
+USERBUILD_MODE=0
+
+if [ "$1" = "-s" ]
+then
+ STATS_MODE=1
+elif [ "$1" = "-u" ]
+then
+ USERBUILD_MODE=1
+fi
+
+if [ ! -r "$PERF" ]
+then
+ echo "Cannot read $PERF test binary"
+fi
+
+if ! adb shell true >/dev/null 2>&1
+then
+ echo "No device detected over adb"
+fi
+
+HARDWARE=`adb shell getprop ro.hardware | tr -d "\r"`
+
+case "$HARDWARE" in
+ tuna | steelhead)
+ CPUFREQ="/sys/devices/system/cpu/cpu0/cpufreq"
+ CACHE="/dev/block/platform/omap/omap_hsmmc.0/by-name/cache"
+ MMCDEV="mmcblk0"
+ ;;
+
+ stingray | wingray)
+ CPUFREQ="/sys/devices/system/cpu/cpu0/cpufreq"
+ CACHE="/dev/block/platform/sdhci-tegra.3/by-name/cache"
+ MMCDEV="mmcblk0"
+ ;;
+
+ herring)
+ echo "This test will wipe the userdata partition on $HARDWARE devices."
+ read -p "Do you want to proceed? " ANSWER
+
+ if [ "$ANSWER" != "yes" ]
+ then
+ echo "aborting test"
+ exit 1
+ fi
+
+ CPUFREQ="/sys/devices/system/cpu/cpu0/cpufreq"
+ CACHE="/dev/block/platform/s3c-sdhci.0/by-name/userdata"
+ MMCDEV="mmcblk0"
+ ;;
+
+ grouper)
+ CPUFREQ="/sys/devices/system/cpu/cpu0/cpufreq"
+ CACHE="/dev/block/platform/sdhci-tegra.3/by-name/CAC"
+ MMCDEV="mmcblk0"
+ ;;
+
+ manta)
+ CPUFREQ="/sys/devices/system/cpu/cpu0/cpufreq"
+ CACHE="/dev/block/platform/dw_mmc.0/by-name/cache"
+ MMCDEV="mmcblk0"
+ ;;
+
+ flo)
+ CPUFREQ="/sys/devices/system/cpu/cpu0/cpufreq"
+ CACHE="dev/block/platform/msm_sdcc.1/by-name/cache"
+ MMCDEV="mmcblk0"
+ ;;
+
+ *)
+ echo "Unknown hardware $HARDWARE. Exiting."
+ exit 1
+esac
+
+# We cannot stop and unmount stuff in a user build, so don't even try.
+if [ "$USERBUILD_MODE" -eq 0 ]
+then
+ # prepare the device
+ adb root
+ adb wait-for-device
+ adb push "$PERF" /dev
+ adb shell stop
+ adb shell stop sdcard
+ adb shell stop ril-daemon
+ adb shell stop media
+ adb shell stop drm
+ adb shell stop keystore
+ adb shell stop tf_daemon
+ adb shell stop bluetoothd
+ adb shell stop hciattach
+ adb shell stop p2p_supplicant
+ adb shell stop wpa_supplicant
+ adb shell stop mobicore
+ adb shell umount /sdcard >/dev/null 2>&1
+ adb shell umount /mnt/sdcard >/dev/null 2>&1
+ adb shell umount /mnt/shell/sdcard0 >/dev/null 2>&1
+ adb shell umount /mnt/shell/emulated >/dev/null 2>&1
+ adb shell umount /cache >/dev/null 2>&1
+ if [ "$STATS_MODE" -ne 1 ]
+ then
+ adb shell umount /data >/dev/null 2>&1
+ fi
+else
+ # For user builds, put the $PERF binary in /data/local/tmp,
+ # and also setup CACHE to point to a file on /data/local/tmp,
+ # and create that file
+ PERF_LOC=/data/local/tmp
+ adb push "$PERF" "$PERF_LOC"
+ CACHE=/data/local/tmp/testfile
+ echo "Creating testfile for user builds (can take up to 60 seconds)"
+ adb shell dd if=/dev/zero of=$CACHE bs=1048576 count=512
+fi
+
+# Add more services here that other devices need to stop.
+# So far, this list is sufficient for:
+# Prime
+
+if [ "$USERBUILD_MODE" -eq 0 ]
+then
+ # At this point, the device is quiescent, need to crank up the cpu speed,
+ # then run tests
+ adb shell "cat $CPUFREQ/cpuinfo_max_freq > $CPUFREQ/scaling_max_freq"
+ adb shell "cat $CPUFREQ/cpuinfo_max_freq > $CPUFREQ/scaling_min_freq"
+fi
+
+# Start the tests
+
+if [ "$STATS_MODE" -eq 1 ]
+then
+ # This test looks for the average and max random write times for the emmc
+ # chip. It should be run with the emmc chip full for worst case numbers,
+ # and after fstrim for best case numbers. So first fill the chip, twice,
+ # then run the test, then remove the large file, run fstrim, and run the
+ # test again.
+
+ # Remove the test file if it exists, then make it anew.
+ echo "Filling userdata"
+ adb shell rm -f "$STATS_FILE"
+ adb shell dd if=/dev/zero of="$STATS_FILE" bs=1048576
+ adb shell sync
+
+ # Do it again to make sure to fill up all the reserved blocks used for
+ # wear levelling, plus any unused blocks in the other partitions. Yes,
+ # this is not precise, just a good heuristic.
+ echo "Filling userdata again"
+ adb shell rm "$STATS_FILE"
+ adb shell sync
+ adb shell dd if=/dev/zero of="$STATS_FILE" bs=1048576
+ adb shell sync
+
+ # Run the test
+ echo "Running stats test after filling emmc chip"
+ adb shell /dev/$PERF -w -o -s 20000 -f /dev/full_stats 400 "$CACHE"
+
+ # Remove the file, and have vold do fstrim
+ adb shell rm "$STATS_FILE"
+ adb shell sync
+ # Make sure fstrim knows there is work to do
+ sleep 10
+
+ # Get the current number of FSTRIM complete lines in thh logcat
+ ORIGCNT=`adb shell logcat -d | grep -c "Finished fstrim work"`
+
+ # Attempt to start fstrim
+ OUT=`adb shell vdc fstrim dotrim | grep "Command not recognized"`
+
+ if [ -z "$OUT" ]
+ then
+ # Wait till we see another fstrim finished line
+ sleep 10
+ let T=10
+ NEWCNT=`adb shell logcat -d |grep -c "Finished fstrim work"`
+ while [ "$NEWCNT" -eq "$ORIGCNT" ]
+ do
+ sleep 10
+ let T=T+10
+ if [ "$T" -ge 300 ]
+ then
+ echo "Error: FSTRIM did not complete in 300 seconds, continuing"
+ break
+ fi
+ NEWCNT=`adb shell logcat -d |grep -c "Finished fstrim work"`
+ done
+
+ echo "FSTRIM took "$T" seconds"
+
+ # Run the test again
+ echo "Running test after fstrim"
+ adb shell /dev/$PERF -w -o -s 20000 -f /dev/fstrimmed_stats 400 "$CACHE"
+
+ # Retrieve the full data logs
+ adb pull /dev/fstrimmed_stats $HARDWARE-fstrimmed_stats
+ adb pull /dev/full_stats $HARDWARE-full_stats
+ else
+ echo "Device doesn't support fstrim, not running test a second time"
+ fi
+
+else
+
+ # Sequential read test
+ if [ "$USERBUILD_MODE" -eq 0 ]
+ then
+ # There is no point in running this in USERBUILD mode, because
+ # we can't drop caches, and the numbers are ludicrously high
+ for I in 1 2 3
+ do
+ adb shell "echo 3 > /proc/sys/vm/drop_caches"
+ echo "Sequential read test $I"
+ adb shell dd if="$CACHE" of=/dev/null bs=1048576 count=200
+ done
+ fi
+
+ # Sequential write test
+ for I in 1 2 3
+ do
+ echo "Sequential write test $I"
+ # It's unclear if this test is useful on USERBUILDS, given the
+ # caching on the filesystem
+ adb shell dd if=/dev/zero conv=notrunc of="$CACHE" bs=1048576 count=200
+ done
+
+ if [ "$USERBUILD_MODE" -eq 0 ]
+ then
+ # Random read tests require that we read from a much larger range of offsets
+ # into the emmc chip than the write test. If we only read though 100 Megabytes
+ # (and with a read-ahead of 128K), we quickly fill the buffer cache with 100
+ # Megabytes of data, and subsequent reads are nearly instantaneous. Since
+ # reading is non-destructive, and we've never shipped a device with less than
+ # 8 Gbytes, for this test we read from the raw emmc device, and randomly seek
+ # in the first 6 Gbytes. That is way more memory than any device we currently
+ # have and it should keep the cache from being poluted with entries from
+ # previous random reads.
+ #
+ # Also, test with the read-ahead set very low at 4K, and at the default
+
+ # Random read test, 4K read-ahead
+ ORIG_READAHEAD=`adb shell cat /sys/block/$MMCDEV/queue/read_ahead_kb | tr -d "\r"`
+ adb shell "echo 4 > /sys/block/$MMCDEV/queue/read_ahead_kb"
+ for I in 1 2 3
+ do
+ adb shell "echo 3 > /proc/sys/vm/drop_caches"
+ echo "Random read (4K read-ahead) test $I"
+ adb shell "$PERF_LOC"/"$PERF" -r 6000 "/dev/block/$MMCDEV"
+ done
+
+ # Random read test, default read-ahead
+ adb shell "echo $ORIG_READAHEAD > /sys/block/$MMCDEV/queue/read_ahead_kb"
+ for I in 1 2 3
+ do
+ adb shell "echo 3 > /proc/sys/vm/drop_caches"
+ echo "Random read (default read-ahead of ${ORIG_READAHEAD}K) test $I"
+ adb shell "$PERF_LOC"/"$PERF" -r 6000 "/dev/block/$MMCDEV"
+ done
+ fi
+
+ # Random write test
+ for I in 1 2 3
+ do
+ echo "Random write test $I"
+ adb shell "$PERF_LOC"/"$PERF" -w 100 "$CACHE"
+ done
+
+ # Random write test with O_SYNC
+ for I in 1 2 3
+ do
+ echo "Random write with o_sync test $I"
+ adb shell "$PERF_LOC"/"$PERF" -w -o 100 "$CACHE"
+ done
+fi
+
+# cleanup
+if [ "$USERBUILD_MODE" -eq 0 ]
+then
+ # Make a new empty /cache filesystem
+ adb shell make_ext4fs -w "$CACHE"
+else
+ adb shell rm -f "$CACHE" "$PERF_LOC"/"$PERF"
+fi
+
diff --git a/tests/ext4/rand_emmc_perf.c b/tests/ext4/rand_emmc_perf.c
new file mode 100644
index 0000000..fed7a54
--- /dev/null
+++ b/tests/ext4/rand_emmc_perf.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+/* A simple test of emmc random read and write performance. When testing write
+ * performance, try it twice, once with O_SYNC compiled in, and once with it commented
+ * out. Without O_SYNC, the close(2) blocks until all the dirty buffers are written
+ * out, but the numbers tend to be higher.
+ */
+
+#define _LARGEFILE64_SOURCE
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+
+#define TST_BLK_SIZE 4096
+/* Number of seconds to run the test */
+#define TEST_LEN 10
+
+struct stats {
+ struct timeval start;
+ struct timeval end;
+ off64_t offset;
+};
+
+static void usage(void) {
+ fprintf(stderr, "Usage: rand_emmc_perf [ -r | -w ] [-o] [-s count] [-f full_stats_filename] <size_in_mb> <block_dev>\n");
+ exit(1);
+}
+
+static void print_stats(struct stats *stats_buf, int stats_count,
+ char * full_stats_file)
+{
+ int i;
+ struct timeval t;
+ struct timeval sum = { 0, 0 };
+ struct timeval max = { 0, 0 };
+ long long total_usecs;
+ long long avg_usecs;
+ long long max_usecs;
+ long long variance = 0;;
+ long long x;
+ double sdev;
+ FILE *full_stats = NULL;
+
+ if (full_stats_file) {
+ full_stats = fopen(full_stats_file, "w");
+ if (full_stats == NULL) {
+ fprintf(stderr, "Cannot open full stats output file %s, ignoring\n",
+ full_stats_file);
+ }
+ }
+
+ for (i = 0; i < stats_count; i++) {
+ timersub(&stats_buf[i].end, &stats_buf[i].start, &t);
+ if (timercmp(&t, &max, >)) {
+ max = t;
+ }
+ if (full_stats) {
+ fprintf(full_stats, "%lld\n", (t.tv_sec * 1000000LL) + t.tv_usec);
+ }
+ timeradd(&sum, &t, &sum);
+ }
+
+ if (full_stats) {
+ fclose(full_stats);
+ }
+
+ max_usecs = (max.tv_sec * 1000000LL) + max.tv_usec;
+ total_usecs = (sum.tv_sec * 1000000LL) + sum.tv_usec;
+ avg_usecs = total_usecs / stats_count;
+ printf("average random %d byte iop time = %lld usecs\n",
+ TST_BLK_SIZE, avg_usecs);
+ printf("maximum random %d byte iop time = %lld usecs\n",
+ TST_BLK_SIZE, max_usecs);
+
+ /* Now that we have the average (aka mean) go through the data
+ * again and compute the standard deviation.
+ * The formula is sqrt(sum_1_to_n((Xi - avg)^2)/n)
+ */
+ for (i = 0; i < stats_count; i++) {
+ timersub(&stats_buf[i].end, &stats_buf[i].start, &t); /* Xi */
+ x = (t.tv_sec * 1000000LL) + t.tv_usec; /* Convert to long long */
+ x = x - avg_usecs; /* Xi - avg */
+ x = x * x; /* (Xi - avg) ^ 2 */
+ variance += x; /* Summation */
+ }
+ sdev = sqrt((double)variance/(double)stats_count);
+ printf("standard deviation of iops is %.2f\n", sdev);
+}
+
+static void stats_test(int fd, int write_mode, off64_t max_blocks, int stats_count,
+ char *full_stats_file)
+{
+ struct stats *stats_buf;
+ char buf[TST_BLK_SIZE] = { 0 };
+ int i;
+
+ stats_buf = malloc(stats_count * sizeof(struct stats));
+ if (stats_buf == NULL) {
+ fprintf(stderr, "Cannot allocate stats_buf\n");
+ exit(1);
+ }
+
+ for (i = 0; i < stats_count; i++) {
+ gettimeofday(&stats_buf[i].start, NULL);
+
+ if (lseek64(fd, (rand() % max_blocks) * TST_BLK_SIZE, SEEK_SET) < 0) {
+ fprintf(stderr, "lseek64 failed\n");
+ }
+
+ if (write_mode) {
+ if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
+ fprintf(stderr, "Short write\n");
+ }
+ } else {
+ if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
+ fprintf(stderr, "Short read\n");
+ }
+ }
+
+ gettimeofday(&stats_buf[i].end, NULL);
+ }
+
+ print_stats(stats_buf, stats_count, full_stats_file);
+}
+
+static void perf_test(int fd, int write_mode, off64_t max_blocks)
+{
+ struct timeval start, end, res;
+ char buf[TST_BLK_SIZE] = { 0 };
+ long long iops = 0;
+ int msecs;
+
+ res.tv_sec = 0;
+ gettimeofday(&start, NULL);
+ while (res.tv_sec < TEST_LEN) {
+ if (lseek64(fd, (rand() % max_blocks) * TST_BLK_SIZE, SEEK_SET) < 0) {
+ fprintf(stderr, "lseek64 failed\n");
+ }
+ if (write_mode) {
+ if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
+ fprintf(stderr, "Short write\n");
+ }
+ } else {
+ if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
+ fprintf(stderr, "Short read\n");
+ }
+ }
+ iops++;
+ gettimeofday(&end, NULL);
+ timersub(&end, &start, &res);
+ }
+ close(fd);
+
+ /* The close can take a while when in write_mode as buffers are flushed.
+ * So get the time again. */
+ gettimeofday(&end, NULL);
+ timersub(&end, &start, &res);
+
+ msecs = (res.tv_sec * 1000) + (res.tv_usec / 1000);
+ printf("%.0f %dbyte iops/sec\n", (float)iops * 1000 / msecs, TST_BLK_SIZE);
+}
+
+int main(int argc, char *argv[])
+{
+ int fd, fd2;
+ int write_mode = 0;
+ int o_sync = 0;
+ int stats_mode = 0;
+ int stats_count;
+ char *full_stats_file = NULL;
+ off64_t max_blocks;
+ unsigned int seed;
+ int c;
+
+ while ((c = getopt(argc, argv, "+rwos:f:")) != -1) {
+ switch (c) {
+ case '?':
+ default:
+ usage();
+ break;
+
+ case 'r':
+ /* Do nothing, read mode is the default */
+ break;
+
+ case 'w':
+ write_mode = 1;
+ break;
+
+ case 'o':
+ o_sync = O_SYNC;
+ break;
+
+ case 's':
+ stats_mode = 1;
+ stats_count = atoi(optarg);
+ break;
+
+ case 'f':
+ free(full_stats_file);
+ full_stats_file = strdup(optarg);
+ if (full_stats_file == NULL) {
+ fprintf(stderr, "Cannot get full stats filename\n");
+ }
+ break;
+ }
+ }
+
+ if (o_sync && !write_mode) {
+ /* Can only specify o_sync in write mode. Probably doesn't matter,
+ * but clear o_sync if in read mode */
+ o_sync = 0;
+ }
+
+ if ((argc - optind) != 2) {
+ usage();
+ }
+
+ /* Size is given in megabytes, so compute the number of TST_BLK_SIZE blocks. */
+ max_blocks = atoll(argv[optind]) * ((1024*1024) / TST_BLK_SIZE);
+
+ if ((fd = open(argv[optind + 1], O_RDWR | o_sync)) < 0) {
+ fprintf(stderr, "Cannot open block device %s\n", argv[optind + 1]);
+ exit(1);
+ }
+
+ fd2 = open("/dev/urandom", O_RDONLY);
+ if (fd2 < 0) {
+ fprintf(stderr, "Cannot open /dev/urandom\n");
+ }
+ if (read(fd2, &seed, sizeof(seed)) != sizeof(seed)) {
+ fprintf(stderr, "Cannot read /dev/urandom\n");
+ }
+ close(fd2);
+ srand(seed);
+
+ if (stats_mode) {
+ stats_test(fd, write_mode, max_blocks, stats_count, full_stats_file);
+ } else {
+ perf_test(fd, write_mode, max_blocks);
+ }
+ free(full_stats_file);
+
+ exit(0);
+}
+
diff --git a/tests/framebuffer/Android.mk b/tests/framebuffer/Android.mk
new file mode 100644
index 0000000..7f4c712
--- /dev/null
+++ b/tests/framebuffer/Android.mk
@@ -0,0 +1,24 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ refresh.c
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils
+
+LOCAL_MODULE:= test-fb-refresh
+
+LOCAL_CFLAGS := -Wno-unused-parameter
+
+include $(BUILD_EXECUTABLE)
+
+##
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := fb_test.c
+LOCAL_MODULE = test-fb-simple
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_STATIC_LIBRARIES := libc
+LOCAL_CFLAGS := -Wno-unused-parameter
+include $(BUILD_EXECUTABLE)
diff --git a/tests/framebuffer/fb_test.c b/tests/framebuffer/fb_test.c
new file mode 100644
index 0000000..0b8bc68
--- /dev/null
+++ b/tests/framebuffer/fb_test.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <linux/fb.h>
+#include <linux/kd.h>
+
+struct simple_fb {
+ void *data;
+ int width;
+ int height;
+ int stride;
+ int bpp;
+};
+
+static struct simple_fb gr_fbs[2];
+static unsigned gr_active_fb = 0;
+
+static int gr_fb_fd = -1;
+static int gr_vt_fd = -1;
+
+static struct fb_var_screeninfo vi;
+struct fb_fix_screeninfo fi;
+struct timespec tv, tv2;
+
+static void dumpinfo(struct fb_fix_screeninfo *fi,
+ struct fb_var_screeninfo *vi);
+
+static int get_framebuffer(struct simple_fb *fb, unsigned bpp)
+{
+ int fd;
+ void *bits;
+ int bytes_per_pixel;
+
+ fd = open("/dev/graphics/fb0", O_RDWR);
+ 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_VSCREENINFO, &vi) < 0) {
+ perror("failed to get fb0 info");
+ return -1;
+ }
+
+ if (bpp && vi.bits_per_pixel != bpp) {
+ printf("bpp != %d, forcing...\n", bpp);
+ vi.bits_per_pixel = bpp;
+ if(ioctl(fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
+ perror("failed to force bpp");
+ return -1;
+ }
+ }
+
+ if(ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
+ perror("failed to get fb0 info");
+ return -1;
+ }
+
+ dumpinfo(&fi, &vi);
+
+ bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if(bits == MAP_FAILED) {
+ perror("failed to mmap framebuffer");
+ return -1;
+ }
+
+ bytes_per_pixel = vi.bits_per_pixel >> 3;
+
+ fb->width = vi.xres;
+ fb->height = vi.yres;
+ fb->stride = fi.line_length / bytes_per_pixel;
+ fb->data = bits;
+ fb->bpp = vi.bits_per_pixel;
+
+ fb++;
+
+ fb->width = vi.xres;
+ fb->height = vi.yres;
+ fb->stride = fi.line_length / bytes_per_pixel;
+ fb->data = (void *)((unsigned long)bits +
+ vi.yres * vi.xres * bytes_per_pixel);
+ fb->bpp = vi.bits_per_pixel;
+
+ return fd;
+}
+
+static void set_active_framebuffer(unsigned n)
+{
+ if(n > 1) return;
+ vi.yres_virtual = vi.yres * 2;
+ vi.yoffset = n * vi.yres;
+ if(ioctl(gr_fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
+ fprintf(stderr,"active fb swap failed!\n");
+ } else
+ printf("active buffer: %d\n", n);
+}
+
+static void dumpinfo(struct fb_fix_screeninfo *fi, struct fb_var_screeninfo *vi)
+{
+ fprintf(stderr,"vi.xres = %d\n", vi->xres);
+ fprintf(stderr,"vi.yres = %d\n", vi->yres);
+ fprintf(stderr,"vi.xresv = %d\n", vi->xres_virtual);
+ fprintf(stderr,"vi.yresv = %d\n", vi->yres_virtual);
+ fprintf(stderr,"vi.xoff = %d\n", vi->xoffset);
+ fprintf(stderr,"vi.yoff = %d\n", vi->yoffset);
+ fprintf(stderr, "vi.bits_per_pixel = %d\n", vi->bits_per_pixel);
+
+ fprintf(stderr, "fi.line_length = %d\n", fi->line_length);
+
+}
+
+int gr_init(int bpp, int id)
+{
+ int fd = -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;
+ }
+ }
+
+ gr_fb_fd = get_framebuffer(gr_fbs, bpp);
+
+ if(gr_fb_fd < 0) {
+ if (fd >= 0) {
+ ioctl(fd, KDSETMODE, (void*) KD_TEXT);
+ close(fd);
+ }
+ return -1;
+ }
+
+ gr_vt_fd = fd;
+
+ /* start with 0 as front (displayed) and 1 as back (drawing) */
+ gr_active_fb = id;
+ set_active_framebuffer(id);
+
+ return 0;
+}
+
+void gr_exit(void)
+{
+ close(gr_fb_fd);
+ gr_fb_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)
+{
+ return gr_fbs[0].width;
+}
+
+int gr_fb_height(void)
+{
+ return gr_fbs[0].height;
+}
+
+uint16_t red = 0xf800;
+uint16_t green = 0x07e0;
+uint16_t blue = 0x001f;
+uint16_t white = 0xffff;
+uint16_t black = 0x0;
+
+uint32_t red32 = 0x00ff0000;
+uint32_t green32 = 0x0000ff00;
+uint32_t blue32 = 0x000000ff;
+uint32_t white32 = 0x00ffffff;
+uint32_t black32 = 0x0;
+
+void draw_grid(int w, int h, void* _loc) {
+ int i, j;
+ int v;
+ int stride = fi.line_length / (vi.bits_per_pixel >> 3);
+ uint16_t *loc = _loc;
+ uint32_t *loc32 = _loc;
+
+ for (j = 0; j < h/2; j++) {
+ for (i = 0; i < w/2; i++)
+ if (vi.bits_per_pixel == 16)
+ loc[i + j*(stride)] = red;
+ else
+ loc32[i + j*(stride)] = red32;
+ for (; i < w; i++)
+ if (vi.bits_per_pixel == 16)
+ loc[i + j*(stride)] = green;
+ else
+ loc32[i + j*(stride)] = green32;
+ }
+
+ for (; j < h; j++) {
+ for (i = 0; i < w/2; i++)
+ if (vi.bits_per_pixel == 16)
+ loc[i + j*(stride)] = blue;
+ else
+ loc32[i + j*(stride)] = blue32;
+ for (; i < w; i++)
+ if (vi.bits_per_pixel == 16)
+ loc[i + j*(stride)] = white;
+ else
+ loc32[i + j*(stride)] = white32;
+ }
+
+}
+
+void clear_screen(int w, int h, void* _loc)
+{
+ int i,j;
+ int stride = fi.line_length / (vi.bits_per_pixel >> 3);
+ uint16_t *loc = _loc;
+ uint32_t *loc32 = _loc;
+
+ for (j = 0; j < h; j++)
+ for (i = 0; i < w; i++)
+ if (vi.bits_per_pixel == 16)
+ loc[i + j*(stride)] = black;
+ else
+ loc32[i + j*(stride)] = black32;
+}
+
+int main(int argc, char **argv) {
+ int w;
+ int h;
+ int id = 0;
+ int bpp = 0;
+
+ if (argc > 1)
+ bpp = atoi(argv[1]);
+
+ if (argc > 4)
+ id = !!atoi(argv[4]);
+
+ gr_init(bpp, id);
+
+ if (argc > 3) {
+ w = atoi(argv[2]);
+ h = atoi(argv[3]);
+ } else {
+ w = vi.xres;
+ h = vi.yres;
+ }
+
+ clear_screen(vi.xres, vi.yres, gr_fbs[0].data);
+ clear_screen(vi.xres, vi.yres, gr_fbs[1].data);
+
+ draw_grid(w, h, gr_fbs[id].data);
+
+ set_active_framebuffer(!id);
+ set_active_framebuffer(id);
+
+ return 0;
+}
diff --git a/tests/framebuffer/minui.h b/tests/framebuffer/minui.h
new file mode 100644
index 0000000..4efc971
--- /dev/null
+++ b/tests/framebuffer/minui.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef _MINUI_H_
+#define _MINUI_H_
+
+int gr_init(void);
+void gr_exit(void);
+
+int gr_fb_width(void);
+int gr_fb_height(void);
+void gr_flip(void);
+
+void gr_color(unsigned char r, unsigned char g, unsigned char b);
+void gr_fill(int x, int y, int w, int h);
+int gr_text(int x, int y, const char *s);
+int gr_measure(const char *s);
+
+
+typedef struct event event;
+
+struct event
+{
+ unsigned type;
+ unsigned code;
+ unsigned value;
+};
+
+int ev_init(void);
+void ev_exit(void);
+
+int ev_get(event *ev, unsigned dont_wait);
+
+#define TYPE_KEY 1
+
+#define KEY_UP 103
+#define KEY_DOWN 108
+#define KEY_LEFT 105
+#define KEY_RIGHT 106
+#define KEY_CENTER 232
+#define KEY_ENTER 28
+
+#endif
diff --git a/tests/framebuffer/refresh.c b/tests/framebuffer/refresh.c
new file mode 100644
index 0000000..38e7871
--- /dev/null
+++ b/tests/framebuffer/refresh.c
@@ -0,0 +1,167 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+#include <time.h>
+#include <errno.h>
+
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+
+#include <linux/fb.h>
+
+int64_t systemTime()
+{
+ struct timespec t;
+ t.tv_sec = t.tv_nsec = 0;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return (int64_t)(t.tv_sec)*1000000000LL + t.tv_nsec;
+}
+
+int main(int argc, char** argv)
+{
+ char const * const device_template[] = {
+ "/dev/graphics/fb%u",
+ "/dev/fb%u",
+ 0 };
+ int fd = -1;
+ int i=0;
+ int j=0;
+ char name[64];
+ while ((fd==-1) && device_template[i]) {
+ snprintf(name, 64, device_template[i], 0);
+ fd = open(name, O_RDWR, 0);
+ i++;
+ }
+ if (fd < 0)
+ return -errno;
+
+ struct fb_fix_screeninfo finfo;
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
+ return -errno;
+
+ struct fb_var_screeninfo info;
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
+ return -errno;
+
+ info.reserved[0] = 0;
+ info.reserved[1] = 0;
+ info.reserved[2] = 0;
+ info.xoffset = 0;
+ info.yoffset = 0;
+ info.bits_per_pixel = 16;
+ info.activate = FB_ACTIVATE_NOW;
+
+ if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
+ printf("FBIOPUT_VSCREENINFO failed (%d x %d)\n",
+ info.xres_virtual, info.yres_virtual);
+ return 0;
+ }
+
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
+ return -errno;
+
+ uint64_t denominator = (uint64_t)( info.upper_margin + info.lower_margin + info.yres )
+ * ( info.left_margin + info.right_margin + info.xres )
+ * info.pixclock;
+ int refreshRate = denominator ? (1000000000000000LLU / denominator) : 0;
+
+ float xdpi = (info.xres * 25.4f) / info.width;
+ float ydpi = (info.yres * 25.4f) / info.height;
+ float fps = refreshRate / 1000.0f;
+
+ printf( "using (fd=%d)\n"
+ "id = %s\n"
+ "xres = %d px\n"
+ "yres = %d px\n"
+ "xres_virtual = %d px\n"
+ "yres_virtual = %d px\n"
+ "bpp = %d\n"
+ "r = %2u:%u\n"
+ "g = %2u:%u\n"
+ "b = %2u:%u\n",
+ fd,
+ finfo.id,
+ info.xres,
+ info.yres,
+ info.xres_virtual,
+ info.yres_virtual,
+ info.bits_per_pixel,
+ info.red.offset, info.red.length,
+ info.green.offset, info.green.length,
+ info.blue.offset, info.blue.length
+ );
+
+ printf( "width = %d mm (%f dpi)\n"
+ "height = %d mm (%f dpi)\n"
+ "refresh rate = %.2f Hz\n",
+ info.width, xdpi,
+ info.height, ydpi,
+ fps
+ );
+
+ printf("upper_margin=%d, lower_margin=%d, left_margin=%d, right_margin=%d, pixclock=%d, finfo.smem_len=%d\n",
+ info.upper_margin, info.lower_margin, info.left_margin, info.right_margin, info.pixclock, finfo.smem_len);
+
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
+ return -errno;
+
+ if (finfo.smem_len <= 0)
+ return -errno;
+
+ /*
+ * Open and map the display.
+ */
+
+ uint16_t* buffer = (uint16_t*) mmap(
+ 0, finfo.smem_len,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd, 0);
+
+ if (buffer == MAP_FAILED)
+ return -errno;
+
+ // at least for now, always clear the fb
+ memset(buffer, 0, finfo.smem_len);
+ memset(buffer, 0xff, 320*(info.yres_virtual/2)*2);
+
+ int l,t,w,h;
+ l=0;
+ t=0;
+ w=320;
+ h=480;
+ info.reserved[0] = 0x54445055; // "UPDT";
+ info.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
+ info.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
+
+ int err;
+ int c = 0;
+ int64_t time = systemTime();
+ while (1) {
+
+ info.activate = FB_ACTIVATE_VBL;
+ info.yoffset = 0;
+ ioctl(fd, FBIOPUT_VSCREENINFO, &info);
+
+ info.activate = FB_ACTIVATE_VBL;
+ info.yoffset = info.yres_virtual/2;
+ err = ioctl(fd, FBIOPUT_VSCREENINFO, &info);
+
+ c+=2;
+ if (c==60*2) {
+ int64_t now = systemTime();
+ time = now - time;
+ printf("refresh rate = %f Hz\n", (c*1000000000.0 / (double)time));
+ c = 0;
+ time = now;
+ }
+ }
+ return 0;
+}
diff --git a/tests/fstest/Android.mk b/tests/fstest/Android.mk
new file mode 100644
index 0000000..9be7ae4
--- /dev/null
+++ b/tests/fstest/Android.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2008 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := recovery_test
+LOCAL_SRC_FILES := recovery_test.cpp
+LOCAL_SHARED_LIBRARIES += libcutils libutils liblog liblogwrap
+LOCAL_STATIC_LIBRARIES += libtestUtil libfs_mgr
+LOCAL_C_INCLUDES += system/extras/tests/include \
+ system/extras/ext4_utils \
+ system/core/logwrapper/include
+include $(BUILD_NATIVE_TEST)
diff --git a/tests/fstest/recovery_test.cpp b/tests/fstest/recovery_test.cpp
new file mode 100644
index 0000000..02c7e8f
--- /dev/null
+++ b/tests/fstest/recovery_test.cpp
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2014 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 requied 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.
+ *
+ */
+
+/*
+ * These file system recovery tests ensure the ability to recover from
+ * filesystem crashes in key blocks (e.g. superblock).
+ */
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fs_mgr.h>
+#include <gtest/gtest.h>
+#include <logwrap/logwrap.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "cutils/properties.h"
+#include "ext4.h"
+#include "ext4_utils.h"
+
+#define LOG_TAG "fsRecoveryTest"
+#include <utils/Log.h>
+#include <testUtil.h>
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define FSTAB_PREFIX "/fstab."
+#define SB_OFFSET 1024
+static char UMOUNT_BIN[] = "/system/bin/umount";
+static char VDC_BIN[] = "/system/bin/vdc";
+
+enum Fs_Type { FS_UNKNOWN, FS_EXT4, FS_F2FS };
+
+namespace android {
+
+class DataFileVerifier {
+ public:
+ explicit DataFileVerifier(const char* file_name) {
+ strncpy(test_file_, file_name, FILENAME_MAX);
+ }
+
+ void verify_write() {
+ int write_fd = open(test_file_, O_CREAT | O_WRONLY, 0666);
+ ASSERT_TRUE(write_fd);
+ ASSERT_EQ(write(write_fd, "TEST", 4), 4);
+ close(write_fd);
+ }
+
+ void verify_read() {
+ char read_buff[4];
+ int read_fd = open(test_file_, O_RDONLY);
+ ASSERT_TRUE(read_fd);
+ ASSERT_EQ(read(read_fd, read_buff, sizeof(read_buff)), 4);
+ ASSERT_FALSE(strncmp(read_buff, "TEST", 4));
+ close(read_fd);
+ }
+
+ ~DataFileVerifier() {
+ unlink(test_file_);
+ }
+
+ private:
+ char test_file_[FILENAME_MAX];
+};
+
+namespace ext4 {
+bool getSuperBlock(const int blk_fd, struct ext4_super_block* sb) {
+ if (lseek(blk_fd, SB_OFFSET, SEEK_SET) == -1) {
+ testPrintE("Cannot lseek to ext4 superblock to read");
+ return false;
+ }
+
+ if (read(blk_fd, sb, sizeof(*sb)) != sizeof(*sb)) {
+ testPrintE("Cannot read ext4 superblock");
+ return false;
+ }
+
+ if (sb->s_magic != 0xEF53) {
+ testPrintE("Invalid ext4 superblock magic");
+ return false;
+ }
+
+ return true;
+}
+
+bool setSbErrorBit(const int blk_fd) {
+ // Read super block.
+ struct ext4_super_block sb;
+ if (!getSuperBlock(blk_fd, &sb)) {
+ return false;
+ }
+
+ // Check that the detected errors bit is not set.
+ if (sb.s_state & 0x2) {
+ testPrintE("Ext4 superblock already corrupted");
+ return false;
+ }
+
+ // Set the detected errors bit.
+ sb.s_state |= 0x2;
+
+ // Write superblock.
+ if (lseek(blk_fd, SB_OFFSET, SEEK_SET) == -1) {
+ testPrintE("Cannot lseek to superblock to write\n");
+ return false;
+ }
+
+ if (write(blk_fd, &sb, sizeof(sb)) != sizeof(sb)) {
+ testPrintE("Cannot write superblock\n");
+ return false;
+ }
+
+ return true;
+}
+
+bool corruptGdtFreeBlock(const int blk_fd) {
+ // Read super block.
+ struct ext4_super_block sb;
+ if (!getSuperBlock(blk_fd, &sb)) {
+ return false;
+ }
+ // Make sure the block size is 2K or 4K.
+ if ((sb.s_log_block_size != 1) && (sb.s_log_block_size != 2)) {
+ testPrintE("Ext4 block size not 2K or 4K\n");
+ return false;
+ }
+ int block_size = 1 << (10 + sb.s_log_block_size);
+ int num_bgs = DIV_ROUND_UP(sb.s_blocks_count_lo, sb.s_blocks_per_group);
+
+ if (sb.s_desc_size != sizeof(struct ext2_group_desc)) {
+ testPrintE("Can't handle ext4 block group descriptor size of %d",
+ sb.s_desc_size);
+ return false;
+ }
+
+ // Read first block group descriptor, decrement free block count, and
+ // write it back out.
+ if (lseek(blk_fd, block_size, SEEK_SET) == -1) {
+ testPrintE("Cannot lseek to ext4 block group descriptor table to read");
+ return false;
+ }
+
+ // Read in block group descriptors till we read one that has at least one free
+ // block.
+ struct ext2_group_desc gd;
+ for (int i = 0; i < num_bgs; i++) {
+ if (read(blk_fd, &gd, sizeof(gd)) != sizeof(gd)) {
+ testPrintE("Cannot read ext4 group descriptor %d", i);
+ return false;
+ }
+ if (gd.bg_free_blocks_count) {
+ break;
+ }
+ }
+
+ gd.bg_free_blocks_count--;
+
+ if (lseek(blk_fd, -sizeof(gd), SEEK_CUR) == -1) {
+ testPrintE("Cannot lseek to ext4 block group descriptor table to write");
+ return false;
+ }
+
+ if (write(blk_fd, &gd, sizeof(gd)) != sizeof(gd)) {
+ testPrintE("Cannot write modified ext4 group descriptor");
+ return false;
+ }
+ return true;
+}
+
+} // namespace ext4
+
+class FsRecoveryTest : public ::testing::Test {
+ protected:
+ FsRecoveryTest() : fs_type(FS_UNKNOWN), blk_fd_(-1) {}
+
+ bool setCacheInfoFromFstab() {
+ fs_type = FS_UNKNOWN;
+ char propbuf[PROPERTY_VALUE_MAX];
+ property_get("ro.hardware", propbuf, "");
+ char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+ snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
+
+ struct fstab *fstab = fs_mgr_read_fstab(fstab_filename);
+ if (!fstab) {
+ testPrintE("failed to open %s\n", fstab_filename);
+ } else {
+ // Loop through entries looking for cache.
+ for (int i = 0; i < fstab->num_entries; ++i) {
+ if (!strcmp(fstab->recs[i].mount_point, "/cache")) {
+ strcpy(blk_path_, fstab->recs[i].blk_device);
+ if (!strcmp(fstab->recs[i].fs_type, "ext4")) {
+ fs_type = FS_EXT4;
+ break;
+ } else if (!strcmp(fstab->recs[i].fs_type, "f2fs")) {
+ fs_type = FS_F2FS;
+ break;
+ }
+ }
+ }
+ fs_mgr_free_fstab(fstab);
+ }
+ return fs_type != FS_UNKNOWN;
+ }
+
+ bool unmountCache() {
+ char cache_str[] = "/cache";
+ char *umount_argv[] = {
+ UMOUNT_BIN,
+ cache_str,
+ };
+ int status;
+ return android_fork_execvp_ext(ARRAY_SIZE(umount_argv), umount_argv,
+ NULL, true, LOG_KLOG, false, NULL,
+ NULL, 0) >= 0;
+ }
+
+ bool mountAll() {
+ char storage_str[] = "storage";
+ char mountall_str[] = "mountall";
+ char *mountall_argv[] = {
+ VDC_BIN,
+ storage_str,
+ mountall_str,
+ };
+ int status;
+ return android_fork_execvp_ext(ARRAY_SIZE(mountall_argv), mountall_argv,
+ NULL, true, LOG_KLOG, false, NULL,
+ NULL, 0) >= 0;
+ }
+
+ int getCacheBlkFd() {
+ if (blk_fd_ == -1) {
+ blk_fd_ = open(blk_path_, O_RDWR);
+ }
+ return blk_fd_;
+ }
+
+ void closeCacheBlkFd() {
+ if (blk_fd_ > -1) {
+ close(blk_fd_);
+ }
+ blk_fd_ = -1;
+ }
+
+ void assertCacheHealthy() {
+ const char* test_file = "/cache/FsRecoveryTestGarbage.txt";
+ DataFileVerifier file_verify(test_file);
+ file_verify.verify_write();
+ file_verify.verify_read();
+ }
+
+ virtual void SetUp() {
+ assertCacheHealthy();
+ ASSERT_TRUE(setCacheInfoFromFstab());
+ }
+
+ virtual void TearDown() {
+ // Ensure /cache partition is accessible, mounted and healthy for other
+ // tests.
+ closeCacheBlkFd();
+ ASSERT_TRUE(mountAll());
+ assertCacheHealthy();
+ }
+
+ Fs_Type fs_type;
+
+ private:
+ char blk_path_[FILENAME_MAX];
+ int blk_fd_;
+};
+
+TEST_F(FsRecoveryTest, EXT4_CorruptGdt) {
+ if (fs_type != FS_EXT4) {
+ return;
+ }
+ // Setup test file in /cache.
+ const char* test_file = "/cache/CorruptGdtGarbage.txt";
+ DataFileVerifier file_verify(test_file);
+ file_verify.verify_write();
+ // Unmount and corrupt /cache gdt.
+ ASSERT_TRUE(unmountCache());
+ ASSERT_TRUE(ext4::corruptGdtFreeBlock(getCacheBlkFd()));
+ closeCacheBlkFd();
+ ASSERT_TRUE(mountAll());
+
+ // Verify results.
+ file_verify.verify_read();
+}
+
+TEST_F(FsRecoveryTest, EXT4_SetErrorBit) {
+ if (fs_type != FS_EXT4) {
+ return;
+ }
+ // Setup test file in /cache.
+ const char* test_file = "/cache/ErrorBitGarbagetxt";
+ DataFileVerifier file_verify(test_file);
+ file_verify.verify_write();
+
+ // Unmount and set /cache super block error bit.
+ ASSERT_TRUE(unmountCache());
+ ASSERT_TRUE(ext4::setSbErrorBit(getCacheBlkFd()));
+ closeCacheBlkFd();
+ ASSERT_TRUE(mountAll());
+
+ // Verify results.
+ file_verify.verify_read();
+ struct ext4_super_block sb;
+ ASSERT_TRUE(ext4::getSuperBlock(getCacheBlkFd(), &sb));
+ // Verify e2fsck has recovered the error bit of sb.
+ ASSERT_FALSE(sb.s_state & 0x2);
+}
+} // namespace android
diff --git a/tests/icachetest/Android.mk b/tests/icachetest/Android.mk
new file mode 100644
index 0000000..132efd3
--- /dev/null
+++ b/tests/icachetest/Android.mk
@@ -0,0 +1,15 @@
+# Copyright 2006 The Android Open Source Project
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= icache_main.c icache.S icache2.S
+
+LOCAL_SHARED_LIBRARIES := libc
+
+LOCAL_MODULE:= icache
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_TARGET_ARCH := arm
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/icachetest/icache.S b/tests/icachetest/icache.S
new file mode 100644
index 0000000..fbe8fa7
--- /dev/null
+++ b/tests/icachetest/icache.S
@@ -0,0 +1,181 @@
+/*
+ * icache.s
+ *
+ *
+ * Copyright 2005 The Android Open Source Project
+ *
+ */
+
+ .text
+ .global icache_test
+ .type icache_test, %function
+ .align
+
+
+#define LOOP \
+ subs r2, r2, #1 ; \
+ mov r0, r0 ; \
+ mov r0, r0 ; \
+ mov r0, r0 ; \
+ mov r0, r0 ; \
+ mov r0, r0 ; \
+ beq end_loop ; \
+ mov r0, r0 ; \
+
+
+
+ /*
+ * r0 = loop_count
+ * r1 = step
+ */
+
+ .align 5
+
+icache_test:
+ mov r0, r0
+ mov r0, r0
+ mov r0, r0
+ mov r0, r0
+ mov r0, r0
+
+end_loop:
+ subs r0, r0, r1
+ mov r2, r1
+ bxmi lr
+
+
+ /* here we're aligned on a cache line */
+
+ /* each loop iteration is one cache line
+ repeat this block 2048 times... */
+
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+
+ b end_loop
diff --git a/tests/icachetest/icache2.S b/tests/icachetest/icache2.S
new file mode 100644
index 0000000..2a204ce
--- /dev/null
+++ b/tests/icachetest/icache2.S
@@ -0,0 +1,171 @@
+/*
+ * icache.s
+ *
+ *
+ * Copyright 2005 The Android Open Source Project
+ *
+ */
+
+ .text
+ .align
+
+ .global icache_test2
+ .type icache_test2, %function
+
+#define LOOP \
+ mov r0, r0 ; \
+ mov r0, r0 ; \
+ mov r0, r0 ; \
+ mov r0, r0 ; \
+ mov r0, r0 ; \
+ mov r0, r0 ; \
+ mov r0, r0 ; \
+ mov r0, r0 ;
+
+
+ /*
+ * r0 = loop_count
+ * r1 = step
+ * r2 = mask
+ */
+
+icache_test2:
+end_loop:
+
+ /* each loop iteration is one cache line
+ repeat this block 2048 times... */
+
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+ LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP
+
+ subs r0, r0, #1
+ bgt end_loop
+ bx lr
+
+
diff --git a/tests/icachetest/icache_main.c b/tests/icachetest/icache_main.c
new file mode 100644
index 0000000..93f36d4
--- /dev/null
+++ b/tests/icachetest/icache_main.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <sys/time.h>
+
+extern void icache_test(long count, long step);
+extern void icache_test2(long count);
+
+int main()
+{
+ printf("[bytes]\t[us]\n");
+
+ struct timeval now, tm;
+ long long t;
+ long MBs;
+ long i;
+ long step = 32;
+ for (i=0 ; step<=2048 ; i++, step+=32)
+ {
+ long value;
+ gettimeofday(&now, 0);
+ icache_test(0x800000L, step);
+ gettimeofday(&tm, 0);
+ t = (tm.tv_sec*1000000LL+tm.tv_usec) - (now.tv_sec*1000000LL+now.tv_usec);
+ printf("%6ld\t%lld\n", step*32, t);
+ }
+
+ gettimeofday(&now, 0);
+ icache_test2(0x800000L / 2048);
+ gettimeofday(&tm, 0);
+ t = (tm.tv_sec*1000000LL+tm.tv_usec) - (now.tv_sec*1000000LL+now.tv_usec);
+ MBs = (8388608LL*32*1000000) / (t * (1024*1024));
+ printf("\n%6lld us\t%ld MB/s\n", t, MBs);
+
+ return 0;
+}
diff --git a/tests/include/testUtil.h b/tests/include/testUtil.h
new file mode 100644
index 0000000..3b75914
--- /dev/null
+++ b/tests/include/testUtil.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 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.
+ *
+ */
+
+#ifndef _TESTUTIL_H_
+#define _TESTUTIL_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+__BEGIN_DECLS
+
+// Time Utilities
+struct timespec double2ts(double amt);
+struct timeval double2tv(double amt);
+double ts2double(const struct timespec *val);
+double tv2double(const struct timeval *val);
+struct timespec tsDelta(const struct timespec *first,
+ const struct timespec *second);
+struct timeval tvDelta(const struct timeval *first,
+ const struct timeval *second);
+
+void testDelay(float amt);
+void testDelaySpin(float amt);
+
+// Pseudo Random Utilities
+int testRandBool(void);
+uint32_t testRand(void);
+uint32_t testRandMod(uint32_t mod);
+double testRandFract(void);
+
+// Testcase Output
+void testSetLogCatTag(const char *tag);
+const char *testGetLogCatTag(void);
+void testPrint(FILE *stream, const char *fmt, ...);
+#define testPrintI(...) do { \
+ testPrint(stdout, __VA_ARGS__); \
+ } while (0)
+#define testPrintE(...) do { \
+ testPrint(stderr, __VA_ARGS__); \
+ } while (0)
+
+// Hex Dump
+void testXDump(const void *buf, size_t size);
+void testXDumpSetIndent(uint8_t indent);
+uint8_t testXDumpGetIndent(void);
+void testXDumpSetOffset(uint64_t offset);
+uint64_t testXDumpGetOffset(void);
+
+// Command Execution
+void testExecCmd(const char *cmd);
+
+__END_DECLS
+
+#endif
diff --git a/tests/iptables/Android.mk b/tests/iptables/Android.mk
new file mode 100644
index 0000000..56a3fa8
--- /dev/null
+++ b/tests/iptables/Android.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2011 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.
+#
+
+include $(call all-subdir-makefiles)
diff --git a/tests/iptables/qtaguid/Android.mk b/tests/iptables/qtaguid/Android.mk
new file mode 100644
index 0000000..b92b662
--- /dev/null
+++ b/tests/iptables/qtaguid/Android.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2011 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := socketTag
+LOCAL_SRC_FILES := socketTag.cpp
+LOCAL_SHARED_LIBRARIES += libcutils libutils liblog
+LOCAL_STATIC_LIBRARIES += libtestUtil
+LOCAL_C_INCLUDES += system/extras/tests/include
+LOCAL_CFLAGS += -fno-strict-aliasing
+
+include $(BUILD_NATIVE_TEST)
diff --git a/tests/iptables/qtaguid/socketTag.cpp b/tests/iptables/qtaguid/socketTag.cpp
new file mode 100644
index 0000000..24a87e0
--- /dev/null
+++ b/tests/iptables/qtaguid/socketTag.cpp
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2011 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 requied 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.
+ *
+ */
+
+/*
+ * This socket tagging test is to ensure that the
+ * netfilter/xt_qtaguid kernel module somewhat behaves as expected
+ * with respect to tagging sockets.
+ */
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <gtest/gtest.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <string>
+
+#define LOG_TAG "socketTagTest"
+#include <utils/Log.h>
+#include <testUtil.h>
+
+namespace android {
+
+class SockInfo {
+public:
+ SockInfo() : fd(-1), addr(NULL) {};
+ int setup(uint64_t tag);
+ bool checkTag(uint64_t tag, uid_t uid);
+ int fd;
+ void *addr;
+};
+
+
+int openCtrl() {
+ int ctrl;
+ ctrl = open("/proc/net/xt_qtaguid/ctrl", O_RDWR);
+ if (!ctrl) {
+ testPrintE("qtaguid ctrl open failed: %s", strerror(errno));
+ }
+ return ctrl;
+}
+
+int doCtrlCommand(const char *fmt, ...)
+ __attribute__((__format__(__printf__, 1, 2)));
+
+int doCtrlCommand(const char *fmt, ...) {
+ char *buff;
+ int ctrl;
+ int res;
+ va_list argp;
+
+ va_start(argp, fmt);
+ ctrl = openCtrl();
+ vasprintf(&buff, fmt, argp);
+ errno = 0;
+ res = write(ctrl, buff, strlen(buff));
+ testPrintI("cmd: '%s' res=%d %d/%s", buff, res, errno, strerror(errno));
+ close(ctrl);
+ free(buff);
+ va_end(argp);
+ return res;
+}
+
+
+int writeModuleParam(const char *param, const char *data) {
+ int param_fd;
+ int res;
+ std::string filename("/sys/module/xt_qtaguid/parameters/");
+
+ filename += param;
+ param_fd = open(filename.c_str(), O_WRONLY);
+ if (param_fd < 0) {
+ testPrintE("qtaguid param open failed: %s", strerror(errno));
+ return -1;
+ }
+ res = write(param_fd, data, strlen(data));
+ if (res < 0) {
+ testPrintE("qtaguid param write failed: %s", strerror(errno));
+ }
+ close(param_fd);
+ return res;
+}
+
+/*----------------------------------------------------------------*/
+int SockInfo::setup(uint64_t tag) {
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd < 0) {
+ testPrintE("socket creation failed: %s", strerror(errno));
+ return -1;
+ }
+ if (doCtrlCommand("t %d %" PRIu64, fd, tag) < 0) {
+ testPrintE("socket setup: failed to tag");
+ close(fd);
+ return -1;
+ }
+ if (!checkTag(tag, getuid())) {
+ testPrintE("socket setup: Unexpected results: tag not found");
+ close(fd);
+ return -1;
+ }
+ if (doCtrlCommand("u %d", fd) < 0) {
+ testPrintE("socket setup: Unexpected results");
+ close(fd);
+ return -1;
+ }
+ return 0;
+}
+
+/* checkTag() also tries to lookup the socket address in the kernel and
+ * return it when *addr == NULL.
+ * This allows for better look ups when another process is also setting the same
+ * tag + uid. But it is not fool proof.
+ * Without the kernel reporting more info on who setup the socket tag, it is
+ * not easily verifiable from user-space.
+ * Returns: true if tag found.
+ */
+bool SockInfo::checkTag(uint64_t acct_tag, uid_t uid) {
+ int ctrl_fd;
+ ctrl_fd = openCtrl();
+ char ctrl_data[1024];
+ ssize_t read_size;
+ char *buff;
+ char *pos;
+ int res;
+ char *match_template;
+ uint64_t k_tag;
+ uint32_t k_uid;
+ uint64_t full_tag;
+ long dummy_count;
+ pid_t dummy_pid;
+
+ read_size = read(ctrl_fd, ctrl_data, sizeof(ctrl_data));
+ if (read_size < 0) {
+ testPrintE("Unable to read active tags from ctrl %d/%s",
+ errno, strerror(errno));
+ }
+ ctrl_data[read_size] = '\0';
+ testPrintI("<ctrl_raw_data>\n%s</ctrl_raw_data>", ctrl_data);
+
+ if (addr) {
+ assert(sizeof(void*) == sizeof(long int)); // Why does %p use 0x? grrr. %lx.
+ asprintf(&match_template, "sock=%" PRIxPTR " %s", (uintptr_t)addr, "tag=0x%" PRIx64" (uid=%u)");
+ }
+ else {
+ /* Allocate for symmetry */
+ asprintf(&match_template, "%s", " tag=0x%" PRIx64 " (uid=%u)");
+ }
+
+ full_tag = acct_tag | uid;
+
+ asprintf(&buff, match_template, full_tag | uid, uid);
+ testPrintI("looking for '%s'", buff);
+ pos = strstr(ctrl_data, buff);
+
+ if (pos && !addr) {
+ assert(sizeof(void*) == sizeof(long int)); // Why does %p use 0x? grrr. %lx.
+ res = sscanf(pos - strlen("sock=1234abcd"),
+ "sock=%" SCNxPTR " tag=0x%" SCNx64 " (uid=%" SCNu32 ") pid=%u f_count=%lu",
+ (uintptr_t *)&addr, &k_tag, &k_uid, &dummy_pid, &dummy_count );
+ if (!(res == 5 && k_tag == full_tag && k_uid == uid)) {
+ testPrintE("Unable to read sock addr res=%d", res);
+ addr = 0;
+ }
+ else {
+ testPrintI("Got sock_addr %lx", addr);
+ }
+ }
+ free(buff);
+ free(match_template);
+ close(ctrl_fd);
+ return pos != NULL;
+}
+
+
+class SocketTaggingTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ ctrl_fd = -1;
+ dev_fd = -1;
+ my_uid = getuid();
+ my_pid = getpid();
+ srand48(my_pid * my_uid);
+ // Adjust fake UIDs and tags so that multiple instances can run in parallel.
+ fake_uid = testRand();
+ fake_uid2 = testRand();
+ valid_tag1 = ((uint64_t)my_pid << 48) | ((uint64_t)testRand() << 32);
+ valid_tag2 = ((uint64_t)my_pid << 48) | ((uint64_t)testRand() << 32);
+ valid_tag2 &= 0xffffff00ffffffffllu; // Leave some room to make counts visible.
+ testPrintI("* start: pid=%lu uid=%lu uid1=0x%lx/%lu uid2=0x%lx/%lu"
+ " tag1=0x%" PRIx64 "/%" PRIu64 " tag2=0x%" PRIx64 "/% " PRIu64,
+ (unsigned long)my_pid, (unsigned long)my_uid,
+ (unsigned long)fake_uid, (unsigned long)fake_uid,
+ (unsigned long)fake_uid2, (unsigned long)fake_uid2,
+ valid_tag1, valid_tag1, valid_tag2, valid_tag2);
+ max_uint_tag = 0xffffffff00000000llu;
+ max_uint_tag = 1llu << 63 | (((uint64_t)my_pid << 48) ^ max_uint_tag);
+
+ testPrintI("kernel has qtaguid");
+ ctrl_fd = openCtrl();
+ ASSERT_GE(ctrl_fd, 0) << "qtaguid ctrl open failed";
+ close(ctrl_fd);
+ dev_fd = open("/dev/xt_qtaguid", O_RDONLY);
+ EXPECT_GE(dev_fd, 0) << "qtaguid dev open failed";
+
+ // We want to clean up any previous faulty test runs.
+ testPrintI("delete command does not fail");
+ EXPECT_GE(doCtrlCommand("d 0 %u", fake_uid), 0) << "Failed to delete fake_uid";
+ EXPECT_GE(doCtrlCommand("d 0 %u", fake_uid2), 0) << "Failed to delete fake_uid2";
+ EXPECT_GE(doCtrlCommand("d 0 %u", my_uid), 0) << "Failed to delete my_uid";
+
+ testPrintI("setup sock0 and addr via tag");
+ ASSERT_FALSE(sock0.setup(valid_tag1)) << "socket0 setup failed";
+ testPrintI("setup sock1 and addr via tag");
+ ASSERT_FALSE(sock1.setup(valid_tag1)) << "socket1 setup failed";
+ }
+
+ virtual void TearDown() {
+ if (dev_fd >= 0) {
+ close(dev_fd);
+ }
+ if (ctrl_fd >= 0) {
+ close(ctrl_fd);
+ }
+ }
+
+ SockInfo sock0;
+ SockInfo sock1;
+ int ctrl_fd;
+ int dev_fd;
+ uid_t fake_uid;
+ uid_t fake_uid2;
+ uid_t my_uid;
+ pid_t my_pid;
+ uint64_t valid_tag1;
+ uint64_t valid_tag2;
+ uint64_t max_uint_tag;
+ static const uint64_t invalid_tag1 = 0x0000000100000001llu;
+ static const int max_tags = 5;
+};
+
+TEST_F(SocketTaggingTest, TagData) {
+ max_uint_tag = 0xffffffff00000000llu;
+ char *max_tags_str;
+
+ testPrintI("setup tag limit");
+ asprintf(&max_tags_str, "%d", max_tags);
+ ASSERT_GE(writeModuleParam("max_sock_tags", max_tags_str), 0) << "Failed to setup tag limit";
+
+ testPrintI("tag quota reach limit");
+ for (int cnt = 0; cnt < max_tags; cnt++ ) {
+ uint64_t tag = valid_tag2 + ((uint64_t)cnt << 32);
+ EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, tag , fake_uid2), 0)
+ << "Tagging within limit failed";
+ EXPECT_TRUE(sock0.checkTag(tag, fake_uid2))<< "Unexpected results: tag not found";
+ }
+
+ testPrintI("tag quota go over limit");
+ uint64_t new_tag = valid_tag2 + ((uint64_t)max_tags << 32);
+ EXPECT_LT(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, new_tag, fake_uid2), 0);
+ EXPECT_TRUE(sock0.checkTag(valid_tag2 + (((uint64_t)max_tags - 1) << 32),
+ fake_uid2)) << "Unexpected results: tag not found";
+
+ testPrintI("valid untag");
+ EXPECT_GE(doCtrlCommand("u %d", sock0.fd), 0);
+ EXPECT_FALSE(sock0.checkTag(valid_tag2 + (((uint64_t)max_tags - 1) << 32), fake_uid2))
+ << "Untagged tag should not be there";
+
+ testPrintI("tag after untag should not free up max tags");
+ uint64_t new_tag2 = valid_tag2 + ((uint64_t)max_tags << 32);
+ EXPECT_LT(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, new_tag2 , fake_uid2), 0);
+ EXPECT_FALSE(sock0.checkTag(valid_tag2 + ((uint64_t)max_tags << 32), fake_uid2))
+ << "Tag should not be there";
+
+ testPrintI("delete one tag");
+ uint64_t new_tag3 = valid_tag2 + (((uint64_t)max_tags / 2) << 32);
+ EXPECT_GE(doCtrlCommand("d %" PRIu64 " %u", new_tag3, fake_uid2), 0);
+
+ testPrintI("2 tags after 1 delete pass/fail");
+ uint64_t new_tag4;
+ new_tag4 = valid_tag2 + (((uint64_t)max_tags + 1 ) << 32);
+ EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, new_tag4 , fake_uid2), 0);
+ EXPECT_TRUE(sock0.checkTag(valid_tag2 + (((uint64_t)max_tags + 1) << 32), fake_uid2))
+ << "Tag not found";
+ new_tag4 = valid_tag2 + (((uint64_t)max_tags + 2 ) << 32);
+ EXPECT_LT(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, new_tag4 , fake_uid2), 0);
+ EXPECT_FALSE(sock0.checkTag(valid_tag2 + (((uint64_t)max_tags + 2) << 32), fake_uid2))
+ << "Tag should not be there";
+
+ /* TODO(jpa): test tagging two different sockets with same tags and
+ * check refcounts the tag_node should be +2
+ */
+}
+
+TEST_F(SocketTaggingTest, InsufficientArgsFails) {
+ // Insufficient args. Expected failure
+ EXPECT_LE(doCtrlCommand("t"), 0) << "Insufficient args, should fail.";
+}
+
+TEST_F(SocketTaggingTest, BadCommandFails) {
+ // Bad command. Expected failure";
+ EXPECT_LE(doCtrlCommand("?"), 0) << "Bad command, should fail";
+}
+
+TEST_F(SocketTaggingTest, NoTagNoUid) {
+ // no tag, no uid
+ EXPECT_GE(doCtrlCommand("t %d", sock0.fd), 0);
+ ASSERT_TRUE(sock0.checkTag(0, my_uid)) << "Tag not found";
+}
+
+TEST_F(SocketTaggingTest, InvalidTagFail) {
+ // Invalid tag. Expected failure
+ EXPECT_LE(doCtrlCommand("t %d %" PRIu64, sock0.fd, invalid_tag1), 0);
+ ASSERT_FALSE(sock0.checkTag(invalid_tag1, my_uid)) << "Tag should not be there";
+}
+
+TEST_F(SocketTaggingTest, ValidTagWithNoUid) {
+ // Valid tag with no uid
+ EXPECT_GE(doCtrlCommand("t %d %" PRIu64, sock0.fd, valid_tag1), 0);
+ EXPECT_TRUE(sock0.checkTag(valid_tag1, my_uid)) << "Tag not found";
+}
+
+TEST_F(SocketTaggingTest, ValidUntag) {
+ // Valid untag
+ EXPECT_GE(doCtrlCommand("t %d %" PRIu64, sock0.fd, valid_tag1), 0);
+ EXPECT_TRUE(sock0.checkTag(valid_tag1, my_uid)) << "Tag not found";
+ EXPECT_GE(doCtrlCommand("u %d", sock0.fd), 0);
+ EXPECT_FALSE(sock0.checkTag(valid_tag1, my_uid)) << "Tag should be removed";
+}
+
+TEST_F(SocketTaggingTest, ValidFirsttag) {
+ // Valid 1st tag
+ EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag2, fake_uid), 0);
+ EXPECT_TRUE(sock0.checkTag(valid_tag2, fake_uid)) << "Tag not found.";
+}
+
+TEST_F(SocketTaggingTest, ValidReTag) {
+ // Valid re-tag
+ EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag2, fake_uid), 0);
+ EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag2, fake_uid), 0);
+ EXPECT_TRUE(sock0.checkTag(valid_tag2, fake_uid)) << "Tag not found.";
+}
+
+TEST_F(SocketTaggingTest, ValidReTagWithAcctTagChange) {
+ // Valid re-tag with acct_tag change
+ EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag2, fake_uid), 0);
+ EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag1, fake_uid), 0);
+ EXPECT_TRUE(sock0.checkTag(valid_tag1, fake_uid)) << "Tag not found.";
+}
+
+TEST_F(SocketTaggingTest, ReTagWithUidChange) {
+ // Re-tag with uid change
+ EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag1, fake_uid), 0);
+ EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag2, fake_uid2), 0);
+}
+
+TEST_F(SocketTaggingTest, Valid64BitAcctTag) {
+ // Valid 64bit acct tag
+ EXPECT_GE(doCtrlCommand("t %d %" PRIu64, sock0.fd, max_uint_tag), 0);
+ EXPECT_TRUE(sock0.checkTag(max_uint_tag, my_uid)) << "Tag not found.";
+}
+
+TEST_F(SocketTaggingTest, TagAnotherSocket) {
+ testPrintI("Tag two sockets");
+ EXPECT_GE(doCtrlCommand("t %d %" PRIu64, sock0.fd, max_uint_tag), 0);
+ EXPECT_GE(doCtrlCommand("t %d %" PRIu64 " %u", sock1.fd, valid_tag1, fake_uid2), 0);
+ EXPECT_TRUE(sock1.checkTag(valid_tag1, fake_uid2)) << "Tag not found.";
+ testPrintI("Untag socket0 of them only.");
+ EXPECT_GE(doCtrlCommand("u %d", sock0.fd), 0);
+ EXPECT_FALSE(sock0.checkTag(max_uint_tag, fake_uid)) << "Tag should not be there";
+ EXPECT_TRUE(sock1.checkTag(valid_tag1, fake_uid2)) << "Tag not found";
+ testPrintI("Now untag socket1 as well.");
+ EXPECT_GE(doCtrlCommand("u %d", sock1.fd), 0);
+ EXPECT_FALSE(sock1.checkTag(valid_tag1, fake_uid2)) << "Tag should not be there";
+}
+
+TEST_F(SocketTaggingTest, TagInvalidSocketFail) {
+ // Invalid tag. Expected failure
+ close(sock0.fd);
+ EXPECT_LE(doCtrlCommand("t %d %" PRIu64 " %u", sock0.fd, valid_tag1, my_uid), 0);
+ EXPECT_FALSE(sock0.checkTag(valid_tag1, my_uid)) << "Tag should not be there";
+}
+
+TEST_F(SocketTaggingTest, UntagInvalidSocketFail) {
+ // Invalid untag. Expected failure";
+ close(sock1.fd);
+ EXPECT_LE(doCtrlCommand("u %d", sock1.fd), 0);
+}
+
+} // namespace android
diff --git a/tests/kernel.config/Android.mk b/tests/kernel.config/Android.mk
new file mode 100644
index 0000000..c05fcc8
--- /dev/null
+++ b/tests/kernel.config/Android.mk
@@ -0,0 +1,79 @@
+# Copyright 2016 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+
+# -----------------------------------------------------------------------------
+# Unit tests.
+# -----------------------------------------------------------------------------
+
+test_c_flags := \
+ -fstack-protector-all \
+ -g \
+ -Wall -Wextra \
+ -Werror \
+ -fno-builtin \
+ -std=gnu++11
+
+# Required Tests
+cts_src_files := \
+ aslr_test.cpp \
+ multicast_test.cpp \
+ pstore_test.cpp \
+ sysvipc_test.cpp \
+ logger_test.cpp
+
+# Required plus Recommended Tests
+test_src_files := \
+ $(cts_src_files) \
+ aslr_rec_test.cpp \
+ mmc_max_speed_test.cpp \
+
+cts_executable := CtsKernelConfigTestCases
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := kernel-config-unit-tests
+LOCAL_MODULE_TAGS := tests
+LOCAL_CFLAGS := $(test_c_flags)
+LOCAL_CFLAGS := -DHAS_KCMP
+LOCAL_SRC_FILES := $(test_src_files)
+include $(BUILD_NATIVE_TEST)
+
+ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(cts_executable)_list
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(test_c_flags)
+LOCAL_SRC_FILES := $(cts_src_files)
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+LOCAL_CXX_STL := libc++
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_HOST_NATIVE_TEST)
+
+endif # ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(cts_executable)
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(test_c_flags)
+LOCAL_CFLAGS := -DHAS_KCMP
+LOCAL_SRC_FILES := $(cts_src_files)
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+LOCAL_STATIC_LIBRARIES := libgtest libgtest_main
+
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+LOCAL_CTS_TEST_PACKAGE := android.kernel.config
+LOCAL_CTS_GTEST_LIST_EXECUTABLE := $(ALL_MODULES.$(cts_executable)_list$(HOST_2ND_ARCH_MODULE_SUFFIX).INSTALLED)
+include $(BUILD_CTS_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ scrape_mmap_addr.cpp
+
+LOCAL_MODULE := scrape_mmap_addr
+include $(BUILD_NATIVE_TEST)
diff --git a/tests/kernel.config/AndroidTest.xml b/tests/kernel.config/AndroidTest.xml
new file mode 100644
index 0000000..4fe3192
--- /dev/null
+++ b/tests/kernel.config/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<configuration description="Config for CTS Kernel Config test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="CtsKernelConfigTestCases->/data/local/tmp/CtsKernelConfigTestCases" />
+ <option name="append-bitness" value="true" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="CtsKernelConfigTestCases" />
+ </test>
+</configuration>
diff --git a/tests/kernel.config/aslr_rec_test.cpp b/tests/kernel.config/aslr_rec_test.cpp
new file mode 100644
index 0000000..e154424
--- /dev/null
+++ b/tests/kernel.config/aslr_rec_test.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "aslr_test.h"
+
+/* run tests if on supported arch */
+#if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || defined(__arm__)
+
+/* make sure the default entropy values matches what we expect */
+TEST_F(AslrMmapTest, match_default) {
+ if (user32) {
+ // running 32-bit userspace on 64-bit kernel, only compat used.
+ return;
+ } else {
+ EXPECT_EQ(def, get_mmap_rnd_bits(false));
+ }
+}
+
+/* make sure the default compat entropy values matches what we expect */
+TEST_F(AslrMmapTest, match_compat_default) {
+ if (compat || user32)
+ EXPECT_EQ(def_cmpt, get_mmap_rnd_bits(true));
+}
+
+/* make sure we can't set entropy below a minimum threshold */
+TEST_F(AslrMmapTest, match_min) {
+ if (user32) {
+ // running 32-bit userspace on 64-bit kernel, only compat used.
+ return;
+ } else {
+ EXPECT_FALSE(set_mmap_rnd_bits(min - 1, false));
+ EXPECT_TRUE(set_mmap_rnd_bits(min, false));
+ EXPECT_EQ(min, get_mmap_rnd_bits(false));
+ }
+}
+
+/* make sure we can't set compat entropy below a minimum threshold */
+TEST_F(AslrMmapTest, match_compat_min) {
+ if (compat || user32) {
+ EXPECT_FALSE(set_mmap_rnd_bits(min_cmpt - 1, true));
+ EXPECT_TRUE(set_mmap_rnd_bits(min_cmpt, true));
+ EXPECT_EQ(min_cmpt, get_mmap_rnd_bits(true));
+ }
+}
+
+/* make sure we can't set entropy above a maximum threshold */
+TEST_F(AslrMmapTest, match_max) {
+ if (user32) {
+ // running 32-bit userspace on 64-bit kernel, only compat used.
+ return;
+ } else {
+ EXPECT_FALSE(set_mmap_rnd_bits(max + 1, false));
+ EXPECT_TRUE(set_mmap_rnd_bits(max, false));
+ EXPECT_EQ(max, get_mmap_rnd_bits(false));
+ }
+}
+
+/* make sure we can't set compat entropy above a maximum threshold */
+TEST_F(AslrMmapTest, match_compat_max) {
+ if (compat || user32) {
+ EXPECT_FALSE(set_mmap_rnd_bits(max_cmpt + 1, true));
+ EXPECT_TRUE(set_mmap_rnd_bits(max_cmpt, true));
+ EXPECT_EQ(max_cmpt, get_mmap_rnd_bits(true));
+ }
+}
+
+/* make sure observed entropy is what we expect when we set min value */
+TEST_F(AslrMmapTest, entropy_min) {
+ if (user32) {
+ // running 32-bit userspace on 64-bit kernel, only compat used.
+ return;
+ } else {
+ EXPECT_TRUE(set_mmap_rnd_bits(min, false));
+ EXPECT_EQ(min, calc_mmap_entropy(path, lib, 16));
+ }
+}
+
+/* make sure observed compat entropy is what we expect when we set min value */
+TEST_F(AslrMmapTest, entropy_cmpt_min) {
+ if (compat || user32) {
+ EXPECT_TRUE(set_mmap_rnd_bits(min_cmpt, true));
+ EXPECT_EQ(min_cmpt, calc_mmap_entropy(SCRAPE_PATH_32, SCRAPE_LIB_32, 16));
+ }
+}
+
+/* make sure observed entropy is what we expect when we set max value */
+TEST_F(AslrMmapTest, entropy_max) {
+ if (user32) {
+ // running 32-bit userspace on 64-bit kernel, only compat used.
+ return;
+ } else {
+ EXPECT_TRUE(set_mmap_rnd_bits(max, false));
+ EXPECT_EQ(max, calc_mmap_entropy(path, lib, 16));
+ }
+}
+
+/* make sure observed compat entropy is what we expect when we set max value */
+TEST_F(AslrMmapTest, entropy_cmpt_max) {
+ if (compat || user32) {
+ EXPECT_TRUE(set_mmap_rnd_bits(max_cmpt, true));
+ EXPECT_EQ(max_cmpt, calc_mmap_entropy(SCRAPE_PATH_32, SCRAPE_LIB_32, 16));
+ }
+}
+
+/* make sure observed entropy is what we expect for default value */
+TEST_F(AslrMmapTest, entropy_def) {
+ if (user32) {
+ // running 32-bit userspace on 64-bit kernel, only compat used.
+ return;
+ } else {
+ EXPECT_EQ(def, calc_mmap_entropy(path, lib, 16));
+ }
+}
+
+/* make sure observed entropy is what we expect for default compat value */
+TEST_F(AslrMmapTest, entropy_cmpt_def) {
+ if (compat || user32) {
+ EXPECT_EQ(def_cmpt, calc_mmap_entropy(SCRAPE_PATH_32, SCRAPE_LIB_32, 16));
+ }
+}
+
+#endif /* supported arch */
diff --git a/tests/kernel.config/aslr_test.cpp b/tests/kernel.config/aslr_test.cpp
new file mode 100644
index 0000000..ef47f4f
--- /dev/null
+++ b/tests/kernel.config/aslr_test.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "aslr_test.h"
+
+unsigned int get_mmap_rnd_bits(bool compat) {
+ std::string path;
+
+ if (compat)
+ path = PROCFS_COMPAT_PATH;
+ else
+ path = PROCFS_PATH;
+
+ std::ifstream bi_file(path);
+ if (!bi_file)
+ return false;
+ std::string str_rec;
+ bi_file >> str_rec;
+
+ return stoi(str_rec);
+}
+
+bool set_mmap_rnd_bits(unsigned int new_val, bool compat) {
+ std::string path;
+
+ if (compat)
+ path = "/proc/sys/vm/mmap_rnd_compat_bits";
+ else
+ path = "/proc/sys/vm/mmap_rnd_bits";
+
+ std::ofstream bo_file(path, std::ios::out);
+ if (!bo_file)
+ return false;
+
+ std::string str_val = std::to_string(new_val);
+ bo_file << str_val << std::flush;
+ bo_file.close();
+
+ // check to make sure it was recorded
+ std::ifstream bi_file(path);
+ if (!bi_file)
+ return false;
+ std::string str_rec;
+ bi_file >> str_rec;
+ bi_file.close();
+ if (str_val.compare(str_rec) != 0)
+ return false;
+ return true;
+}
+
+std::string scrape_addr(const char *exec_name, const char *lib_match) {
+ pid_t pid;
+ int fd[2];
+ char buff[MAX_ADDR_LEN];
+ int len, status;
+ if(pipe(fd)) {
+ std::cerr << "Error creating pipe:" << strerror(errno) << "\n";
+ return std::string();
+ }
+
+ if ((pid = fork()) < 0) {
+ std::cerr << "Error creating new process: " << strerror(errno) << "\n";
+ close(fd[0]);
+ close(fd[1]);
+ return std::string();
+ } else if (pid > 0) {
+ // parent
+ close(fd[1]);
+ wait(&status);
+ if (status == -1) {
+ std::cerr << "Unable to find starting address of mmapp'd libc. Aborting.\n";
+ close(fd[0]);
+ return std::string();
+ }
+ len = read(fd[0], buff, MAX_ADDR_LEN - 1);
+ if (len < 0) {
+ std::cerr << "Error reading pipe from child: " << strerror(errno) << "\n";
+ close(fd[0]);
+ return std::string();
+ }
+ buff[len] = '\0';
+ close(fd[0]);
+ } else {
+ // child, dup 'n' exec
+ close(fd[0]);
+ if(dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
+ std::cerr << "Error dup'n pipe to STDOUT of child: " << strerror(errno) << "\n";
+ close(fd[1]);
+ return std::string();
+ }
+ if(execlp(exec_name, exec_name, lib_match, (char *) NULL)) {
+ std::cerr << "Error exec'ing mmap_scraper: " << strerror(errno) << "\n";
+ close(fd[1]);
+ return std::string();
+ }
+ }
+ return std::string(buff, strlen(buff));
+}
+
+unsigned int calc_mmap_entropy(const char *exec_name, const char *lib_match, size_t samp_sz) {
+ uint64_t min_addr = 0, max_addr = 0;
+
+ std::unordered_set<uint64_t> addrs = { };
+
+ // get our first value
+ uint64_t addr = min_addr = max_addr = std::stoll(scrape_addr(exec_name, lib_match), 0, 16);
+ addrs.insert(addr);
+ for (unsigned int i = 0; i < samp_sz - 1; ++i) {
+ std::string addr_str = scrape_addr(exec_name, lib_match);
+ if (addr_str.empty())
+ return 0;
+ addr = std::stoll(addr_str, 0, 16);
+ if (addr < min_addr)
+ min_addr = addr;
+ if (addr >= max_addr)
+ max_addr = addr;
+ addrs.insert(addr);
+ }
+ if (addrs.size() < (samp_sz >> 1)) {
+ std::cerr << "> 50% collisions in mmap addresses, entropy appears to be rigged!";
+ return 0;
+ }
+ unsigned int e_bits = (int) (std::ceil(std::log2(max_addr - min_addr)) - std::log2(getpagesize()));
+ return e_bits;
+}
+
+const char *AslrMmapTest::path;
+const char *AslrMmapTest::lib;
+unsigned int AslrMmapTest::def, AslrMmapTest::min, AslrMmapTest::max;
+bool AslrMmapTest::compat = false, AslrMmapTest::user32 = false;
+unsigned int AslrMmapTest::def_cmpt, AslrMmapTest::min_cmpt, AslrMmapTest::max_cmpt;
+
+void AslrMmapTest::SetUpTestCase() {
+ /* set up per-arch values */
+#if defined(__x86_64__)
+ def = 32;
+ min = 28;
+ max = 32;
+ path = SCRAPE_PATH_64;
+ lib = SCRAPE_LIB_64;
+
+ compat = true;
+ def_cmpt = 16;
+ min_cmpt = 8;
+ max_cmpt = 16;
+
+#elif defined(__i386__)
+ def = 16;
+ min = 8;
+ max = 16;
+ path = SCRAPE_PATH_32;
+ lib = SCRAPE_LIB_32;
+
+ if (!access(PROCFS_COMPAT_PATH, F_OK)) {
+ // running 32 bit userspace over 64-bit kernel
+ user32 = true;
+ def_cmpt = 16;
+ min_cmpt = 8;
+ max_cmpt = 16;
+ }
+
+#elif defined(__aarch64__)
+ unsigned int pgbits = std::log2(getpagesize());
+ def = 24;
+ min = 18 - (pgbits - 12);
+ max = 24;
+ path = SCRAPE_PATH_64;
+ lib = SCRAPE_LIB_64;
+
+ compat = true;
+ def_cmpt = 16;
+ min_cmpt = 11 - (pgbits - 12);
+ max_cmpt = 16;
+
+#elif defined(__arm__)
+ unsigned int pgbits = std::log2(getpagesize());
+ def = 16;
+ min = 8;
+ max = 16;
+ path = SCRAPE_PATH_32;
+ lib = SCRAPE_LIB_32;
+
+ if (!access(PROCFS_COMPAT_PATH, F_OK)) {
+ // running 32 bit userspace over 64-bit kernel
+ user32 = true;
+ def_cmpt = 16;
+ min_cmpt = 11 - (pgbits - 12);;
+ max_cmpt = 16;
+ }
+#endif
+}
+
+void AslrMmapTest::TearDown() {
+ if (!user32)
+ set_mmap_rnd_bits(def, false);
+ if (user32 || compat)
+ set_mmap_rnd_bits(def_cmpt, true);
+}
+
+/* run tests only if on supported arch */
+#if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || defined(__arm__)
+
+TEST_F(AslrMmapTest, entropy_min_def) {
+ if (user32) {
+ // running 32-bit userspace on 64-bit kernel, only compat used.
+ return;
+ } else {
+ EXPECT_GE(def, calc_mmap_entropy(path, lib, 16));
+ }
+}
+
+TEST_F(AslrMmapTest, entropy_min_cmpt_def) {
+ if (compat || user32) {
+ EXPECT_GE(def_cmpt, calc_mmap_entropy(SCRAPE_PATH_32, SCRAPE_LIB_32, 16));
+ }
+}
+
+#endif /* supported arch */
diff --git a/tests/kernel.config/aslr_test.h b/tests/kernel.config/aslr_test.h
new file mode 100644
index 0000000..355a62a
--- /dev/null
+++ b/tests/kernel.config/aslr_test.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ASLR_TEST_H
+#define ASLR_TEST_H
+
+#include <cmath>
+#include <errno.h>
+#include <fstream>
+#include <iostream>
+#include <stdint.h>
+#include <string>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <unordered_set>
+
+#include <gtest/gtest.h>
+
+#define MAX_ADDR_LEN 256
+
+#define PROCFS_PATH "/proc/sys/vm/mmap_rnd_bits"
+#define PROCFS_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
+
+#define SCRAPE_PATH_64 "/data/nativetest64/scrape_mmap_addr/scrape_mmap_addr"
+#define SCRAPE_PATH_32 "/data/nativetest/scrape_mmap_addr/scrape_mmap_addr"
+#define SCRAPE_LIB_64 "/system/bin/linker64"
+#define SCRAPE_LIB_32 "/system/bin/linker"
+
+class AslrMmapTest : public ::testing::Test {
+ protected:
+ static void SetUpTestCase();
+ static const char *path;
+ static const char *lib;
+ static unsigned int def, min, max;
+ static bool compat, user32;
+ static unsigned int def_cmpt, min_cmpt, max_cmpt;
+
+ void TearDown();
+};
+
+/*
+ * gets the current mmap_rnd_bits value. requires root.
+ */
+unsigned int get_mmap_rnd_bits(bool compat);
+
+/*
+ * sets the corresponding mmap_rnd_bits variable, returns false if couldn't
+ * change. requires root.
+ */
+bool set_mmap_rnd_bits(unsigned int new_val, bool compat);
+
+/*
+ * scrape_addr - get the raw starting address from /proc/child_pid/mmaps
+ */
+std::string scrape_addr(const char *exec_name, const char *lib_match);
+
+/*
+ * forks off sample_size processes and records the starting address of the
+ * indicated library as reported by exec_name. Reports entropy observed among
+ * recorded samples.
+ */
+unsigned int calc_mmap_entropy(const char *exec_name, const char *lib_match, size_t samp_sz);
+
+#endif //ASLR_TEST_H
diff --git a/tests/kernel.config/logger_test.cpp b/tests/kernel.config/logger_test.cpp
new file mode 100644
index 0000000..f0874d8
--- /dev/null
+++ b/tests/kernel.config/logger_test.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+TEST(kernel_config, NOT_CONFIG_ANDROID_LOGGER) {
+ EXPECT_NE(0, access("/dev/log/main", F_OK));
+ EXPECT_NE(0, access("/dev/log_main", F_OK));
+ EXPECT_NE(0, access("/dev/log/radio", F_OK));
+ EXPECT_NE(0, access("/dev/log_radio", F_OK));
+ EXPECT_NE(0, access("/dev/log/events", F_OK));
+ EXPECT_NE(0, access("/dev/log_events", F_OK));
+ EXPECT_NE(0, access("/dev/log/system", F_OK));
+ EXPECT_NE(0, access("/dev/log_system", F_OK));
+}
diff --git a/tests/kernel.config/mmc_max_speed_test.cpp b/tests/kernel.config/mmc_max_speed_test.cpp
new file mode 100644
index 0000000..40cf0d0
--- /dev/null
+++ b/tests/kernel.config/mmc_max_speed_test.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+TEST(kernel_config, CONFIG_MMC_BLOCK_MAX_SPEED) {
+ EXPECT_EQ(0, access("/sys/block/mmcblk0/max_read_speed", F_OK));
+ EXPECT_EQ(0, access("/sys/block/mmcblk0/max_write_speed", F_OK));
+ EXPECT_EQ(0, access("/sys/block/mmcblk0/cache_size", F_OK));
+}
diff --git a/tests/kernel.config/multicast_test.cpp b/tests/kernel.config/multicast_test.cpp
new file mode 100644
index 0000000..28655e8
--- /dev/null
+++ b/tests/kernel.config/multicast_test.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+TEST(kernel_config, CONFIG_IPV6) {
+ EXPECT_EQ(0, access("/proc/net/igmp6", F_OK));
+}
+
+TEST(kernel_config, CONFIG_IP_MULTICAST) {
+ EXPECT_EQ(0, access("/proc/net/igmp", F_OK));
+}
diff --git a/tests/kernel.config/pstore_test.cpp b/tests/kernel.config/pstore_test.cpp
new file mode 100644
index 0000000..1dd5e72
--- /dev/null
+++ b/tests/kernel.config/pstore_test.cpp
@@ -0,0 +1,32 @@
+
+/*
+ * Copyright (C) 2016 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.
+ */
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+TEST(kernel_config, CONFIG_PSTORE) {
+ EXPECT_EQ(0, access("/sys/fs/pstore", F_OK));
+}
+
+TEST(kernel_config, CONFIG_PSTORE_CONSOLE) {
+ EXPECT_EQ(0, access("/sys/fs/pstore/console-ramoops", F_OK));
+}
+
+TEST(kernel_config, CONFIG_PSTORE_PMSG) {
+ EXPECT_EQ(0, access("/dev/pmsg0", F_OK));
+ EXPECT_EQ(0, access("/sys/fs/pstore/pmsg-ramoops-0", F_OK));
+}
diff --git a/tests/kernel.config/scrape_mmap_addr.cpp b/tests/kernel.config/scrape_mmap_addr.cpp
new file mode 100644
index 0000000..be5995f
--- /dev/null
+++ b/tests/kernel.config/scrape_mmap_addr.cpp
@@ -0,0 +1,32 @@
+#include <errno.h>
+#include <fstream>
+#include <iostream>
+#include <regex>
+#include <string>
+#include <string.h>
+
+int main(int argc, char * argv[]) {
+ if (argc != 2) {
+ std::cerr << "usage: " << argv[0] << ": libname\n";
+ return -1;
+ }
+ std::regex reg(std::string("^([a-f0-9]+)\\-[0-9a-f]+\\s+.+\\s+(\\d+)\\s+.+\\s+\\d+\\s+") + std::string(argv[1]) + std::string("\\s*$"));
+
+ /* open /proc/self/maps */
+ std::string ln;
+ std::ifstream m_file("/proc/self/maps");
+ if (!m_file) {
+ std::cerr << "Unable to open /proc/self/maps " << strerror(errno) << "\n";
+ return -1;
+ }
+ while (getline(m_file, ln)) {
+ std::smatch sm;
+ if (std::regex_match (ln,sm, reg)) {
+ if (std::stoi(sm[2]) == 0) {
+ std::cout << sm[1];
+ return 0;
+ }
+ }
+ }
+ return -1;
+}
diff --git a/tests/kernel.config/sysvipc_test.cpp b/tests/kernel.config/sysvipc_test.cpp
new file mode 100644
index 0000000..49952f0
--- /dev/null
+++ b/tests/kernel.config/sysvipc_test.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#include <errno.h>
+#ifdef HAS_KCMP
+#include <linux/kcmp.h>
+#include <sys/syscall.h>
+#endif
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+#ifdef HAS_KCMP
+int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) {
+ return syscall(SYS_kcmp, pid1, pid2, type, 0, idx1, idx2);
+}
+#endif
+
+TEST(kernel_config, NOT_CONFIG_SYSVIPC) {
+#ifdef HAS_KCMP
+ pid_t pid = getpid();
+ int ret = kcmp(pid, pid, KCMP_SYSVSEM, 0, 0);
+ int error = (ret == -1) ? (errno == ENOSYS) ? EOPNOTSUPP : errno : 0;
+ EXPECT_EQ(-1, kcmp(pid, pid, KCMP_SYSVSEM, 0, 0));
+ EXPECT_EQ(EOPNOTSUPP, error);
+#endif
+ EXPECT_EQ(-1, access("/proc/sysvipc", F_OK));
+ EXPECT_EQ(-1, access("/proc/sysvipc/msg", F_OK));
+ EXPECT_EQ(-1, access("/proc/sysvipc/sem", F_OK));
+ EXPECT_EQ(-1, access("/proc/sysvipc/shm", F_OK));
+}
+
diff --git a/tests/lib/Android.mk b/tests/lib/Android.mk
new file mode 100644
index 0000000..db16ed2
--- /dev/null
+++ b/tests/lib/Android.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2010 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(call all-subdir-makefiles)
diff --git a/tests/lib/testUtil/Android.mk b/tests/lib/testUtil/Android.mk
new file mode 100644
index 0000000..f814dac
--- /dev/null
+++ b/tests/lib/testUtil/Android.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2010 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE:= libtestUtil
+LOCAL_SRC_FILES:= testUtil.c
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../include
+LOCAL_CFLAGS += -std=c99
+LOCAL_SHARED_LIBRARIES += libcutils libutils
+
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/tests/lib/testUtil/testUtil.c b/tests/lib/testUtil/testUtil.c
new file mode 100644
index 0000000..d4dcea2
--- /dev/null
+++ b/tests/lib/testUtil/testUtil.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2010 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.
+ *
+ */
+
+#include <testUtil.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include <cutils/log.h>
+
+#define ALEN(a) (sizeof(a) / sizeof((a)[0])) // Array length
+typedef unsigned int bool_t;
+#define true (0 == 0)
+#define false (!true)
+
+#define MAXSTR 200
+
+static const char *logCatTag;
+static const unsigned int uSecsPerSec = 1000000;
+static const unsigned int nSecsPerSec = 1000000000;
+
+// struct timespec to double
+double ts2double(const struct timespec *val)
+{
+ double rv;
+
+ rv = val->tv_sec;
+ rv += (double) val->tv_nsec / nSecsPerSec;
+
+ return rv;
+}
+
+// struct timeval to double
+double tv2double(const struct timeval *val)
+{
+ double rv;
+
+ rv = val->tv_sec;
+ rv += (double) val->tv_usec / uSecsPerSec;
+
+ return rv;
+}
+
+// double to struct timespec
+struct timespec double2ts(double amt)
+{
+ struct timespec rv;
+
+ rv.tv_sec = floor(amt);
+ rv.tv_nsec = (amt - rv.tv_sec) * nSecsPerSec;
+ // TODO: Handle cases where amt is negative
+ while ((unsigned) rv.tv_nsec >= nSecsPerSec) {
+ rv.tv_nsec -= nSecsPerSec;
+ rv.tv_sec++;
+ }
+
+ return rv;
+}
+
+// double to struct timeval
+struct timeval double2tv(double amt)
+{
+ struct timeval rv;
+
+ rv.tv_sec = floor(amt);
+ rv.tv_usec = (amt - rv.tv_sec) * uSecsPerSec;
+ // TODO: Handle cases where amt is negative
+ while ((unsigned) rv.tv_usec >= uSecsPerSec) {
+ rv.tv_usec -= uSecsPerSec;
+ rv.tv_sec++;
+ }
+
+ return rv;
+}
+
+// Delta (difference) between two struct timespec.
+// It is expected that the time given by the structure pointed to by
+// second, is later than the time pointed to by first.
+struct timespec tsDelta(const struct timespec *first,
+ const struct timespec *second)
+{
+ struct timespec rv;
+
+ assert(first != NULL);
+ assert(second != NULL);
+ assert(first->tv_nsec >= 0 && first->tv_nsec < nSecsPerSec);
+ assert(second->tv_nsec >= 0 && second->tv_nsec < nSecsPerSec);
+ rv.tv_sec = second->tv_sec - first->tv_sec;
+ if (second->tv_nsec >= first->tv_nsec) {
+ rv.tv_nsec = second->tv_nsec - first->tv_nsec;
+ } else {
+ rv.tv_nsec = (second->tv_nsec + nSecsPerSec) - first->tv_nsec;
+ rv.tv_sec--;
+ }
+
+ return rv;
+}
+
+// Delta (difference) between two struct timeval.
+// It is expected that the time given by the structure pointed to by
+// second, is later than the time pointed to by first.
+struct timeval tvDelta(const struct timeval *first,
+ const struct timeval *second)
+{
+ struct timeval rv;
+
+ assert(first != NULL);
+ assert(second != NULL);
+ assert(first->tv_usec >= 0 && first->tv_usec < uSecsPerSec);
+ assert(second->tv_usec >= 0 && second->tv_usec < uSecsPerSec);
+ rv.tv_sec = second->tv_sec - first->tv_sec;
+ if (second->tv_usec >= first->tv_usec) {
+ rv.tv_usec = second->tv_usec - first->tv_usec;
+ } else {
+ rv.tv_usec = (second->tv_usec + uSecsPerSec) - first->tv_usec;
+ rv.tv_sec--;
+ }
+
+ return rv;
+}
+
+void testPrint(FILE *stream, const char *fmt, ...)
+{
+ char line[MAXSTR];
+ va_list args;
+
+ va_start(args, fmt);
+ vsnprintf(line, sizeof(line), fmt, args);
+ if (stream == stderr) {
+ ALOG(LOG_ERROR, logCatTag, "%s", line);
+ } else {
+ ALOG(LOG_INFO, logCatTag, "%s", line);
+ }
+ vfprintf(stream, fmt, args);
+ fputc('\n', stream);
+}
+
+// Set tag used while logging to the logcat error interface
+void testSetLogCatTag(const char *tag)
+{
+ logCatTag = tag;
+}
+
+// Obtain pointer to current log to logcat error interface tag
+const char * testGetLogCatTag(void)
+{
+ return logCatTag;
+}
+
+/*
+ * Random
+ *
+ * Returns a pseudo random number in the range [0:2^32-1].
+ *
+ * Precondition: srand48() called to set the seed of
+ * the pseudo random number generator.
+ */
+uint32_t testRand(void)
+{
+ uint32_t val;
+
+ // Use lrand48() to obtain 31 bits worth
+ // of randomness.
+ val = lrand48();
+
+ // Make an additional lrand48() call and merge
+ // the randomness into the most significant bits.
+ val ^= lrand48() << 1;
+
+ return val;
+}
+
+/*
+ * Random Modulus
+ *
+ * Pseudo randomly returns unsigned integer in the range [0, mod).
+ *
+ * Precondition: srand48() called to set the seed of
+ * the pseudo random number generator.
+ */
+uint32_t testRandMod(uint32_t mod)
+{
+ // Obtain the random value
+ // Use lrand48() when it would produce a sufficient
+ // number of random bits, otherwise use testRand().
+ const uint32_t lrand48maxVal = ((uint32_t) 1 << 31) - 1;
+ uint32_t val = (mod <= lrand48maxVal) ? (uint32_t) lrand48() : testRand();
+
+ /*
+ * The contents of individual bytes tend to be less than random
+ * across different seeds. For example, srand48(x) and
+ * srand48(x + n * 4) cause lrand48() to return the same sequence of
+ * least significant bits. For small mod values this can produce
+ * noticably non-random sequnces. For mod values of less than 2
+ * bytes, will use the randomness from all the bytes.
+ */
+ if (mod <= 0x10000) {
+ val = (val & 0xffff) ^ (val >> 16);
+
+ // If mod less than a byte, can further combine down to
+ // a single byte.
+ if (mod <= 0x100) {
+ val = (val & 0xff) ^ (val >> 8);
+ }
+ }
+
+ return val % mod;
+}
+
+/*
+ * Random Boolean
+ *
+ * Pseudo randomly returns 0 (false) or 1 (true).
+ *
+ * Precondition: srand48() called to set the seed of
+ * the pseudo random number generator.
+ */
+int testRandBool(void)
+{
+ return (testRandMod(2));
+}
+
+/*
+ * Random Fraction
+ *
+ * Pseudo randomly return a value in the range [0.0, 1.0).
+ *
+ * Precondition: srand48() called to set the seed of
+ * the pseudo random number generator.
+ */
+double testRandFract(void)
+{
+ return drand48();
+}
+
+// Delays for the number of seconds specified by amt or a greater amount.
+// The amt variable is of type float and thus non-integer amounts
+// of time can be specified. This function automatically handles cases
+// where nanosleep(2) returns early due to reception of a signal.
+void testDelay(float amt)
+{
+ struct timespec start, current, delta;
+ struct timespec remaining;
+
+ // Get the time at which we started
+ clock_gettime(CLOCK_MONOTONIC, &start);
+
+ do {
+ // Get current time
+ clock_gettime(CLOCK_MONOTONIC, ¤t);
+
+ // How much time is left
+ delta = tsDelta(&start, ¤t);
+ if (ts2double(&delta) > amt) { break; }
+
+ // Request to sleep for the remaining time
+ remaining = double2ts(amt - ts2double(&delta));
+ (void) nanosleep(&remaining, NULL);
+ } while (true);
+}
+
+// Delay spins for the number of seconds specified by amt or a greater
+// amount. The amt variable is of type float and thus non-integer amounts
+// of time can be specified. Differs from testDelay() in that
+// testDelaySpin() performs a spin loop, instead of using nanosleep().
+void testDelaySpin(float amt)
+{
+ struct timespec start, current, delta;
+
+ // Get the time at which we started
+ clock_gettime(CLOCK_MONOTONIC, &start);
+
+ do {
+ // Get current time
+ clock_gettime(CLOCK_MONOTONIC, ¤t);
+
+ // How much time is left
+ delta = tsDelta(&start, ¤t);
+ if (ts2double(&delta) > amt) { break; }
+ } while (true);
+}
+
+/*
+ * Hex Dump
+ *
+ * Displays in hex the contents of the memory starting at the location
+ * pointed to by buf, for the number of bytes given by size.
+ * Each line of output is indented by a number of spaces that
+ * can be set by calling xDumpSetIndent(). It is also possible
+ * to offset the displayed address by an amount set by calling
+ * xDumpSetOffset.
+ */
+static uint8_t xDumpIndent;
+static uint64_t xDumpOffset;
+void
+testXDump(const void *buf, size_t size)
+{
+ const unsigned int bytesPerLine = 16;
+ int rv;
+ char line[MAXSTR];
+ const unsigned char *ptr = buf, *start = buf;
+ size_t num = size;
+ char *linep = line;
+
+ while (num) {
+ if (((ptr - start) % bytesPerLine) == 0) {
+ if (linep != line) {
+ testPrintE("%s", line);
+ }
+ linep = line;
+ rv = snprintf(linep, ALEN(line) - (linep - line),
+ "%*s%06llx:", xDumpIndent, "",
+ (long long) (ptr - start) + xDumpOffset);
+ linep += rv;
+ }
+
+ // Check that there is at least room for 4
+ // more characters. The 4 characters being
+ // a space, 2 hex digits and the terminating
+ // '\0'.
+ assert((ALEN(line) - 4) >= (linep - line));
+ rv = snprintf(linep, ALEN(line) - (linep - line),
+ " %02x", *ptr++);
+ linep += rv;
+ num--;
+ }
+ if (linep != line) {
+ testPrintE("%s", line);
+ }
+}
+
+// Set an indent of spaces for each line of hex dump output
+void
+testXDumpSetIndent(uint8_t indent)
+{
+ xDumpIndent = indent;
+}
+
+// Obtain the current hex dump indent amount
+uint8_t
+testXDumpGetIndent(void)
+{
+ return xDumpIndent;
+}
+
+// Set the hex dump address offset amount
+void
+testXDumpSetOffset(uint64_t offset)
+{
+ xDumpOffset = offset;
+}
+
+// Get the current hex dump address offset amount
+uint64_t
+testXDumpGetOffset(void)
+{
+ return xDumpOffset;
+}
+
+/*
+ * Execute Command
+ *
+ * Executes the command pointed to by cmd. Output from the
+ * executed command is captured and sent to LogCat Info. Once
+ * the command has finished execution, it's exit status is captured
+ * and checked for an exit status of zero. Any other exit status
+ * causes diagnostic information to be printed and an immediate
+ * testcase failure.
+ */
+void testExecCmd(const char *cmd)
+{
+ FILE *fp;
+ int rv;
+ int status;
+ char str[MAXSTR];
+
+ // Display command to be executed
+ testPrintI("cmd: %s", cmd);
+
+ // Execute the command
+ fflush(stdout);
+ if ((fp = popen(cmd, "r")) == NULL) {
+ testPrintE("execCmd popen failed, errno: %i", errno);
+ exit(100);
+ }
+
+ // Obtain and display each line of output from the executed command
+ while (fgets(str, sizeof(str), fp) != NULL) {
+ if ((strlen(str) > 1) && (str[strlen(str) - 1] == '\n')) {
+ str[strlen(str) - 1] = '\0';
+ }
+ testPrintI(" out: %s", str);
+ }
+
+ // Obtain and check return status of executed command.
+ // Fail on non-zero exit status
+ status = pclose(fp);
+ if (!(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) {
+ testPrintE("Unexpected command failure");
+ testPrintE(" status: %#x", status);
+ if (WIFEXITED(status)) {
+ testPrintE("WEXITSTATUS: %i", WEXITSTATUS(status));
+ }
+ if (WIFSIGNALED(status)) {
+ testPrintE("WTERMSIG: %i", WTERMSIG(status));
+ }
+ exit(101);
+ }
+}
diff --git a/tests/memtest/Android.mk b/tests/memtest/Android.mk
new file mode 100644
index 0000000..90d6d83
--- /dev/null
+++ b/tests/memtest/Android.mk
@@ -0,0 +1,26 @@
+# Copyright 2006 The Android Open Source Project
+ifneq ($(filter $(TARGET_ARCH),arm arm64),)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ memtest.cpp \
+ fptest.cpp \
+ thumb.cpp \
+ bandwidth.cpp \
+
+LOCAL_MODULE := memtest
+LOCAL_MODULE_TAGS := debug
+LOCAL_CFLAGS += \
+ -fomit-frame-pointer \
+ -Wall \
+ -Werror \
+
+LOCAL_MULTILIB := 32
+
+LOCAL_SANITIZE := never
+
+include $(BUILD_EXECUTABLE)
+endif
diff --git a/tests/memtest/bandwidth.cpp b/tests/memtest/bandwidth.cpp
new file mode 100644
index 0000000..5ff6756
--- /dev/null
+++ b/tests/memtest/bandwidth.cpp
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#include "bandwidth.h"
+
+#include <ctype.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <map>
+#include <vector>
+
+
+typedef struct {
+ const char *name;
+ bool int_type;
+} option_t;
+
+option_t bandwidth_opts[] = {
+ { "size", true },
+ { "num_warm_loops", true },
+ { "num_loops", true },
+ { "type", false },
+ { NULL, false },
+};
+
+option_t per_core_opts[] = {
+ { "size", true },
+ { "num_warm_loops", true},
+ { "num_loops", true },
+ { "type", false },
+ { NULL, false },
+};
+
+option_t multithread_opts[] = {
+ { "size", true },
+ { "num_warm_loops", true},
+ { "num_loops", true },
+ { "type", false },
+ { "num_threads", true },
+ { NULL, false },
+};
+
+typedef union {
+ int int_value;
+ const char *char_value;
+} arg_value_t;
+typedef std::map<const char*, arg_value_t> arg_t;
+
+bool processBandwidthOptions(int argc, char** argv, option_t options[],
+ arg_t *values) {
+ for (int i = 1; i < argc; i++) {
+ if (argv[i][0] == '-' && argv[i][1] == '-' && !isdigit(argv[i][2])) {
+ char *arg = &argv[i][2];
+
+ for (int j = 0; options[j].name != NULL; j++) {
+ if (strcmp(arg, options[j].name) == 0) {
+ const char *name = options[j].name;
+ if (i == argc - 1) {
+ printf("The option --%s requires an argument.\n", name);
+ return false;
+ }
+ if (options[j].int_type) {
+ (*values)[name].int_value = strtol(argv[++i], NULL, 0);
+ } else {
+ (*values)[name].char_value = argv[++i];
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+BandwidthBenchmark *createBandwidthBenchmarkObject(arg_t values) {
+ BandwidthBenchmark *bench = NULL;
+
+ const char *name = values["type"].char_value;
+ size_t size = 0;
+ if (values.count("size") > 0) {
+ size = values["size"].int_value;
+ }
+ if (strcmp(name, "copy_ldrd_strd") == 0) {
+ bench = new CopyLdrdStrdBenchmark();
+ } else if (strcmp(name, "copy_ldmia_stmia") == 0) {
+ bench = new CopyLdmiaStmiaBenchmark();
+ } else if (strcmp(name, "copy_vld1_vst1") == 0) {
+ bench = new CopyVld1Vst1Benchmark();
+ } else if (strcmp(name, "copy_vldr_vstr") == 0) {
+ bench = new CopyVldrVstrBenchmark();
+ } else if (strcmp(name, "copy_vldmia_vstmia") == 0) {
+ bench = new CopyVldmiaVstmiaBenchmark();
+ } else if (strcmp(name, "memcpy") == 0) {
+ bench = new MemcpyBenchmark();
+ } else if (strcmp(name, "write_strd") == 0) {
+ bench = new WriteStrdBenchmark();
+ } else if (strcmp(name, "write_stmia") == 0) {
+ bench = new WriteStmiaBenchmark();
+ } else if (strcmp(name, "write_vst1") == 0) {
+ bench = new WriteVst1Benchmark();
+ } else if (strcmp(name, "write_vstr") == 0) {
+ bench = new WriteVstrBenchmark();
+ } else if (strcmp(name, "write_vstmia") == 0) {
+ bench = new WriteVstmiaBenchmark();
+ } else if (strcmp(name, "memset") == 0) {
+ bench = new MemsetBenchmark();
+ } else if (strcmp(name, "read_ldrd") == 0) {
+ bench = new ReadLdrdBenchmark();
+ } else if (strcmp(name, "read_ldmia") == 0) {
+ bench = new ReadLdmiaBenchmark();
+ } else if (strcmp(name, "read_vld1") == 0) {
+ bench = new ReadVld1Benchmark();
+ } else if (strcmp(name, "read_vldr") == 0) {
+ bench = new ReadVldrBenchmark();
+ } else if (strcmp(name, "read_vldmia") == 0) {
+ bench = new ReadVldmiaBenchmark();
+ } else {
+ printf("Unknown type name %s\n", name);
+ return NULL;
+ }
+
+ if (!bench->setSize(size)) {
+ printf("Failed to allocate buffers for benchmark.\n");
+ return NULL;
+ }
+
+ if (values.count("num_warm_loops") > 0) {
+ bench->set_num_loops(values["num_warm_loops"].int_value);
+ }
+ if (values.count("num_loops") > 0) {
+ bench->set_num_loops(values["num_loops"].int_value);
+ }
+
+ return bench;
+}
+
+bool getAvailCpus(std::vector<int> *cpu_list) {
+ cpu_set_t cpuset;
+
+ CPU_ZERO(&cpuset);
+ if (sched_getaffinity(0, sizeof(cpuset), &cpuset) != 0) {
+ perror("sched_getaffinity failed.");
+ return false;
+ }
+
+ for (int i = 0; i < CPU_SETSIZE; i++) {
+ if (CPU_ISSET(i, &cpuset)) {
+ cpu_list->push_back(i);
+ }
+ }
+
+ return true;
+}
+
+typedef struct {
+ int core;
+ BandwidthBenchmark *bench;
+ double avg_mb;
+ volatile bool *run;
+} thread_arg_t;
+
+void *runBandwidthThread(void *data) {
+ thread_arg_t *arg = reinterpret_cast<thread_arg_t *>(data);
+
+ if (arg->core >= 0) {
+ cpu_set_t cpuset;
+ CPU_ZERO(&cpuset);
+ CPU_SET(arg->core, &cpuset);
+ if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {
+ perror("sched_setaffinity failed");
+ return NULL;
+ }
+ }
+
+ // Spinloop waiting for the run variable to get set to true.
+ while (!*arg->run) {
+ }
+
+ double avg_mb = 0;
+ for (int run = 1; ; run++) {
+ arg->bench->run();
+ if (!*arg->run) {
+ // Throw away the last data point since it's possible not
+ // all of the threads are running at this point.
+ break;
+ }
+ avg_mb = (avg_mb/run) * (run-1) + arg->bench->mb_per_sec()/run;
+ }
+ arg->avg_mb = avg_mb;
+
+ return NULL;
+}
+
+bool processThreadArgs(int argc, char** argv, option_t options[],
+ arg_t *values) {
+ // Use some smaller values for the number of loops.
+ (*values)["num_warm_loops"].int_value = 1000000;
+ (*values)["num_loops"].int_value = 10000000;
+
+ if (!processBandwidthOptions(argc, argv, options, values)) {
+ return false;
+ }
+ if (values->count("size") > 0 && ((*values)["size"].int_value % 64) != 0) {
+ printf("The size values must be a multiple of 64.\n");
+ return false;
+ }
+ if (values->count("type") == 0) {
+ printf("Must specify the type value.\n");
+ return false;
+ }
+
+ BandwidthBenchmark *bench = createBandwidthBenchmarkObject(*values);
+ if (!bench) {
+ return false;
+ }
+
+ if (setpriority(PRIO_PROCESS, 0, -20)) {
+ perror("Unable to raise priority of process.");
+ return false;
+ }
+
+ printf("Calculating optimum run time...\n");
+ nsecs_t t = system_time();
+ bench->run();
+ t = system_time() - t;
+ // Since this is only going to be running single threaded, assume that
+ // if the number is set to ten times this value, we should get at least
+ // a couple of samples per thread.
+ int run_time = int((t/1000000000.0)*10 + 0.5) + 5;
+
+ (*values)["run_time"].int_value = run_time;
+ (*values)["size"].int_value = bench->size();
+ (*values)["num_warm_loops"].int_value = bench->num_warm_loops();
+ (*values)["num_loops"].int_value = bench->num_loops();
+ delete bench;
+
+ return true;
+}
+
+bool runThreadedTest(thread_arg_t args[], int num_threads, int run_time) {
+ pthread_t threads[num_threads];
+ volatile bool run = false;
+
+ int rc;
+ for (int i = 0; i < num_threads; i++) {
+ args[i].run = &run;
+ rc = pthread_create(&threads[i], NULL, runBandwidthThread,
+ (void*)&args[i]);
+ if (rc != 0) {
+ printf("Failed to launch thread %d\n", i);
+ return false;
+ }
+ }
+
+ // Kick start the threads.
+ run = true;
+
+ // Let the threads run.
+ sleep(run_time);
+
+ // Stop the threads.
+ run = false;
+
+ // Wait for the threads to complete.
+ for (int i = 0; i < num_threads; i++) {
+ rc = pthread_join(threads[i], NULL);
+ if (rc != 0) {
+ printf("Thread %d failed to join.\n", i);
+ return false;
+ }
+ printf("Thread %d: bandwidth using %s %0.2f MB/s\n", i,
+ args[i].bench->getName(), args[i].avg_mb);
+ }
+
+ return true;
+}
+
+int per_core_bandwidth(int argc, char** argv) {
+ arg_t values;
+ if (!processThreadArgs(argc, argv, per_core_opts, &values)) {
+ return -1;
+ }
+
+ std::vector<int> cpu_list;
+ if (!getAvailCpus(&cpu_list)) {
+ printf("Failed to get available cpu list.\n");
+ return -1;
+ }
+
+ thread_arg_t args[cpu_list.size()];
+
+ int i = 0;
+ for (std::vector<int>::iterator it = cpu_list.begin();
+ it != cpu_list.end(); ++it, ++i) {
+ args[i].core = *it;
+ args[i].bench = createBandwidthBenchmarkObject(values);
+ if (!args[i].bench) {
+ return -1;
+ }
+ }
+
+ printf("Running on %d cores\n", cpu_list.size());
+ printf(" run_time = %ds\n", values["run_time"].int_value);
+ printf(" size = %d\n", values["size"].int_value);
+ printf(" num_warm_loops = %d\n", values["num_warm_loops"].int_value);
+ printf(" num_loops = %d\n", values["num_loops"].int_value);
+ printf("\n");
+
+ if (!runThreadedTest(args, cpu_list.size(), values["run_time"].int_value)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int multithread_bandwidth(int argc, char** argv) {
+ arg_t values;
+ if (!processThreadArgs(argc, argv, multithread_opts, &values)) {
+ return -1;
+ }
+ if (values.count("num_threads") == 0) {
+ printf("Must specify the num_threads value.\n");
+ return -1;
+ }
+ int num_threads = values["num_threads"].int_value;
+
+ thread_arg_t args[num_threads];
+
+ for (int i = 0; i < num_threads; i++) {
+ args[i].core = -1;
+ args[i].bench = createBandwidthBenchmarkObject(values);
+ if (!args[i].bench) {
+ return -1;
+ }
+ }
+
+ printf("Running %d threads\n", num_threads);
+ printf(" run_time = %ds\n", values["run_time"].int_value);
+ printf(" size = %d\n", values["size"].int_value);
+ printf(" num_warm_loops = %d\n", values["num_warm_loops"].int_value);
+ printf(" num_loops = %d\n", values["num_loops"].int_value);
+ printf("\n");
+
+ if (!runThreadedTest(args, num_threads, values["run_time"].int_value)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+bool run_bandwidth_benchmark(int argc, char** argv, const char *name,
+ std::vector<BandwidthBenchmark*> bench_objs) {
+ arg_t values;
+ values["size"].int_value = 0;
+ values["num_warm_loops"].int_value = 0;
+ values["num_loops"].int_value = 0;
+ if (!processBandwidthOptions(argc, argv, bandwidth_opts, &values)) {
+ return false;
+ }
+
+ size_t size = values["size"].int_value;
+ if ((size % 64) != 0) {
+ printf("The size value must be a multiple of 64.\n");
+ return false;
+ }
+
+ if (setpriority(PRIO_PROCESS, 0, -20)) {
+ perror("Unable to raise priority of process.");
+ return false;
+ }
+
+ bool preamble_printed = false;
+ size_t num_warm_loops = values["num_warm_loops"].int_value;
+ size_t num_loops = values["num_loops"].int_value;
+ for (std::vector<BandwidthBenchmark*>::iterator it = bench_objs.begin();
+ it != bench_objs.end(); ++it) {
+ if (!(*it)->canRun()) {
+ continue;
+ }
+ if (!(*it)->setSize(values["size"].int_value)) {
+ printf("Failed creating buffer for bandwidth test.\n");
+ return false;
+ }
+ if (num_warm_loops) {
+ (*it)->set_num_warm_loops(num_warm_loops);
+ }
+ if (num_loops) {
+ (*it)->set_num_loops(num_loops);
+ }
+ if (!preamble_printed) {
+ preamble_printed = true;
+ printf("Benchmarking %s bandwidth\n", name);
+ printf(" size = %d\n", (*it)->size());
+ printf(" num_warm_loops = %d\n", (*it)->num_warm_loops());
+ printf(" num_loops = %d\n\n", (*it)->num_loops());
+ }
+ (*it)->run();
+ printf(" %s bandwidth with %s: %0.2f MB/s\n", name, (*it)->getName(),
+ (*it)->mb_per_sec());
+ }
+
+ return true;
+}
+
+int copy_bandwidth(int argc, char** argv) {
+ std::vector<BandwidthBenchmark*> bench_objs;
+ bench_objs.push_back(new CopyLdrdStrdBenchmark());
+ bench_objs.push_back(new CopyLdmiaStmiaBenchmark());
+ bench_objs.push_back(new CopyVld1Vst1Benchmark());
+ bench_objs.push_back(new CopyVldrVstrBenchmark());
+ bench_objs.push_back(new CopyVldmiaVstmiaBenchmark());
+ bench_objs.push_back(new MemcpyBenchmark());
+
+ if (!run_bandwidth_benchmark(argc, argv, "copy", bench_objs)) {
+ return -1;
+ }
+ return 0;
+}
+
+int write_bandwidth(int argc, char** argv) {
+ std::vector<BandwidthBenchmark*> bench_objs;
+ bench_objs.push_back(new WriteStrdBenchmark());
+ bench_objs.push_back(new WriteStmiaBenchmark());
+ bench_objs.push_back(new WriteVst1Benchmark());
+ bench_objs.push_back(new WriteVstrBenchmark());
+ bench_objs.push_back(new WriteVstmiaBenchmark());
+ bench_objs.push_back(new MemsetBenchmark());
+
+ if (!run_bandwidth_benchmark(argc, argv, "write", bench_objs)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int read_bandwidth(int argc, char** argv) {
+ std::vector<BandwidthBenchmark*> bench_objs;
+ bench_objs.push_back(new ReadLdrdBenchmark());
+ bench_objs.push_back(new ReadLdmiaBenchmark());
+ bench_objs.push_back(new ReadVld1Benchmark());
+ bench_objs.push_back(new ReadVldrBenchmark());
+ bench_objs.push_back(new ReadVldmiaBenchmark());
+
+ if (!run_bandwidth_benchmark(argc, argv, "read", bench_objs)) {
+ return -1;
+ }
+ return 0;
+}
diff --git a/tests/memtest/bandwidth.h b/tests/memtest/bandwidth.h
new file mode 100644
index 0000000..b43349c
--- /dev/null
+++ b/tests/memtest/bandwidth.h
@@ -0,0 +1,940 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef __BANDWIDTH_H__
+#define __BANDWIDTH_H__
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils/Compat.h"
+#include "memtest.h"
+
+// Bandwidth Class definitions.
+class BandwidthBenchmark {
+public:
+ BandwidthBenchmark()
+ : _size(0),
+ _num_warm_loops(DEFAULT_NUM_WARM_LOOPS),
+ _num_loops(DEFAULT_NUM_LOOPS) {}
+ virtual ~BandwidthBenchmark() {}
+
+ bool run() {
+ if (_size == 0) {
+ return false;
+ }
+ if (!canRun()) {
+ return false;
+ }
+
+ bench(_num_warm_loops);
+
+ nsecs_t t = system_time();
+ bench(_num_loops);
+ t = system_time() - t;
+
+ _mb_per_sec = (_size*(_num_loops/_BYTES_PER_MB))/(t/_NUM_NS_PER_SEC);
+
+ return true;
+ }
+
+ bool canRun() { return !usesNeon() || isNeonSupported(); }
+
+ virtual bool setSize(size_t size) = 0;
+
+ virtual const char *getName() = 0;
+
+ virtual bool verify() = 0;
+
+ virtual bool usesNeon() { return false; }
+
+ bool isNeonSupported() {
+#if defined(__ARM_NEON__)
+ return true;
+#else
+ return false;
+#endif
+ }
+
+ // Accessors/mutators.
+ double mb_per_sec() { return _mb_per_sec; }
+ size_t num_warm_loops() { return _num_warm_loops; }
+ size_t num_loops() { return _num_loops; }
+ size_t size() { return _size; }
+
+ void set_num_warm_loops(size_t num_warm_loops) {
+ _num_warm_loops = num_warm_loops;
+ }
+ void set_num_loops(size_t num_loops) { _num_loops = num_loops; }
+
+ // Static constants
+ static const unsigned int DEFAULT_NUM_WARM_LOOPS = 1000000;
+ static const unsigned int DEFAULT_NUM_LOOPS = 20000000;
+
+protected:
+ virtual void bench(size_t num_loops) = 0;
+
+ double _mb_per_sec;
+ size_t _size;
+ size_t _num_warm_loops;
+ size_t _num_loops;
+
+private:
+ // Static constants
+ static const CONSTEXPR double _NUM_NS_PER_SEC = 1000000000.0;
+ static const CONSTEXPR double _BYTES_PER_MB = 1024.0* 1024.0;
+};
+
+class CopyBandwidthBenchmark : public BandwidthBenchmark {
+public:
+ CopyBandwidthBenchmark() : BandwidthBenchmark(), _src(NULL), _dst(NULL) { }
+
+ bool setSize(size_t size) {
+ if (_src) {
+ free(_src);
+ }
+ if (_dst) {
+ free(_dst);
+ }
+
+ if (size == 0) {
+ _size = DEFAULT_COPY_SIZE;
+ } else {
+ _size = size;
+ }
+
+ _src = reinterpret_cast<char*>(memalign(64, _size));
+ if (!_src) {
+ perror("Failed to allocate memory for test.");
+ return false;
+ }
+ _dst = reinterpret_cast<char*>(memalign(64, _size));
+ if (!_dst) {
+ perror("Failed to allocate memory for test.");
+ return false;
+ }
+
+ return true;
+ }
+ virtual ~CopyBandwidthBenchmark() {
+ if (_src) {
+ free(_src);
+ _src = NULL;
+ }
+ if (_dst) {
+ free(_dst);
+ _dst = NULL;
+ }
+ }
+
+ bool verify() {
+ memset(_src, 0x23, _size);
+ memset(_dst, 0, _size);
+ bench(1);
+ if (memcmp(_src, _dst, _size) != 0) {
+ printf("Buffers failed to compare after one loop.\n");
+ return false;
+ }
+
+ memset(_src, 0x23, _size);
+ memset(_dst, 0, _size);
+ _num_loops = 2;
+ bench(2);
+ if (memcmp(_src, _dst, _size) != 0) {
+ printf("Buffers failed to compare after two loops.\n");
+ return false;
+ }
+
+ return true;
+ }
+
+protected:
+ char *_src;
+ char *_dst;
+
+ static const unsigned int DEFAULT_COPY_SIZE = 8000;
+};
+
+class CopyLdrdStrdBenchmark : public CopyBandwidthBenchmark {
+public:
+ CopyLdrdStrdBenchmark() : CopyBandwidthBenchmark() { }
+ virtual ~CopyLdrdStrdBenchmark() {}
+
+ const char *getName() { return "ldrd/strd"; }
+
+protected:
+ // Copy using ldrd/strd instructions.
+ void bench(size_t num_loops) {
+ asm volatile(
+ "stmfd sp!, {r0,r1,r2,r3,r4,r6,r7}\n"
+
+ "mov r0, %0\n"
+ "mov r1, %1\n"
+ "mov r2, %2\n"
+ "mov r3, %3\n"
+
+ "0:\n"
+ "mov r4, r2, lsr #6\n"
+
+ "1:\n"
+ "ldrd r6, r7, [r0]\n"
+ "strd r6, r7, [r1]\n"
+ "ldrd r6, r7, [r0, #8]\n"
+ "strd r6, r7, [r1, #8]\n"
+ "ldrd r6, r7, [r0, #16]\n"
+ "strd r6, r7, [r1, #16]\n"
+ "ldrd r6, r7, [r0, #24]\n"
+ "strd r6, r7, [r1, #24]\n"
+ "ldrd r6, r7, [r0, #32]\n"
+ "strd r6, r7, [r1, #32]\n"
+ "ldrd r6, r7, [r0, #40]\n"
+ "strd r6, r7, [r1, #40]\n"
+ "ldrd r6, r7, [r0, #48]\n"
+ "strd r6, r7, [r1, #48]\n"
+ "ldrd r6, r7, [r0, #56]\n"
+ "strd r6, r7, [r1, #56]\n"
+
+ "add r0, r0, #64\n"
+ "add r1, r1, #64\n"
+ "subs r4, r4, #1\n"
+ "bgt 1b\n"
+
+ "sub r0, r0, r2\n"
+ "sub r1, r1, r2\n"
+ "subs r3, r3, #1\n"
+ "bgt 0b\n"
+
+ "ldmfd sp!, {r0,r1,r2,r3,r4,r6,r7}\n"
+ :: "r" (_src), "r" (_dst), "r" (_size), "r" (num_loops) : "r0", "r1", "r2", "r3");
+ }
+};
+
+class CopyLdmiaStmiaBenchmark : public CopyBandwidthBenchmark {
+public:
+ CopyLdmiaStmiaBenchmark() : CopyBandwidthBenchmark() { }
+ virtual ~CopyLdmiaStmiaBenchmark() {}
+
+ const char *getName() { return "ldmia/stmia"; }
+
+protected:
+ // Copy using ldmia/stmia instructions.
+ void bench(size_t num_loops) {
+ asm volatile(
+ "stmfd sp!, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12}\n"
+
+ "mov r0, %0\n"
+ "mov r1, %1\n"
+ "mov r2, %2\n"
+ "mov r3, %3\n"
+
+ "0:\n"
+ "mov r4, r2, lsr #6\n"
+
+ "1:\n"
+ "ldmia r0!, {r5, r6, r7, r8, r9, r10, r11, r12}\n"
+ "stmia r1!, {r5, r6, r7, r8, r9, r10, r11, r12}\n"
+ "subs r4, r4, #1\n"
+ "ldmia r0!, {r5, r6, r7, r8, r9, r10, r11, r12}\n"
+ "stmia r1!, {r5, r6, r7, r8, r9, r10, r11, r12}\n"
+ "bgt 1b\n"
+
+ "sub r0, r0, r2\n"
+ "sub r1, r1, r2\n"
+ "subs r3, r3, #1\n"
+ "bgt 0b\n"
+
+ "ldmfd sp!, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12}\n"
+ :: "r" (_src), "r" (_dst), "r" (_size), "r" (num_loops) : "r0", "r1", "r2", "r3");
+ }
+};
+
+class CopyVld1Vst1Benchmark : public CopyBandwidthBenchmark {
+public:
+ CopyVld1Vst1Benchmark() : CopyBandwidthBenchmark() { }
+ virtual ~CopyVld1Vst1Benchmark() {}
+
+ const char *getName() { return "vld1/vst1"; }
+
+ bool usesNeon() { return true; }
+
+protected:
+ // Copy using vld1/vst1 instructions.
+#if defined(__ARM_NEON__)
+ void bench(size_t num_loops) {
+ asm volatile(
+ "stmfd sp!, {r0,r1,r2,r3,r4}\n"
+
+ "mov r0, %0\n"
+ "mov r1, %1\n"
+ "mov r2, %2\n"
+ "mov r3, %3\n"
+
+ "0:\n"
+ "mov r4, r2, lsr #6\n"
+
+ "1:\n"
+ "vld1.8 {d0-d3}, [r0]!\n"
+ "vld1.8 {d4-d7}, [r0]!\n"
+ "subs r4, r4, #1\n"
+ "vst1.8 {d0-d3}, [r1:128]!\n"
+ "vst1.8 {d4-d7}, [r1:128]!\n"
+ "bgt 1b\n"
+
+ "sub r0, r0, r2\n"
+ "sub r1, r1, r2\n"
+ "subs r3, r3, #1\n"
+ "bgt 0b\n"
+
+ "ldmfd sp!, {r0,r1,r2,r3,r4}\n"
+ :: "r" (_src), "r" (_dst), "r" (_size), "r" (num_loops) : "r0", "r1", "r2", "r3");
+#else
+ void bench(size_t) {
+#endif
+ }
+};
+
+class CopyVldrVstrBenchmark : public CopyBandwidthBenchmark {
+public:
+ CopyVldrVstrBenchmark() : CopyBandwidthBenchmark() { }
+ virtual ~CopyVldrVstrBenchmark() {}
+
+ const char *getName() { return "vldr/vstr"; }
+
+ bool usesNeon() { return true; }
+
+protected:
+ // Copy using vldr/vstr instructions.
+#if defined(__ARM_NEON__)
+ void bench(size_t num_loops) {
+ asm volatile(
+ "stmfd sp!, {r0,r1,r2,r3,r4}\n"
+
+ "mov r0, %0\n"
+ "mov r1, %1\n"
+ "mov r2, %2\n"
+ "mov r3, %3\n"
+
+ "0:\n"
+ "mov r4, r2, lsr #6\n"
+
+ "1:\n"
+ "vldr d0, [r0, #0]\n"
+ "subs r4, r4, #1\n"
+ "vldr d1, [r0, #8]\n"
+ "vstr d0, [r1, #0]\n"
+ "vldr d0, [r0, #16]\n"
+ "vstr d1, [r1, #8]\n"
+ "vldr d1, [r0, #24]\n"
+ "vstr d0, [r1, #16]\n"
+ "vldr d0, [r0, #32]\n"
+ "vstr d1, [r1, #24]\n"
+ "vldr d1, [r0, #40]\n"
+ "vstr d0, [r1, #32]\n"
+ "vldr d0, [r0, #48]\n"
+ "vstr d1, [r1, #40]\n"
+ "vldr d1, [r0, #56]\n"
+ "vstr d0, [r1, #48]\n"
+ "add r0, r0, #64\n"
+ "vstr d1, [r1, #56]\n"
+ "add r1, r1, #64\n"
+ "bgt 1b\n"
+
+ "sub r0, r0, r2\n"
+ "sub r1, r1, r2\n"
+ "subs r3, r3, #1\n"
+ "bgt 0b\n"
+
+ "ldmfd sp!, {r0,r1,r2,r3,r4}\n"
+ :: "r" (_src), "r" (_dst), "r" (_size), "r" (num_loops) : "r0", "r1", "r2", "r3");
+#else
+ void bench(size_t) {
+#endif
+ }
+};
+
+class CopyVldmiaVstmiaBenchmark : public CopyBandwidthBenchmark {
+public:
+ CopyVldmiaVstmiaBenchmark() : CopyBandwidthBenchmark() { }
+ virtual ~CopyVldmiaVstmiaBenchmark() {}
+
+ const char *getName() { return "vldmia/vstmia"; }
+
+ bool usesNeon() { return true; }
+
+protected:
+ // Copy using vldmia/vstmia instructions.
+#if defined(__ARM_NEON__)
+ void bench(size_t num_loops) {
+ asm volatile(
+ "stmfd sp!, {r0,r1,r2,r3,r4}\n"
+
+ "mov r0, %0\n"
+ "mov r1, %1\n"
+ "mov r2, %2\n"
+ "mov r3, %3\n"
+
+ "0:\n"
+ "mov r4, r2, lsr #6\n"
+
+ "1:\n"
+ "vldmia r0!, {d0-d7}\n"
+ "subs r4, r4, #1\n"
+ "vstmia r1!, {d0-d7}\n"
+ "bgt 1b\n"
+
+ "sub r0, r0, r2\n"
+ "sub r1, r1, r2\n"
+ "subs r3, r3, #1\n"
+ "bgt 0b\n"
+
+ "ldmfd sp!, {r0,r1,r2,r3,r4}\n"
+ :: "r" (_src), "r" (_dst), "r" (_size), "r" (num_loops) : "r0", "r1", "r2", "r3");
+#else
+ void bench(size_t) {
+#endif
+ }
+};
+
+class MemcpyBenchmark : public CopyBandwidthBenchmark {
+public:
+ MemcpyBenchmark() : CopyBandwidthBenchmark() { }
+ virtual ~MemcpyBenchmark() {}
+
+ const char *getName() { return "memcpy"; }
+
+protected:
+ void bench(size_t num_loops) {
+ for (size_t i = 0; i < num_loops; i++) {
+ memcpy(_dst, _src, _size);
+ }
+ }
+};
+
+class SingleBufferBandwidthBenchmark : public BandwidthBenchmark {
+public:
+ SingleBufferBandwidthBenchmark() : BandwidthBenchmark(), _buffer(NULL) { }
+ virtual ~SingleBufferBandwidthBenchmark() {
+ if (_buffer) {
+ free(_buffer);
+ _buffer = NULL;
+ }
+ }
+
+ bool setSize(size_t size) {
+ if (_buffer) {
+ free(_buffer);
+ _buffer = NULL;
+ }
+
+ if (size == 0) {
+ _size = DEFAULT_SINGLE_BUFFER_SIZE;
+ } else {
+ _size = size;
+ }
+
+ _buffer = reinterpret_cast<char*>(memalign(64, _size));
+ if (!_buffer) {
+ perror("Failed to allocate memory for test.");
+ return false;
+ }
+ memset(_buffer, 0, _size);
+
+ return true;
+ }
+
+ bool verify() { return true; }
+
+protected:
+ char *_buffer;
+
+ static const unsigned int DEFAULT_SINGLE_BUFFER_SIZE = 16000;
+};
+
+class WriteBandwidthBenchmark : public SingleBufferBandwidthBenchmark {
+public:
+ WriteBandwidthBenchmark() : SingleBufferBandwidthBenchmark() { }
+ virtual ~WriteBandwidthBenchmark() { }
+
+ bool verify() {
+ memset(_buffer, 0, _size);
+ bench(1);
+ for (size_t i = 0; i < _size; i++) {
+ if (_buffer[i] != 1) {
+ printf("Buffer failed to compare after one loop.\n");
+ return false;
+ }
+ }
+
+ memset(_buffer, 0, _size);
+ bench(2);
+ for (size_t i = 0; i < _size; i++) {
+ if (_buffer[i] != 2) {
+ printf("Buffer failed to compare after two loops.\n");
+ return false;
+ }
+ }
+
+ return true;
+ }
+};
+
+class WriteStrdBenchmark : public WriteBandwidthBenchmark {
+public:
+ WriteStrdBenchmark() : WriteBandwidthBenchmark() { }
+ virtual ~WriteStrdBenchmark() {}
+
+ const char *getName() { return "strd"; }
+
+protected:
+ // Write a given value using strd.
+ void bench(size_t num_loops) {
+ asm volatile(
+ "stmfd sp!, {r0,r1,r2,r3,r4,r5}\n"
+
+ "mov r0, %0\n"
+ "mov r1, %1\n"
+ "mov r2, %2\n"
+
+ "mov r4, #0\n"
+ "mov r5, #0\n"
+
+ "0:\n"
+ "mov r3, r1, lsr #5\n"
+
+ "add r4, r4, #0x01010101\n"
+ "mov r5, r4\n"
+
+ "1:\n"
+ "subs r3, r3, #1\n"
+ "strd r4, r5, [r0]\n"
+ "strd r4, r5, [r0, #8]\n"
+ "strd r4, r5, [r0, #16]\n"
+ "strd r4, r5, [r0, #24]\n"
+ "add r0, r0, #32\n"
+ "bgt 1b\n"
+
+ "sub r0, r0, r1\n"
+ "subs r2, r2, #1\n"
+ "bgt 0b\n"
+
+ "ldmfd sp!, {r0,r1,r2,r3,r4,r5}\n"
+ :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+ }
+};
+
+class WriteStmiaBenchmark : public WriteBandwidthBenchmark {
+public:
+ WriteStmiaBenchmark() : WriteBandwidthBenchmark() { }
+ virtual ~WriteStmiaBenchmark() {}
+
+ const char *getName() { return "stmia"; }
+
+protected:
+ // Write a given value using stmia.
+ void bench(size_t num_loops) {
+ asm volatile(
+ "stmfd sp!, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11}\n"
+
+ "mov r0, %0\n"
+ "mov r1, %1\n"
+ "mov r2, %2\n"
+
+ "mov r4, #0\n"
+
+ "0:\n"
+ "mov r3, r1, lsr #5\n"
+
+ "add r4, r4, #0x01010101\n"
+ "mov r5, r4\n"
+ "mov r6, r4\n"
+ "mov r7, r4\n"
+ "mov r8, r4\n"
+ "mov r9, r4\n"
+ "mov r10, r4\n"
+ "mov r11, r4\n"
+
+ "1:\n"
+ "subs r3, r3, #1\n"
+ "stmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11}\n"
+ "bgt 1b\n"
+
+ "sub r0, r0, r1\n"
+ "subs r2, r2, #1\n"
+ "bgt 0b\n"
+
+ "ldmfd sp!, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11}\n"
+ :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+ }
+};
+
+class WriteVst1Benchmark : public WriteBandwidthBenchmark {
+public:
+ WriteVst1Benchmark() : WriteBandwidthBenchmark() { }
+ virtual ~WriteVst1Benchmark() {}
+
+ const char *getName() { return "vst1"; }
+
+ bool usesNeon() { return true; }
+
+protected:
+ // Write a given value using vst.
+#if defined(__ARM_NEON__)
+ void bench(size_t num_loops) {
+ asm volatile(
+ "stmfd sp!, {r0,r1,r2,r3,r4}\n"
+
+ "mov r0, %0\n"
+ "mov r1, %1\n"
+ "mov r2, %2\n"
+ "mov r4, #0\n"
+
+ "0:\n"
+ "mov r3, r1, lsr #5\n"
+
+ "add r4, r4, #1\n"
+ "vdup.8 d0, r4\n"
+ "vmov d1, d0\n"
+ "vmov d2, d0\n"
+ "vmov d3, d0\n"
+
+ "1:\n"
+ "subs r3, r3, #1\n"
+ "vst1.8 {d0-d3}, [r0:128]!\n"
+ "bgt 1b\n"
+
+ "sub r0, r0, r1\n"
+ "subs r2, r2, #1\n"
+ "bgt 0b\n"
+
+ "ldmfd sp!, {r0,r1,r2,r3,r4}\n"
+ :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+#else
+ void bench(size_t) {
+#endif
+ }
+};
+
+class WriteVstrBenchmark : public WriteBandwidthBenchmark {
+public:
+ WriteVstrBenchmark() : WriteBandwidthBenchmark() { }
+ virtual ~WriteVstrBenchmark() {}
+
+ const char *getName() { return "vstr"; }
+
+ bool usesNeon() { return true; }
+
+protected:
+ // Write a given value using vst.
+#if defined(__ARM_NEON__)
+ void bench(size_t num_loops) {
+ asm volatile(
+ "stmfd sp!, {r0,r1,r2,r3,r4}\n"
+
+ "mov r0, %0\n"
+ "mov r1, %1\n"
+ "mov r2, %2\n"
+ "mov r4, #0\n"
+
+ "0:\n"
+ "mov r3, r1, lsr #5\n"
+
+ "add r4, r4, #1\n"
+ "vdup.8 d0, r4\n"
+ "vmov d1, d0\n"
+ "vmov d2, d0\n"
+ "vmov d3, d0\n"
+
+ "1:\n"
+ "vstr d0, [r0, #0]\n"
+ "subs r3, r3, #1\n"
+ "vstr d1, [r0, #8]\n"
+ "vstr d0, [r0, #16]\n"
+ "vstr d1, [r0, #24]\n"
+ "add r0, r0, #32\n"
+ "bgt 1b\n"
+
+ "sub r0, r0, r1\n"
+ "subs r2, r2, #1\n"
+ "bgt 0b\n"
+
+ "ldmfd sp!, {r0,r1,r2,r3,r4}\n"
+ :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+#else
+ void bench(size_t) {
+#endif
+ }
+};
+
+class WriteVstmiaBenchmark : public WriteBandwidthBenchmark {
+public:
+ WriteVstmiaBenchmark() : WriteBandwidthBenchmark() { }
+ virtual ~WriteVstmiaBenchmark() {}
+
+ const char *getName() { return "vstmia"; }
+
+ bool usesNeon() { return true; }
+
+protected:
+ // Write a given value using vstmia.
+#if defined(__ARM_NEON__)
+ void bench(size_t num_loops) {
+ asm volatile(
+ "stmfd sp!, {r0,r1,r2,r3,r4}\n"
+
+ "mov r0, %0\n"
+ "mov r1, %1\n"
+ "mov r2, %2\n"
+ "mov r4, #0\n"
+
+ "0:\n"
+ "mov r3, r1, lsr #5\n"
+
+ "add r4, r4, #1\n"
+ "vdup.8 d0, r4\n"
+ "vmov d1, d0\n"
+ "vmov d2, d0\n"
+ "vmov d3, d0\n"
+
+ "1:\n"
+ "subs r3, r3, #1\n"
+ "vstmia r0!, {d0-d3}\n"
+ "bgt 1b\n"
+
+ "sub r0, r0, r1\n"
+ "subs r2, r2, #1\n"
+ "bgt 0b\n"
+
+ "ldmfd sp!, {r0,r1,r2,r3,r4}\n"
+ :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+#else
+ void bench(size_t) {
+#endif
+ }
+};
+
+class MemsetBenchmark : public WriteBandwidthBenchmark {
+public:
+ MemsetBenchmark() : WriteBandwidthBenchmark() { }
+ virtual ~MemsetBenchmark() {}
+
+ const char *getName() { return "memset"; }
+
+protected:
+ void bench(size_t num_loops) {
+ for (size_t i = 0; i < num_loops; i++) {
+ memset(_buffer, (i % 255) + 1, _size);
+ }
+ }
+};
+
+class ReadLdrdBenchmark : public SingleBufferBandwidthBenchmark {
+public:
+ ReadLdrdBenchmark() : SingleBufferBandwidthBenchmark() { }
+ virtual ~ReadLdrdBenchmark() {}
+
+ const char *getName() { return "ldrd"; }
+
+protected:
+ // Write a given value using strd.
+ void bench(size_t num_loops) {
+ asm volatile(
+ "stmfd sp!, {r0,r1,r2,r3,r4,r5}\n"
+
+ "mov r0, %0\n"
+ "mov r1, %1\n"
+ "mov r2, %2\n"
+
+ "0:\n"
+ "mov r3, r1, lsr #5\n"
+
+ "1:\n"
+ "subs r3, r3, #1\n"
+ "ldrd r4, r5, [r0]\n"
+ "ldrd r4, r5, [r0, #8]\n"
+ "ldrd r4, r5, [r0, #16]\n"
+ "ldrd r4, r5, [r0, #24]\n"
+ "add r0, r0, #32\n"
+ "bgt 1b\n"
+
+ "sub r0, r0, r1\n"
+ "subs r2, r2, #1\n"
+ "bgt 0b\n"
+
+ "ldmfd sp!, {r0,r1,r2,r3,r4,r5}\n"
+ :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+ }
+};
+
+class ReadLdmiaBenchmark : public SingleBufferBandwidthBenchmark {
+public:
+ ReadLdmiaBenchmark() : SingleBufferBandwidthBenchmark() { }
+ virtual ~ReadLdmiaBenchmark() {}
+
+ const char *getName() { return "ldmia"; }
+
+protected:
+ // Write a given value using stmia.
+ void bench(size_t num_loops) {
+ asm volatile(
+ "stmfd sp!, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11}\n"
+
+ "mov r0, %0\n"
+ "mov r1, %1\n"
+ "mov r2, %2\n"
+
+ "0:\n"
+ "mov r3, r1, lsr #5\n"
+
+ "1:\n"
+ "subs r3, r3, #1\n"
+ "ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11}\n"
+ "bgt 1b\n"
+
+ "sub r0, r0, r1\n"
+ "subs r2, r2, #1\n"
+ "bgt 0b\n"
+
+ "ldmfd sp!, {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11}\n"
+ :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+ }
+};
+
+class ReadVld1Benchmark : public SingleBufferBandwidthBenchmark {
+public:
+ ReadVld1Benchmark() : SingleBufferBandwidthBenchmark() { }
+ virtual ~ReadVld1Benchmark() {}
+
+ const char *getName() { return "vld1"; }
+
+ bool usesNeon() { return true; }
+
+protected:
+ // Write a given value using vst.
+#if defined(__ARM_NEON__)
+ void bench(size_t num_loops) {
+ asm volatile(
+ "stmfd sp!, {r0,r1,r2,r3}\n"
+
+ "mov r0, %0\n"
+ "mov r1, %1\n"
+ "mov r2, %2\n"
+
+ "0:\n"
+ "mov r3, r1, lsr #5\n"
+
+ "1:\n"
+ "subs r3, r3, #1\n"
+ "vld1.8 {d0-d3}, [r0:128]!\n"
+ "bgt 1b\n"
+
+ "sub r0, r0, r1\n"
+ "subs r2, r2, #1\n"
+ "bgt 0b\n"
+
+ "ldmfd sp!, {r0,r1,r2,r3}\n"
+ :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+#else
+ void bench(size_t) {
+#endif
+ }
+};
+
+class ReadVldrBenchmark : public SingleBufferBandwidthBenchmark {
+public:
+ ReadVldrBenchmark() : SingleBufferBandwidthBenchmark() { }
+ virtual ~ReadVldrBenchmark() {}
+
+ const char *getName() { return "vldr"; }
+
+ bool usesNeon() { return true; }
+
+protected:
+ // Write a given value using vst.
+#if defined(__ARM_NEON__)
+ void bench(size_t num_loops) {
+ asm volatile(
+ "stmfd sp!, {r0,r1,r2,r3}\n"
+
+ "mov r0, %0\n"
+ "mov r1, %1\n"
+ "mov r2, %2\n"
+
+ "0:\n"
+ "mov r3, r1, lsr #5\n"
+
+ "1:\n"
+ "vldr d0, [r0, #0]\n"
+ "subs r3, r3, #1\n"
+ "vldr d1, [r0, #8]\n"
+ "vldr d0, [r0, #16]\n"
+ "vldr d1, [r0, #24]\n"
+ "add r0, r0, #32\n"
+ "bgt 1b\n"
+
+ "sub r0, r0, r1\n"
+ "subs r2, r2, #1\n"
+ "bgt 0b\n"
+
+ "ldmfd sp!, {r0,r1,r2,r3}\n"
+ :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+#else
+ void bench(size_t) {
+#endif
+ }
+};
+
+
+class ReadVldmiaBenchmark : public SingleBufferBandwidthBenchmark {
+public:
+ ReadVldmiaBenchmark() : SingleBufferBandwidthBenchmark() { }
+ virtual ~ReadVldmiaBenchmark() {}
+
+ const char *getName() { return "vldmia"; }
+
+ bool usesNeon() { return true; }
+
+protected:
+ // Write a given value using vstmia.
+#if defined(__ARM_NEON__)
+ void bench(size_t num_loops) {
+ asm volatile(
+ "stmfd sp!, {r0,r1,r2,r3}\n"
+
+ "mov r0, %0\n"
+ "mov r1, %1\n"
+ "mov r2, %2\n"
+
+ "0:\n"
+ "mov r3, r1, lsr #5\n"
+
+ "1:\n"
+ "subs r3, r3, #1\n"
+ "vldmia r0!, {d0-d3}\n"
+ "bgt 1b\n"
+
+ "sub r0, r0, r1\n"
+ "subs r2, r2, #1\n"
+ "bgt 0b\n"
+
+ "ldmfd sp!, {r0,r1,r2,r3}\n"
+ :: "r" (_buffer), "r" (_size), "r" (num_loops) : "r0", "r1", "r2");
+#else
+ void bench(size_t) {
+#endif
+ }
+};
+
+#endif // __BANDWIDTH_H__
diff --git a/tests/memtest/fptest.cpp b/tests/memtest/fptest.cpp
new file mode 100644
index 0000000..1ae04b2
--- /dev/null
+++ b/tests/memtest/fptest.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#ifdef __ARM_NEON__
+#include <arm_neon.h>
+#endif
+
+
+typedef long long nsecs_t;
+static nsecs_t gTime;
+float data_f[1024 * 128];
+
+static nsecs_t system_time()
+{
+ struct timespec t;
+ t.tv_sec = t.tv_nsec = 0;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+}
+
+static void startTime()
+{
+ gTime = system_time();
+}
+
+static void endTime(const char *str, double ops)
+{
+ nsecs_t t = system_time() - gTime;
+ double ds = ((double)t) / 1e9;
+ printf("Test: %s, %f Mops\n", str, ops / ds / 1e6);
+}
+
+
+static void test_mad() {
+ for(int i=0; i<1020; i++) {
+ data_f[i] = i;
+ }
+
+ startTime();
+
+ // Do ~1 billion ops
+ for (int ct=0; ct < (1000 * (1000 / 20)); ct++) {
+ for (int i=0; i < 1000; i++) {
+ data_f[i] = (data_f[i] * 0.02f +
+ data_f[i+1] * 0.04f +
+ data_f[i+2] * 0.05f +
+ data_f[i+3] * 0.1f +
+ data_f[i+4] * 0.2f +
+ data_f[i+5] * 0.2f +
+ data_f[i+6] * 0.1f +
+ data_f[i+7] * 0.05f +
+ data_f[i+8] * 0.04f +
+ data_f[i+9] * 0.02f + 1.f);
+ }
+ }
+
+ endTime("scalar mad", 1e9);
+}
+
+
+#ifdef __ARM_NEON__
+
+static void test_fma() {
+ for(int i=0; i<1020 * 4; i++) {
+ data_f[i] = i;
+ }
+ float32x4_t c0_02 = vdupq_n_f32(0.02f);
+ float32x4_t c0_04 = vdupq_n_f32(0.04f);
+ float32x4_t c0_05 = vdupq_n_f32(0.05f);
+ float32x4_t c0_10 = vdupq_n_f32(0.1f);
+ float32x4_t c0_20 = vdupq_n_f32(0.2f);
+ float32x4_t c1_00 = vdupq_n_f32(1.0f);
+
+ startTime();
+
+ // Do ~1 billion ops
+ for (int ct=0; ct < (1000 * (1000 / 80)); ct++) {
+ for (int i=0; i < 1000; i++) {
+ float32x4_t t;
+ t = vmulq_f32(vld1q_f32((float32_t *)&data_f[i]), c0_02);
+ t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+4]), c0_04);
+ t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+8]), c0_05);
+ t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+12]), c0_10);
+ t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+16]), c0_20);
+ t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+20]), c0_20);
+ t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+24]), c0_10);
+ t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+28]), c0_05);
+ t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+32]), c0_04);
+ t = vmlaq_f32(t, vld1q_f32((float32_t *)&data_f[i+36]), c0_02);
+ t = vaddq_f32(t, c1_00);
+ vst1q_f32((float32_t *)&data_f[i], t);
+ }
+ }
+
+ endTime("neon fma", 1e9);
+}
+#endif
+
+int fp_test(int, char**) {
+ test_mad();
+
+#ifdef __ARM_NEON__
+ test_fma();
+#endif
+
+ return 0;
+}
diff --git a/tests/memtest/memtest.cpp b/tests/memtest/memtest.cpp
new file mode 100644
index 0000000..bad9209
--- /dev/null
+++ b/tests/memtest/memtest.cpp
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include "memtest.h"
+
+nsecs_t system_time() {
+ struct timespec t;
+ t.tv_sec = t.tv_nsec = 0;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+}
+
+static void usage(char* p) {
+ printf("Usage: %s <test> <options>\n"
+ "<test> is one of the following:\n"
+ " copy_bandwidth [--size BYTES_TO_COPY]\n"
+ " write_bandwidth [--size BYTES_TO_WRITE]\n"
+ " read_bandwidth [--size BYTES_TO_COPY]\n"
+ " per_core_bandwidth [--size BYTES]\n"
+ " --type copy_ldrd_strd | copy_ldmia_stmia | copy_vld1_vst1 |\n"
+ " copy_vldr_vstr | copy_vldmia_vstmia | memcpy | write_strd |\n"
+ " write_stmia | write_vst1 | write_vstr | write_vstmia | memset |\n"
+ " read_ldrd | read_ldmia | read_vld1 | read_vldr | read_vldmia\n"
+ " multithread_bandwidth [--size BYTES]\n"
+ " --type copy_ldrd_strd | copy_ldmia_stmia | copy_vld1_vst1 |\n"
+ " copy_vldr_vstr | copy_vldmia_vstmia | memcpy | write_strd |\n"
+ " write_stmia | write_vst1 | write_vstr | write_vstmia | memset |\n"
+ " read_ldrd | read_ldmia | read_vld1 | read_vldr | read_vldmia\n"
+ " --num_threads NUM_THREADS_TO_RUN\n"
+ " malloc [fill]\n"
+ " madvise\n"
+ " resampler\n"
+ " stack (stack smasher)\n"
+ " crawl\n"
+ , p);
+}
+
+int copy_bandwidth(int argc, char** argv);
+int write_bandwidth(int argc, char** argv);
+int read_bandwidth(int argc, char** argv);
+int per_core_bandwidth(int argc, char** argv);
+int multithread_bandwidth(int argc, char** argv);
+int malloc_test(int argc, char** argv);
+int madvise_test(int argc, char** argv);
+int stack_smasher_test(int argc, char** argv);
+int crawl_test(int argc, char** argv);
+int fp_test(int argc, char** argv);
+
+typedef struct {
+ const char *cmd_name;
+ int (*func)(int argc, char** argv);
+} function_t;
+
+function_t function_table[] = {
+ { "malloc", malloc_test },
+ { "madvise", madvise_test },
+ { "stack", stack_smasher_test },
+ { "crawl", crawl_test },
+ { "fp", fp_test },
+ { "copy_bandwidth", copy_bandwidth },
+ { "write_bandwidth", write_bandwidth },
+ { "read_bandwidth", read_bandwidth },
+ { "per_core_bandwidth", per_core_bandwidth },
+ { "multithread_bandwidth", multithread_bandwidth },
+};
+
+int main(int argc, char** argv) {
+ if (argc == 1) {
+ usage(argv[0]);
+ return 0;
+ }
+ int err = -1;
+ for (unsigned int i = 0; i < sizeof(function_table)/sizeof(function_t); i++) {
+ if (strcmp(argv[1], function_table[i].cmd_name) == 0) {
+ err = (*function_table[i].func)(argc-1, argv+1);
+ break;
+ }
+ }
+ if (err) {
+ usage(argv[0]);
+ }
+ return err;
+}
+
+int malloc_test(int argc, char** argv) {
+ bool fill = (argc>=2 && !strcmp(argv[1], "fill"));
+ size_t total = 0;
+ size_t size = 0x40000000;
+ while (size) {
+ void* addr = malloc(size);
+ if (addr == 0) {
+ printf("size = %9zd failed\n", size);
+ size >>= 1;
+ } else {
+ total += size;
+ printf("size = %9zd, addr = %p (total = %9zd (%zd MB))\n",
+ size, addr, total, total / (1024*1024));
+ if (fill) {
+ printf("filling...\n");
+ fflush(stdout);
+ memset(addr, 0, size);
+ }
+ size = size + (size>>1);
+ }
+ }
+ printf("done. allocated %zd MB\n", total / (1024*1024));
+ return 0;
+}
+
+int madvise_test(int, char**) {
+ for (int i=0 ; i<2 ; i++) {
+ size_t size = i==0 ? 4096 : 48*1024*1024; // 48 MB
+ printf("Allocating %zd MB... ", size/(1024*1024)); fflush(stdout);
+ void* addr1 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+ printf("%p (%s)\n", addr1, addr1==(void*)-1 ? "failed" : "OK"); fflush(stdout);
+
+ printf("touching %p...\n", addr1); fflush(stdout);
+ memset(addr1, 0x55, size);
+
+ printf("advising DONTNEED...\n"); fflush(stdout);
+ madvise(addr1, size, MADV_DONTNEED);
+
+ printf("reading back %p...\n", addr1); fflush(stdout);
+ if (*(long*)addr1 == 0) {
+ printf("madvise freed some pages\n");
+ } else if (*(long*)addr1 == 0x55555555) {
+ printf("pages are still there\n");
+ } else {
+ printf("getting garbage back\n");
+ }
+
+ printf("Allocating %zd MB... ", size/(1024*1024)); fflush(stdout);
+ void* addr2 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+ printf("%p (%s)\n", addr2, addr2==(void*)-1 ? "failed" : "OK"); fflush(stdout);
+
+ printf("touching %p...\n", addr2); fflush(stdout);
+ memset(addr2, 0xAA, size);
+
+ printf("unmap %p ...\n", addr2); fflush(stdout);
+ munmap(addr2, size);
+
+ printf("touching %p...\n", addr1); fflush(stdout);
+ memset(addr1, 0x55, size);
+
+ printf("unmap %p ...\n", addr1); fflush(stdout);
+ munmap(addr1, size);
+ }
+
+ printf("Done\n"); fflush(stdout);
+ return 0;
+}
+
+int stack_smasher_test(int, char**) {
+ int dummy = 0;
+ printf("corrupting our stack...\n");
+ *(volatile long long*)&dummy = 0;
+ return 0;
+}
+
+// --------------------------------------------------------------------
+
+extern "C" void thumb_function_1(int*p);
+extern "C" void thumb_function_2(int*p);
+extern "C" void arm_function_3(int*p);
+extern "C" void arm_function_2(int*p);
+extern "C" void arm_function_1(int*p);
+
+void arm_function_3(int*) {
+ int a = 0;
+ thumb_function_2(&a);
+}
+
+void arm_function_2(int*) {
+ int a = 0;
+ thumb_function_1(&a);
+}
+
+void arm_function_1(int*) {
+ int a = 0;
+ arm_function_2(&a);
+}
+
+int crawl_test(int, char**) {
+ int a = 0;
+ arm_function_1(&a);
+ return 0;
+}
diff --git a/tests/memtest/memtest.h b/tests/memtest/memtest.h
new file mode 100644
index 0000000..afa6f85
--- /dev/null
+++ b/tests/memtest/memtest.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef __MEMTEST_H__
+#define __MEMTEST_H__
+
+typedef long long nsecs_t;
+
+// Function prototypes.
+nsecs_t system_time();
+
+#endif // __MEMTEST_H__
diff --git a/tests/memtest/thumb.cpp b/tests/memtest/thumb.cpp
new file mode 100644
index 0000000..9293966
--- /dev/null
+++ b/tests/memtest/thumb.cpp
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <unwind.h>
+
+extern "C" void arm_function_3(int* p);
+extern "C" void thumb_function_1(int* p);
+extern "C" void thumb_function_2(int* p);
+
+extern "C" _Unwind_Reason_Code trace_function(_Unwind_Context* context, void *) {
+ printf("0x%x\n", _Unwind_GetIP(context));
+ fflush(stdout);
+ return _URC_NO_REASON;
+}
+
+void thumb_function_1(int*) {
+ int a = 0;
+ arm_function_3(&a);
+}
+
+void thumb_function_2(int*) {
+ printf("unwinding...\n");
+ _Unwind_Backtrace(trace_function, (void*) "backtrace!");
+}
diff --git a/tests/mmc_tracepoints/README b/tests/mmc_tracepoints/README
new file mode 100644
index 0000000..37aba30
--- /dev/null
+++ b/tests/mmc_tracepoints/README
@@ -0,0 +1,27 @@
+The code in this directory is used to process data from the mmc tracepoints
+in the kernel. To turn on mmc tracing, do this:
+
+ adb shell echo 1 >/d/tracing/events/mmc/enable
+ adb shell echo 1 >/d/tracing/tracing_on
+
+To get the trace:
+
+ adb pull /d/tracing/trace
+
+To turn it back off, do:
+
+ adb shell echo 0 >/d/tracing/tracing_enabled
+
+The output is in a form of start/stop pairs. The ops with rw in the name are
+read or write ops, and the ones with erase in the name are the various erase
+opts.
+
+The mmc_trace_reduce script will take the output from the kernel, and convert it
+to a single line per event, which includes the duration of the event.
+
+This can then be fed into other tools for further analysis.
+
+The file mmc_trace_sample_data contains sample mmc trace data from a Nexus 10.
+It includes read, write and discard entries. The discard entries came from
+invoking fstrim in vold with "vdc fstrim dotrim".
+
diff --git a/tests/mmc_tracepoints/mmc_trace_reduce b/tests/mmc_tracepoints/mmc_trace_reduce
new file mode 100755
index 0000000..ef6683e
--- /dev/null
+++ b/tests/mmc_tracepoints/mmc_trace_reduce
@@ -0,0 +1,152 @@
+#!/bin/bash
+
+# TO DO
+# This should be re-written in python.
+
+# Complain about dereferencing unset variables
+set -u
+typeset -i STARTTIME ENDTIME DURATION START_SEC START_USEC DUR_SEC DUR_USEC
+
+if [ "$#" -ne 1 ]
+then
+ echo "Usage: mmc_trace_reduce <trace_file>" >&2
+ exit 1
+fi
+
+exec < "$1"
+
+SAVED_START_LINE=""
+
+while read LINE
+do
+ # Skip comment lines
+ if [ -z "${LINE###*}" ]
+ then
+ continue
+ fi
+
+ # Fix up lines with nuisance spaces
+ LINE=${LINE/AsyncTask /AsyncTask-}
+
+ set $LINE
+
+ if [ "${5##*mmc_blk_*_}" = "start:" ]
+ then
+ if [ ! -z "$SAVED_START_LINE" ]
+ then
+ echo "Ignoring consecutive start line" >&2
+ continue
+ fi
+ SAVED_START_LINE="$LINE"
+
+ # Found a start line. Extract the interesting bits
+ TMP=${4%:}
+ START_SEC="10#${TMP%%.*}"
+ STARTTIME=START_SEC*1000000
+ START_USEC="10#${TMP##*.}"
+ STARTTIME=STARTTIME+START_USEC
+
+ STARTPARMS="$6"
+ STARTCMD=${STARTPARMS%%,addr=*}
+ STARTCMD=${STARTCMD##*cmd=}
+ STARTADDR=${STARTPARMS%%,size=*}
+ STARTADDR=${STARTADDR##*addr=}
+ STARTSIZE=${STARTPARMS##*size=}
+
+ elif [ "${5##*mmc_blk_*_}" = "end:" ]
+ then
+ # Found an end line. Extract the interesting bits,
+ # then make sure it matches with the saved start line,
+ # Finally, do the math and emit a single reduced line
+ TMP=${4%:}
+ ENDTIME="${TMP%%.*}"
+ ENDTIME=ENDTIME*1000000
+ ENDTIME=ENDTIME+10#${TMP##*.}
+
+ ENDPARMS="$6"
+ ENDCMD=${ENDPARMS%%,addr=*}
+ ENDCMD=${ENDCMD##*cmd=}
+ ENDADDR=${ENDPARMS%%,size=*}
+ ENDADDR=${ENDADDR##*addr=}
+ ENDSIZE=${ENDPARMS##*size=}
+
+ if [ "$ENDCMD" != "$STARTCMD" ]
+ then
+ echo "End cmd doesn't match start cmd, ignoring both" >&2
+ SAVED_START_LINE=""
+ continue
+ fi
+ if [ "$ENDADDR" != "$STARTADDR" ]
+ then
+ echo "End addr doesn't match start addr, ignoring both" >&2
+ SAVED_START_LINE=""
+ continue
+ fi
+ if [ "$ENDSIZE" != "$STARTSIZE" ]
+ then
+ echo "End size doesn't match start size, ignoring both" >&2
+ SAVED_START_LINE=""
+ continue
+ fi
+
+ # Turn the command number into a command the flash analysis tool
+ # understands. The tool doesn't differentiate between the different
+ # forms erase, so just emit "discard" for all of them. Also, ignore
+ # the secure_trim2 and sanitize commands as the tool doesn't know
+ # about them either.
+ if [ "$ENDCMD" -eq 18 ]
+ then
+ ENDCMD="read"
+ elif [ "$ENDCMD" -eq 25 ]
+ then
+ ENDCMD="write"
+ elif [ "$ENDCMD" -eq 32 ]
+ then
+ ENDCMD="flush"
+ continue
+ elif [ "$ENDCMD" -eq 0 ]
+ then
+ ENDCMD="discard"
+ elif [ "$ENDCMD" -eq 1 ]
+ then
+ ENDCMD="discard"
+ elif [ "$ENDCMD" -eq 3 ]
+ then
+ ENDCMD="discard"
+ elif [ "$ENDCMD" -eq 2147483648 ] # 0x80000000
+ then
+ ENDCMD="discard"
+ elif [ "$ENDCMD" -eq 2147483649 ] # 0x80000001
+ then
+ ENDCMD="discard"
+ elif [ "$ENDCMD" -eq 2147516416 ] # 0x80008000
+ then
+ # Ignore, as the analysis tool doesn't deal with this
+ # ENDCMD="secure_trim2"
+ SAVED_START_LINE=""
+ continue
+ elif [ "$ENDCMD" -eq 165 ]
+ then
+ # Ignore, as the analysis tool doesn't deal with this
+ # ENDCMD="sanitize"
+ SAVED_START_LINE=""
+ continue
+ else
+ echo "Unrecognized command $ENDCMD, ignoring" >&2
+ SAVED_START_LINE=""
+ continue
+ fi
+
+ DURATION=ENDTIME-STARTTIME
+ DUR_SEC=DURATION/1000000
+ DUR_USEC=DURATION%1000000
+
+ printf "$%s,%s,%s,%d.%06d,%d.%06d\n" "$ENDCMD" "$ENDADDR" "$ENDSIZE" "$START_SEC" "$START_USEC" "$DUR_SEC" "$DUR_USEC"
+
+ SAVED_START_LINE=""
+ fi
+
+ # Ignore unknown lines and continue
+
+done
+
diff --git a/tests/mmc_tracepoints/mmc_trace_sample_data b/tests/mmc_tracepoints/mmc_trace_sample_data
new file mode 100644
index 0000000..4e62dcb
--- /dev/null
+++ b/tests/mmc_tracepoints/mmc_trace_sample_data
@@ -0,0 +1,1545 @@
+# tracer: nop
+#
+# entries-in-buffer/entries-written: 1534/1534 #P:2
+#
+# _-----=> irqs-off
+# / _----=> need-resched
+# | / _---=> hardirq/softirq
+# || / _--=> preempt-depth
+# ||| / delay
+# TASK-PID CPU# |||| TIMESTAMP FUNCTION
+# | | | |||| | |
+ mmcqd/0-82 [000] ...1 49.828932: mmc_blk_rw_start: cmd=25,addr=0x002c6518,size=0x00000010
+ <...>-1484 [000] ..s4 49.829171: mmc_blk_rw_end: cmd=25,addr=0x002c6518,size=0x00000010
+ mmcqd/0-82 [000] ...1 49.830095: mmc_blk_rw_start: cmd=25,addr=0x002c6528,size=0x00000008
+ kworker/0:2-48 [000] ..s4 49.830218: mmc_blk_rw_end: cmd=25,addr=0x002c6528,size=0x00000008
+ mmcqd/0-82 [000] ...1 52.465957: mmc_blk_rw_start: cmd=18,addr=0x001ad578,size=0x00000020
+ <idle>-0 [000] ..s3 52.466404: mmc_blk_rw_end: cmd=18,addr=0x001ad578,size=0x00000020
+ mmcqd/0-82 [000] ...1 52.492868: mmc_blk_rw_start: cmd=18,addr=0x001aecb8,size=0x00000020
+ <idle>-0 [000] ..s3 52.493157: mmc_blk_rw_end: cmd=18,addr=0x001aecb8,size=0x00000020
+ mmcqd/0-82 [000] ...1 54.834287: mmc_blk_rw_start: cmd=25,addr=0x005420a8,size=0x00000008
+ <idle>-0 [000] ..s3 54.834383: mmc_blk_rw_end: cmd=25,addr=0x005420a8,size=0x00000008
+ mmcqd/0-82 [000] ...1 56.114476: mmc_blk_rw_start: cmd=18,addr=0x0013fb18,size=0x00000020
+ <idle>-0 [000] .Ns3 56.114862: mmc_blk_rw_end: cmd=18,addr=0x0013fb18,size=0x00000020
+ mmcqd/0-82 [000] ...1 56.115150: mmc_blk_rw_start: cmd=18,addr=0x0013fb38,size=0x00000040
+ Binder_4-434 [000] ..s3 56.115539: mmc_blk_rw_end: cmd=18,addr=0x0013fb38,size=0x00000040
+ mmcqd/0-82 [000] ...1 56.115616: mmc_blk_rw_start: cmd=18,addr=0x0013faf0,size=0x00000020
+ Binder_4-434 [000] ..s2 56.115856: mmc_blk_rw_end: cmd=18,addr=0x0013faf0,size=0x00000020
+ mmcqd/0-82 [000] ...1 56.118937: mmc_blk_rw_start: cmd=18,addr=0x0013fb78,size=0x00000200
+ <idle>-0 [000] ..s3 56.120836: mmc_blk_rw_end: cmd=18,addr=0x0013fb78,size=0x00000200
+ mmcqd/0-82 [000] ...1 56.123287: mmc_blk_rw_start: cmd=18,addr=0x0013faa8,size=0x00000020
+ <idle>-0 [000] .Ns3 56.123668: mmc_blk_rw_end: cmd=18,addr=0x0013faa8,size=0x00000020
+ mmcqd/0-82 [000] ...1 56.125172: mmc_blk_rw_start: cmd=18,addr=0x0013fb10,size=0x00000008
+ Compiler-387 [000] ..s4 56.125356: mmc_blk_rw_end: cmd=18,addr=0x0013fb10,size=0x00000008
+ mmcqd/0-82 [000] ...1 56.136772: mmc_blk_rw_start: cmd=18,addr=0x0013fd80,size=0x00000008
+ <idle>-0 [000] ..s3 56.136934: mmc_blk_rw_end: cmd=18,addr=0x0013fd80,size=0x00000008
+ mmcqd/0-82 [000] ...1 56.138223: mmc_blk_rw_start: cmd=18,addr=0x0013fda0,size=0x00000008
+ <idle>-0 [000] ..s3 56.138395: mmc_blk_rw_end: cmd=18,addr=0x0013fda0,size=0x00000008
+ mmcqd/0-82 [000] ...1 56.398796: mmc_blk_rw_start: cmd=18,addr=0x0035af18,size=0x00000020
+ WindowManager-396 [000] ..s2 56.399184: mmc_blk_rw_end: cmd=18,addr=0x0035af18,size=0x00000020
+ mmcqd/0-82 [000] ...1 56.399205: mmc_blk_rw_start: cmd=18,addr=0x0035af40,size=0x000000c0
+ WindowManager-396 [000] ..s2 56.399992: mmc_blk_rw_end: cmd=18,addr=0x0035af40,size=0x000000c0
+ mmcqd/0-82 [000] ...1 56.400029: mmc_blk_rw_start: cmd=18,addr=0x00361000,size=0x00000018
+ WindowManager-396 [000] ..s2 56.400300: mmc_blk_rw_end: cmd=18,addr=0x00361000,size=0x00000018
+ mmcqd/0-82 [000] ...1 56.400358: mmc_blk_rw_start: cmd=18,addr=0x003610e8,size=0x00000088
+ WindowManager-396 [000] ..s2 56.400993: mmc_blk_rw_end: cmd=18,addr=0x003610e8,size=0x00000088
+ mmcqd/0-82 [000] ...1 56.402605: mmc_blk_rw_start: cmd=18,addr=0x0035aab8,size=0x00000100
+ WindowManager-396 [000] .Ns3 56.403653: mmc_blk_rw_end: cmd=18,addr=0x0035aab8,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.404001: mmc_blk_rw_start: cmd=18,addr=0x0035a250,size=0x00000100
+ WindowManager-396 [000] ..s3 56.404986: mmc_blk_rw_end: cmd=18,addr=0x0035a250,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.405199: mmc_blk_rw_start: cmd=18,addr=0x0035ade0,size=0x00000100
+ WindowManager-396 [000] ..s3 56.406153: mmc_blk_rw_end: cmd=18,addr=0x0035ade0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.406346: mmc_blk_rw_start: cmd=18,addr=0x0035a020,size=0x000000e8
+ WindowManager-396 [000] ..s2 56.407260: mmc_blk_rw_end: cmd=18,addr=0x0035a020,size=0x000000e8
+ mmcqd/0-82 [000] ...1 56.407510: mmc_blk_rw_start: cmd=18,addr=0x0035a108,size=0x00000090
+ Compiler-387 [000] ..s2 56.408158: mmc_blk_rw_end: cmd=18,addr=0x0035a108,size=0x00000090
+ mmcqd/0-82 [000] ...1 56.408391: mmc_blk_rw_start: cmd=18,addr=0x0035ac10,size=0x00000100
+ WindowManager-396 [000] ..s2 56.409353: mmc_blk_rw_end: cmd=18,addr=0x0035ac10,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.409602: mmc_blk_rw_start: cmd=18,addr=0x0035abb8,size=0x00000058
+ WindowManager-396 [000] ..s2 56.410055: mmc_blk_rw_end: cmd=18,addr=0x0035abb8,size=0x00000058
+ mmcqd/0-82 [000] ...1 56.410338: mmc_blk_rw_start: cmd=18,addr=0x0035ad10,size=0x000000d0
+ UI-395 [000] ..s3 56.411151: mmc_blk_rw_end: cmd=18,addr=0x0035ad10,size=0x000000d0
+ mmcqd/0-82 [000] ...1 56.411364: mmc_blk_rw_start: cmd=18,addr=0x0035a198,size=0x000000b0
+ kworker/0:2-48 [000] ..s2 56.412130: mmc_blk_rw_end: cmd=18,addr=0x0035a198,size=0x000000b0
+ mmcqd/0-82 [000] ...1 56.412521: mmc_blk_rw_start: cmd=18,addr=0x0035a350,size=0x000000b8
+ <idle>-0 [000] ..s3 56.413278: mmc_blk_rw_end: cmd=18,addr=0x0035a350,size=0x000000b8
+ mmcqd/0-82 [000] ...1 56.415655: mmc_blk_rw_start: cmd=18,addr=0x00361018,size=0x000000b8
+ <idle>-0 [000] ..s3 56.416489: mmc_blk_rw_end: cmd=18,addr=0x00361018,size=0x000000b8
+ mmcqd/0-82 [000] ...1 56.416798: mmc_blk_rw_start: cmd=18,addr=0x0035a570,size=0x00000100
+ <idle>-0 [000] ..s3 56.417832: mmc_blk_rw_end: cmd=18,addr=0x0035a570,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.418187: mmc_blk_rw_start: cmd=18,addr=0x0035aa00,size=0x000000b8
+ <idle>-0 [000] ..s3 56.418901: mmc_blk_rw_end: cmd=18,addr=0x0035aa00,size=0x000000b8
+ mmcqd/0-82 [000] ...1 56.422006: mmc_blk_rw_start: cmd=18,addr=0x0035a670,size=0x000000c0
+ <idle>-0 [000] ..s3 56.422804: mmc_blk_rw_end: cmd=18,addr=0x0035a670,size=0x000000c0
+ mmcqd/0-82 [000] ...1 56.424176: mmc_blk_rw_start: cmd=18,addr=0x00b91498,size=0x00000008
+ <idle>-0 [000] ..s3 56.424325: mmc_blk_rw_end: cmd=18,addr=0x00b91498,size=0x00000008
+ mmcqd/0-82 [000] ...1 56.432630: mmc_blk_rw_start: cmd=18,addr=0x0035a918,size=0x000000e8
+ <idle>-0 [000] ..s3 56.433782: mmc_blk_rw_end: cmd=18,addr=0x0035a918,size=0x000000e8
+ mmcqd/0-82 [000] ...1 56.434442: mmc_blk_rw_start: cmd=18,addr=0x0035aee0,size=0x00000038
+ <idle>-0 [000] ..s3 56.434774: mmc_blk_rw_end: cmd=18,addr=0x0035aee0,size=0x00000038
+ mmcqd/0-82 [000] ...1 56.435132: mmc_blk_rw_start: cmd=18,addr=0x0035a248,size=0x00000008
+ <idle>-0 [000] ..s3 56.435292: mmc_blk_rw_end: cmd=18,addr=0x0035a248,size=0x00000008
+ mmcqd/0-82 [000] ...1 56.435774: mmc_blk_rw_start: cmd=18,addr=0x0035a408,size=0x00000100
+ <idle>-0 [000] ..s3 56.436777: mmc_blk_rw_end: cmd=18,addr=0x0035a408,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.436924: mmc_blk_rw_start: cmd=18,addr=0x0035a730,size=0x000000b0
+ <idle>-0 [000] ..s3 56.437682: mmc_blk_rw_end: cmd=18,addr=0x0035a730,size=0x000000b0
+ mmcqd/0-82 [000] ...1 56.443462: mmc_blk_rw_start: cmd=18,addr=0x0035a508,size=0x00000068
+ <idle>-0 [000] ..s3 56.443997: mmc_blk_rw_end: cmd=18,addr=0x0035a508,size=0x00000068
+ mmcqd/0-82 [000] ...1 56.446861: mmc_blk_rw_start: cmd=18,addr=0x003610d0,size=0x00000018
+ ion_chunk_heap-18 [000] ..s2 56.447095: mmc_blk_rw_end: cmd=18,addr=0x003610d0,size=0x00000018
+ mmcqd/0-82 [000] ...1 56.457912: mmc_blk_rw_start: cmd=18,addr=0x0013ffd0,size=0x00000020
+ <idle>-0 [000] ..s3 56.458311: mmc_blk_rw_end: cmd=18,addr=0x0013ffd0,size=0x00000020
+ mmcqd/0-82 [000] ...1 56.503358: mmc_blk_rw_start: cmd=18,addr=0x0013fdb8,size=0x00000008
+ <idle>-0 [000] ..s3 56.503531: mmc_blk_rw_end: cmd=18,addr=0x0013fdb8,size=0x00000008
+ mmcqd/0-82 [000] ...1 56.599614: mmc_blk_rw_start: cmd=18,addr=0x001cae08,size=0x00000020
+ <...>-1488 [000] ..s2 56.599978: mmc_blk_rw_end: cmd=18,addr=0x001cae08,size=0x00000020
+ mmcqd/0-82 [000] ...1 56.600278: mmc_blk_rw_start: cmd=18,addr=0x001dab70,size=0x00000088
+ <...>-1488 [000] .Ns2 56.600968: mmc_blk_rw_end: cmd=18,addr=0x001dab70,size=0x00000088
+ mmcqd/0-82 [000] ...1 56.601458: mmc_blk_rw_start: cmd=18,addr=0x001da970,size=0x00000100
+ <...>-186 [000] ..s4 56.602466: mmc_blk_rw_end: cmd=18,addr=0x001da970,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.602892: mmc_blk_rw_start: cmd=18,addr=0x001cae28,size=0x000000e0
+ <...>-1488 [000] ..s2 56.603805: mmc_blk_rw_end: cmd=18,addr=0x001cae28,size=0x000000e0
+ mmcqd/0-82 [000] ...1 56.604302: mmc_blk_rw_start: cmd=18,addr=0x001f1980,size=0x00000010
+ <...>-1488 [000] ..s2 56.604534: mmc_blk_rw_end: cmd=18,addr=0x001f1980,size=0x00000010
+ mmcqd/0-82 [000] ...1 56.605940: mmc_blk_rw_start: cmd=18,addr=0x001c7f48,size=0x00000018
+ <...>-1488 [000] ..s2 56.606185: mmc_blk_rw_end: cmd=18,addr=0x001c7f48,size=0x00000018
+ mmcqd/0-82 [000] ...1 56.606682: mmc_blk_rw_start: cmd=18,addr=0x00207318,size=0x00000020
+ <...>-1488 [000] ..s2 56.607019: mmc_blk_rw_end: cmd=18,addr=0x00207318,size=0x00000020
+ mmcqd/0-82 [000] ...1 56.607347: mmc_blk_rw_start: cmd=18,addr=0x002073d8,size=0x00000088
+ <...>-1488 [000] ..s2 56.607987: mmc_blk_rw_end: cmd=18,addr=0x002073d8,size=0x00000088
+ mmcqd/0-82 [000] ...1 56.608403: mmc_blk_rw_start: cmd=18,addr=0x00207338,size=0x000000a0
+ <...>-1488 [000] ..s2 56.609126: mmc_blk_rw_end: cmd=18,addr=0x00207338,size=0x000000a0
+ mmcqd/0-82 [000] ...1 56.612141: mmc_blk_rw_start: cmd=18,addr=0x001cbcb0,size=0x00000100
+ <...>-1488 [000] ..s2 56.613209: mmc_blk_rw_end: cmd=18,addr=0x001cbcb0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.615745: mmc_blk_rw_start: cmd=18,addr=0x001caf08,size=0x00000100
+ SurfaceFlinger-150 [000] ..s2 56.616755: mmc_blk_rw_end: cmd=18,addr=0x001caf08,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.616885: mmc_blk_rw_start: cmd=18,addr=0x001d9ff0,size=0x00000100
+ Binder_7-622 [000] ..s4 56.618039: mmc_blk_rw_end: cmd=18,addr=0x001d9ff0,size=0x00000100
+ mmcqd/0-82 [001] ...1 56.619426: mmc_blk_rw_start: cmd=18,addr=0x001da0f0,size=0x00000100
+ Binder_7-622 [000] ..s2 56.620534: mmc_blk_rw_end: cmd=18,addr=0x001da0f0,size=0x00000100
+ mmcqd/0-82 [001] ...1 56.620701: mmc_blk_rw_start: cmd=18,addr=0x001da1f0,size=0x00000100
+ <idle>-0 [000] ..s3 56.621724: mmc_blk_rw_end: cmd=18,addr=0x001da1f0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.621879: mmc_blk_rw_start: cmd=18,addr=0x001cb008,size=0x00000100
+ Binder_B-670 [000] ..s2 56.622887: mmc_blk_rw_end: cmd=18,addr=0x001cb008,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.627277: mmc_blk_rw_start: cmd=18,addr=0x001da2f0,size=0x00000100
+ <...>-1503 [000] ..s2 56.628332: mmc_blk_rw_end: cmd=18,addr=0x001da2f0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.628525: mmc_blk_rw_start: cmd=18,addr=0x001cb108,size=0x00000100
+ <...>-1488 [000] ..s2 56.629524: mmc_blk_rw_end: cmd=18,addr=0x001cb108,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.629924: mmc_blk_rw_start: cmd=18,addr=0x001da3f0,size=0x00000100
+ <...>-1503 [000] ..s2 56.630942: mmc_blk_rw_end: cmd=18,addr=0x001da3f0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.631074: mmc_blk_rw_start: cmd=18,addr=0x001cb208,size=0x00000100
+ SurfaceFlinger-150 [000] ..s2 56.632066: mmc_blk_rw_end: cmd=18,addr=0x001cb208,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.639698: mmc_blk_rw_start: cmd=18,addr=0x001cb308,size=0x00000100
+ <...>-1488 [000] ..s4 56.640734: mmc_blk_rw_end: cmd=18,addr=0x001cb308,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.640888: mmc_blk_rw_start: cmd=18,addr=0x001cb408,size=0x00000100
+ <...>-1488 [000] ..s2 56.641892: mmc_blk_rw_end: cmd=18,addr=0x001cb408,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.641926: mmc_blk_rw_start: cmd=18,addr=0x001da4f0,size=0x00000100
+ <...>-1488 [000] ..s2 56.642952: mmc_blk_rw_end: cmd=18,addr=0x001da4f0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.642981: mmc_blk_rw_start: cmd=18,addr=0x001da5f0,size=0x00000100
+ <...>-1503 [000] ..s2 56.643995: mmc_blk_rw_end: cmd=18,addr=0x001da5f0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.644277: mmc_blk_rw_start: cmd=18,addr=0x001cb508,size=0x00000100
+ kworker/0:1-23 [000] ..s2 56.645266: mmc_blk_rw_end: cmd=18,addr=0x001cb508,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.645946: mmc_blk_rw_start: cmd=18,addr=0x001cb608,size=0x00000100
+ <idle>-0 [000] ..s3 56.646933: mmc_blk_rw_end: cmd=18,addr=0x001cb608,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.647065: mmc_blk_rw_start: cmd=18,addr=0x001da6f0,size=0x00000100
+ <idle>-0 [000] .Ns3 56.648106: mmc_blk_rw_end: cmd=18,addr=0x001da6f0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.651473: mmc_blk_rw_start: cmd=18,addr=0x001cb708,size=0x00000100
+ <idle>-0 [000] ..s3 56.652503: mmc_blk_rw_end: cmd=18,addr=0x001cb708,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.652660: mmc_blk_rw_start: cmd=18,addr=0x001cb808,size=0x00000100
+ <idle>-0 [000] ..s3 56.653650: mmc_blk_rw_end: cmd=18,addr=0x001cb808,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.654708: mmc_blk_rw_start: cmd=18,addr=0x001da7f0,size=0x00000100
+ <idle>-0 [000] ..s3 56.655755: mmc_blk_rw_end: cmd=18,addr=0x001da7f0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.655961: mmc_blk_rw_start: cmd=18,addr=0x001da8f0,size=0x00000080
+ <...>-1488 [000] ..s2 56.656559: mmc_blk_rw_end: cmd=18,addr=0x001da8f0,size=0x00000080
+ mmcqd/0-82 [000] ...1 56.656590: mmc_blk_rw_start: cmd=18,addr=0x001cb908,size=0x00000100
+ <...>-1488 [000] ..s3 56.657590: mmc_blk_rw_end: cmd=18,addr=0x001cb908,size=0x00000100
+ mmcqd/0-82 [001] ...1 56.661710: mmc_blk_rw_start: cmd=18,addr=0x001cba08,size=0x00000100
+ <...>-1488 [000] ..s2 56.662732: mmc_blk_rw_end: cmd=18,addr=0x001cba08,size=0x00000100
+ mmcqd/0-82 [001] ...1 56.663283: mmc_blk_rw_start: cmd=18,addr=0x001cbb08,size=0x00000100
+ <...>-1488 [000] ..s2 56.664267: mmc_blk_rw_end: cmd=18,addr=0x001cbb08,size=0x00000100
+ mmcqd/0-82 [001] ...1 56.664292: mmc_blk_rw_start: cmd=18,addr=0x001daa70,size=0x00000080
+ <...>-204 [000] ..s3 56.664948: mmc_blk_rw_end: cmd=18,addr=0x001daa70,size=0x00000080
+ mmcqd/0-82 [001] ...1 56.664969: mmc_blk_rw_start: cmd=18,addr=0x001cbc08,size=0x000000a8
+ SurfaceFlinger-150 [000] ..s2 56.665694: mmc_blk_rw_end: cmd=18,addr=0x001cbc08,size=0x000000a8
+ mmcqd/0-82 [001] ...1 56.665785: mmc_blk_rw_start: cmd=18,addr=0x001daaf0,size=0x00000080
+ SurfaceFlinger-150 [000] ..s3 56.666372: mmc_blk_rw_end: cmd=18,addr=0x001daaf0,size=0x00000080
+ mmcqd/0-82 [001] ...1 56.697351: mmc_blk_rw_start: cmd=18,addr=0x0013ffa0,size=0x00000008
+ <...>-1503 [000] ..s2 56.697583: mmc_blk_rw_end: cmd=18,addr=0x0013ffa0,size=0x00000008
+ mmcqd/0-82 [001] ...1 56.703729: mmc_blk_rw_start: cmd=18,addr=0x001cbdb0,size=0x000000d0
+ WindowManager-396 [000] ..s2 56.704708: mmc_blk_rw_end: cmd=18,addr=0x001cbdb0,size=0x000000d0
+ mmcqd/0-82 [001] ...1 56.707676: mmc_blk_rw_start: cmd=18,addr=0x001cc148,size=0x00000100
+ <idle>-0 [000] ..s3 56.708698: mmc_blk_rw_end: cmd=18,addr=0x001cc148,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.709038: mmc_blk_rw_start: cmd=18,addr=0x001d35d0,size=0x00000100
+ ion_chunk_heap-18 [000] ..s2 56.710085: mmc_blk_rw_end: cmd=18,addr=0x001d35d0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.710400: mmc_blk_rw_start: cmd=18,addr=0x001d4f18,size=0x00000010
+ ion_chunk_heap-18 [000] ..s3 56.710646: mmc_blk_rw_end: cmd=18,addr=0x001d4f18,size=0x00000010
+ mmcqd/0-82 [000] ...1 56.710661: mmc_blk_rw_start: cmd=18,addr=0x001d4f28,size=0x00000038
+ ion_chunk_heap-18 [000] ..s2 56.711007: mmc_blk_rw_end: cmd=18,addr=0x001d4f28,size=0x00000038
+ mmcqd/0-82 [000] ...1 56.711022: mmc_blk_rw_start: cmd=18,addr=0x001d4f60,size=0x00000010
+ ion_chunk_heap-18 [000] ..s3 56.711188: mmc_blk_rw_end: cmd=18,addr=0x001d4f60,size=0x00000010
+ mmcqd/0-82 [000] ...1 56.711202: mmc_blk_rw_start: cmd=18,addr=0x001d4f70,size=0x00000010
+ ion_chunk_heap-18 [000] ..s4 56.711365: mmc_blk_rw_end: cmd=18,addr=0x001d4f70,size=0x00000010
+ mmcqd/0-82 [000] ...1 56.711385: mmc_blk_rw_start: cmd=18,addr=0x001d4f80,size=0x00000010
+ ion_chunk_heap-18 [000] ..s4 56.711571: mmc_blk_rw_end: cmd=18,addr=0x001d4f80,size=0x00000010
+ mmcqd/0-82 [000] ...1 56.711588: mmc_blk_rw_start: cmd=18,addr=0x001d4f90,size=0x00000010
+ ion_chunk_heap-18 [000] ..s2 56.711769: mmc_blk_rw_end: cmd=18,addr=0x001d4f90,size=0x00000010
+ mmcqd/0-82 [000] ...1 56.711785: mmc_blk_rw_start: cmd=18,addr=0x001d4fa0,size=0x00000010
+ <...>-1523 [000] ..s2 56.711965: mmc_blk_rw_end: cmd=18,addr=0x001d4fa0,size=0x00000010
+ mmcqd/0-82 [000] ...1 56.712020: mmc_blk_rw_start: cmd=18,addr=0x001d4fb0,size=0x00000010
+ ion_chunk_heap-18 [000] ..s2 56.712220: mmc_blk_rw_end: cmd=18,addr=0x001d4fb0,size=0x00000010
+ mmcqd/0-82 [000] ...1 56.712236: mmc_blk_rw_start: cmd=18,addr=0x001d4fc0,size=0x00000010
+ ion_chunk_heap-18 [000] ..s2 56.712423: mmc_blk_rw_end: cmd=18,addr=0x001d4fc0,size=0x00000010
+ mmcqd/0-82 [000] ...1 56.712439: mmc_blk_rw_start: cmd=18,addr=0x001d4fd0,size=0x00000010
+ ion_chunk_heap-18 [000] ..s3 56.712617: mmc_blk_rw_end: cmd=18,addr=0x001d4fd0,size=0x00000010
+ mmcqd/0-82 [000] ...1 56.712633: mmc_blk_rw_start: cmd=18,addr=0x001d4fe0,size=0x00000010
+ ion_chunk_heap-18 [000] ..s3 56.712812: mmc_blk_rw_end: cmd=18,addr=0x001d4fe0,size=0x00000010
+ mmcqd/0-82 [000] ...1 56.712833: mmc_blk_rw_start: cmd=18,addr=0x001d4ff0,size=0x00000020
+ ion_chunk_heap-18 [000] ..s2 56.713092: mmc_blk_rw_end: cmd=18,addr=0x001d4ff0,size=0x00000020
+ mmcqd/0-82 [000] ...1 56.713105: mmc_blk_rw_start: cmd=18,addr=0x001d5010,size=0x00000008
+ ion_chunk_heap-18 [000] ..s2 56.713221: mmc_blk_rw_end: cmd=18,addr=0x001d5010,size=0x00000008
+ mmcqd/0-82 [000] ...1 56.713234: mmc_blk_rw_start: cmd=18,addr=0x001cdc68,size=0x00000100
+ ion_chunk_heap-18 [000] ..s2 56.714260: mmc_blk_rw_end: cmd=18,addr=0x001cdc68,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.714479: mmc_blk_rw_start: cmd=18,addr=0x001cc248,size=0x00000088
+ <...>-95 [000] ..s3 56.715077: mmc_blk_rw_end: cmd=18,addr=0x001cc248,size=0x00000088
+ mmcqd/0-82 [000] ...1 56.716732: mmc_blk_rw_start: cmd=18,addr=0x0013fe68,size=0x00000008
+ ion_chunk_heap-18 [000] ..s3 56.717001: mmc_blk_rw_end: cmd=18,addr=0x0013fe68,size=0x00000008
+ mmcqd/0-82 [000] ...1 56.717019: mmc_blk_rw_start: cmd=18,addr=0x001b9410,size=0x00000018
+ ion_chunk_heap-18 [000] ..s3 56.717306: mmc_blk_rw_end: cmd=18,addr=0x001b9410,size=0x00000018
+ mmcqd/0-82 [000] ...1 56.717328: mmc_blk_rw_start: cmd=18,addr=0x001cd4f0,size=0x00000100
+ Binder_1-198 [000] ..s2 56.718333: mmc_blk_rw_end: cmd=18,addr=0x001cd4f0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.719547: mmc_blk_rw_start: cmd=18,addr=0x001cd710,size=0x00000100
+ ion_chunk_heap-18 [000] ..s2 56.720525: mmc_blk_rw_end: cmd=18,addr=0x001cd710,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.720781: mmc_blk_rw_start: cmd=18,addr=0x001cd970,size=0x00000100
+ ion_chunk_heap-18 [000] ..s3 56.721794: mmc_blk_rw_end: cmd=18,addr=0x001cd970,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.722013: mmc_blk_rw_start: cmd=18,addr=0x001cf240,size=0x00000100
+ <...>-204 [000] ..s3 56.722961: mmc_blk_rw_end: cmd=18,addr=0x001cf240,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.723195: mmc_blk_rw_start: cmd=18,addr=0x001d12b8,size=0x00000100
+ ion_chunk_heap-18 [000] ..s3 56.724218: mmc_blk_rw_end: cmd=18,addr=0x001d12b8,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.724309: mmc_blk_rw_start: cmd=18,addr=0x0013fda8,size=0x00000010
+ ion_chunk_heap-18 [000] ..s2 56.724519: mmc_blk_rw_end: cmd=18,addr=0x0013fda8,size=0x00000010
+ mmcqd/0-82 [000] ...1 56.724532: mmc_blk_rw_start: cmd=18,addr=0x0013fdc0,size=0x00000048
+ ion_chunk_heap-18 [000] ..s2 56.724938: mmc_blk_rw_end: cmd=18,addr=0x0013fdc0,size=0x00000048
+ mmcqd/0-82 [000] ...1 56.726292: mmc_blk_rw_start: cmd=18,addr=0x0013ff90,size=0x00000008
+ <idle>-0 [000] ..s3 56.726465: mmc_blk_rw_end: cmd=18,addr=0x0013ff90,size=0x00000008
+ mmcqd/0-82 [000] ...1 56.728492: mmc_blk_rw_start: cmd=18,addr=0x0013ff30,size=0x00000008
+ <idle>-0 [000] ..s3 56.728670: mmc_blk_rw_end: cmd=18,addr=0x0013ff30,size=0x00000008
+ mmcqd/0-82 [000] ...1 56.729188: mmc_blk_rw_start: cmd=18,addr=0x0013ff38,size=0x00000058
+ <idle>-0 [000] ..s3 56.729717: mmc_blk_rw_end: cmd=18,addr=0x0013ff38,size=0x00000058
+ mmcqd/0-82 [000] ...1 56.729769: mmc_blk_rw_start: cmd=18,addr=0x0013ff98,size=0x00000008
+ <idle>-0 [000] ..s3 56.729932: mmc_blk_rw_end: cmd=18,addr=0x0013ff98,size=0x00000008
+ mmcqd/0-82 [000] ...1 56.729978: mmc_blk_rw_start: cmd=18,addr=0x0013ffa8,size=0x00000010
+ <idle>-0 [000] ..s3 56.730221: mmc_blk_rw_end: cmd=18,addr=0x0013ffa8,size=0x00000010
+ mmcqd/0-82 [000] ...1 56.730269: mmc_blk_rw_start: cmd=18,addr=0x0013feb8,size=0x00000078
+ <idle>-0 [000] ..s3 56.730903: mmc_blk_rw_end: cmd=18,addr=0x0013feb8,size=0x00000078
+ mmcqd/0-82 [000] ...1 56.733814: mmc_blk_rw_start: cmd=18,addr=0x0013fe78,size=0x00000020
+ <idle>-0 [000] ..s3 56.734174: mmc_blk_rw_end: cmd=18,addr=0x0013fe78,size=0x00000020
+ mmcqd/0-82 [000] ...1 56.736291: mmc_blk_rw_start: cmd=18,addr=0x0013fd88,size=0x00000018
+ <idle>-0 [000] ..s3 56.736551: mmc_blk_rw_end: cmd=18,addr=0x0013fd88,size=0x00000018
+ mmcqd/0-82 [000] ...1 56.736604: mmc_blk_rw_start: cmd=18,addr=0x0013fd78,size=0x00000008
+ <...>-1488 [000] ..s2 56.736753: mmc_blk_rw_end: cmd=18,addr=0x0013fd78,size=0x00000008
+ mmcqd/0-82 [000] ...1 56.739250: mmc_blk_rw_start: cmd=18,addr=0x001d8ec0,size=0x00000100
+ <...>-406 [000] .Ns2 56.740339: mmc_blk_rw_end: cmd=18,addr=0x001d8ec0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.740691: mmc_blk_rw_start: cmd=18,addr=0x001d1738,size=0x00000100
+ <idle>-0 [000] ..s3 56.741682: mmc_blk_rw_end: cmd=18,addr=0x001d1738,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.741965: mmc_blk_rw_start: cmd=18,addr=0x001d1b90,size=0x00000100
+ <idle>-0 [000] ..s3 56.742953: mmc_blk_rw_end: cmd=18,addr=0x001d1b90,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.743297: mmc_blk_rw_start: cmd=18,addr=0x001d2a98,size=0x00000100
+ <...>-1496 [000] ..s2 56.744359: mmc_blk_rw_end: cmd=18,addr=0x001d2a98,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.744585: mmc_blk_rw_start: cmd=18,addr=0x001d3478,size=0x00000100
+ <idle>-0 [000] ..s3 56.745592: mmc_blk_rw_end: cmd=18,addr=0x001d3478,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.745846: mmc_blk_rw_start: cmd=18,addr=0x001d3b30,size=0x00000100
+ <idle>-0 [000] ..s3 56.746829: mmc_blk_rw_end: cmd=18,addr=0x001d3b30,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.747117: mmc_blk_rw_start: cmd=18,addr=0x001d9ba8,size=0x00000100
+ <idle>-0 [000] ..s3 56.748190: mmc_blk_rw_end: cmd=18,addr=0x001d9ba8,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.748465: mmc_blk_rw_start: cmd=18,addr=0x001d2df0,size=0x00000100
+ <idle>-0 [000] ..s3 56.749470: mmc_blk_rw_end: cmd=18,addr=0x001d2df0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.749865: mmc_blk_rw_start: cmd=18,addr=0x001ce280,size=0x00000100
+ SurfaceFlinger-150 [000] ..s4 56.750866: mmc_blk_rw_end: cmd=18,addr=0x001ce280,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.751289: mmc_blk_rw_start: cmd=18,addr=0x001d3578,size=0x00000058
+ <idle>-0 [000] ..s3 56.751761: mmc_blk_rw_end: cmd=18,addr=0x001d3578,size=0x00000058
+ mmcqd/0-82 [000] ...1 56.751845: mmc_blk_rw_start: cmd=18,addr=0x001d58c8,size=0x00000100
+ <idle>-0 [000] ..s3 56.752893: mmc_blk_rw_end: cmd=18,addr=0x001d58c8,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.754212: mmc_blk_rw_start: cmd=18,addr=0x0013fe70,size=0x00000008
+ <idle>-0 [000] ..s3 56.754450: mmc_blk_rw_end: cmd=18,addr=0x0013fe70,size=0x00000008
+ mmcqd/0-82 [000] ...1 56.754496: mmc_blk_rw_start: cmd=18,addr=0x0013fe98,size=0x00000020
+ <...>-1497 [000] ..s2 56.754842: mmc_blk_rw_end: cmd=18,addr=0x0013fe98,size=0x00000020
+ mmcqd/0-82 [000] ...1 56.754860: mmc_blk_rw_start: cmd=18,addr=0x001d0740,size=0x00000100
+ <...>-1488 [000] ..s3 56.755885: mmc_blk_rw_end: cmd=18,addr=0x001d0740,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.759274: mmc_blk_rw_start: cmd=18,addr=0x001d5028,size=0x00000100
+ <...>-1488 [000] .Ns4 56.760368: mmc_blk_rw_end: cmd=18,addr=0x001d5028,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.764203: mmc_blk_rw_start: cmd=18,addr=0x001cce38,size=0x00000100
+ <...>-95 [000] ..s3 56.765272: mmc_blk_rw_end: cmd=18,addr=0x001cce38,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.765725: mmc_blk_rw_start: cmd=18,addr=0x001d0650,size=0x000000f0
+ <...>-1488 [000] ..s2 56.766713: mmc_blk_rw_end: cmd=18,addr=0x001d0650,size=0x000000f0
+ mmcqd/0-82 [001] ...1 56.767749: mmc_blk_rw_start: cmd=18,addr=0x001d3d60,size=0x00000070
+ <...>-1488 [000] ..s2 56.768374: mmc_blk_rw_end: cmd=18,addr=0x001d3d60,size=0x00000070
+ mmcqd/0-82 [001] ...1 56.769290: mmc_blk_rw_start: cmd=18,addr=0x001d3dd0,size=0x00000090
+ <...>-1488 [000] ..s2 56.769942: mmc_blk_rw_end: cmd=18,addr=0x001d3dd0,size=0x00000090
+ mmcqd/0-82 [001] ...1 56.774342: mmc_blk_rw_start: cmd=18,addr=0x001cd8d0,size=0x000000a0
+ <...>-406 [000] ..s4 56.775119: mmc_blk_rw_end: cmd=18,addr=0x001cd8d0,size=0x000000a0
+ mmcqd/0-82 [001] ...1 56.775689: mmc_blk_rw_start: cmd=18,addr=0x001d6330,size=0x00000100
+ Compiler-1495 [000] ..s2 56.776705: mmc_blk_rw_end: cmd=18,addr=0x001d6330,size=0x00000100
+ mmcqd/0-82 [001] ...1 56.777034: mmc_blk_rw_start: cmd=18,addr=0x001d36d0,size=0x00000080
+ Compiler-1495 [000] ..s2 56.777586: mmc_blk_rw_end: cmd=18,addr=0x001d36d0,size=0x00000080
+ mmcqd/0-82 [001] ...1 56.777901: mmc_blk_rw_start: cmd=18,addr=0x001d92d0,size=0x00000100
+ Compiler-1495 [000] ..s2 56.778879: mmc_blk_rw_end: cmd=18,addr=0x001d92d0,size=0x00000100
+ mmcqd/0-82 [001] ...1 56.779219: mmc_blk_rw_start: cmd=18,addr=0x001d5838,size=0x00000090
+ Compiler-1495 [000] ..s2 56.779826: mmc_blk_rw_end: cmd=18,addr=0x001d5838,size=0x00000090
+ mmcqd/0-82 [001] ...1 56.780091: mmc_blk_rw_start: cmd=18,addr=0x001cbe80,size=0x00000100
+ <...>-1488 [000] ..s2 56.781135: mmc_blk_rw_end: cmd=18,addr=0x001cbe80,size=0x00000100
+ mmcqd/0-82 [001] ...1 56.781221: mmc_blk_rw_start: cmd=18,addr=0x001d5128,size=0x00000080
+ <...>-1488 [000] ..s2 56.781804: mmc_blk_rw_end: cmd=18,addr=0x001d5128,size=0x00000080
+ mmcqd/0-82 [001] ...1 56.782053: mmc_blk_rw_start: cmd=18,addr=0x001d91c0,size=0x00000100
+ <...>-1488 [000] ..s2 56.783031: mmc_blk_rw_end: cmd=18,addr=0x001d91c0,size=0x00000100
+ mmcqd/0-82 [001] ...1 56.784197: mmc_blk_rw_start: cmd=18,addr=0x001d51a8,size=0x00000100
+ <idle>-0 [000] ..s3 56.785337: mmc_blk_rw_end: cmd=18,addr=0x001d51a8,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.785476: mmc_blk_rw_start: cmd=18,addr=0x001d5018,size=0x00000010
+ <idle>-0 [000] ..s3 56.785673: mmc_blk_rw_end: cmd=18,addr=0x001d5018,size=0x00000010
+ mmcqd/0-82 [000] ...1 56.786668: mmc_blk_rw_start: cmd=18,addr=0x001d1ab0,size=0x000000e0
+ <idle>-0 [000] ..s3 56.787689: mmc_blk_rw_end: cmd=18,addr=0x001d1ab0,size=0x000000e0
+ mmcqd/0-82 [000] ...1 56.788047: mmc_blk_rw_start: cmd=18,addr=0x001d93d0,size=0x00000098
+ <idle>-0 [000] ..s3 56.788712: mmc_blk_rw_end: cmd=18,addr=0x001d93d0,size=0x00000098
+ mmcqd/0-82 [000] ...1 56.789370: mmc_blk_rw_start: cmd=18,addr=0x001d55c8,size=0x00000100
+ <idle>-0 [000] ..s3 56.790423: mmc_blk_rw_end: cmd=18,addr=0x001d55c8,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.790915: mmc_blk_rw_start: cmd=18,addr=0x001d9578,size=0x00000100
+ <idle>-0 [000] ..s3 56.791962: mmc_blk_rw_end: cmd=18,addr=0x001d9578,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.792834: mmc_blk_rw_start: cmd=18,addr=0x001d56c8,size=0x000000d0
+ <idle>-0 [000] ..s3 56.793714: mmc_blk_rw_end: cmd=18,addr=0x001d56c8,size=0x000000d0
+ mmcqd/0-82 [000] ...1 56.793982: mmc_blk_rw_start: cmd=18,addr=0x001ce0a0,size=0x00000100
+ <idle>-0 [000] ..s3 56.794987: mmc_blk_rw_end: cmd=18,addr=0x001ce0a0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.795529: mmc_blk_rw_start: cmd=18,addr=0x001ce950,size=0x00000100
+ <idle>-0 [000] ..s3 56.796486: mmc_blk_rw_end: cmd=18,addr=0x001ce950,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.796968: mmc_blk_rw_start: cmd=18,addr=0x001d54a8,size=0x00000100
+ <idle>-0 [000] ..s3 56.798042: mmc_blk_rw_end: cmd=18,addr=0x001d54a8,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.799026: mmc_blk_rw_start: cmd=18,addr=0x001d10c8,size=0x00000100
+ <...>-1488 [000] ..s2 56.800076: mmc_blk_rw_end: cmd=18,addr=0x001d10c8,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.800814: mmc_blk_rw_start: cmd=18,addr=0x001cdf48,size=0x00000100
+ <...>-1488 [000] ..s2 56.801860: mmc_blk_rw_end: cmd=18,addr=0x001cdf48,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.807747: mmc_blk_rw_start: cmd=18,addr=0x001cc628,size=0x00000100
+ <idle>-0 [000] ..s3 56.808883: mmc_blk_rw_end: cmd=18,addr=0x001cc628,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.810313: mmc_blk_rw_start: cmd=18,addr=0x001cc728,size=0x00000100
+ <idle>-0 [000] ..s3 56.811414: mmc_blk_rw_end: cmd=18,addr=0x001cc728,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.838043: mmc_blk_rw_start: cmd=18,addr=0x001d52a8,size=0x00000098
+ <...>-1509 [000] ..s2 56.838880: mmc_blk_rw_end: cmd=18,addr=0x001d52a8,size=0x00000098
+ mmcqd/0-82 [000] ...1 56.839823: mmc_blk_rw_start: cmd=18,addr=0x001cee08,size=0x00000100
+ <idle>-0 [000] ..s3 56.840907: mmc_blk_rw_end: cmd=18,addr=0x001cee08,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.841309: mmc_blk_rw_start: cmd=18,addr=0x001cc980,size=0x00000100
+ <idle>-0 [000] ..s3 56.842316: mmc_blk_rw_end: cmd=18,addr=0x001cc980,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.842635: mmc_blk_rw_start: cmd=18,addr=0x001d6430,size=0x00000100
+ <idle>-0 [000] ..s3 56.843647: mmc_blk_rw_end: cmd=18,addr=0x001d6430,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.843694: mmc_blk_rw_start: cmd=18,addr=0x001d5420,size=0x00000088
+ <idle>-0 [000] ..s3 56.844291: mmc_blk_rw_end: cmd=18,addr=0x001d5420,size=0x00000088
+ mmcqd/0-82 [000] ...1 56.844588: mmc_blk_rw_start: cmd=18,addr=0x001d3750,size=0x00000100
+ <idle>-0 [000] ..s3 56.845580: mmc_blk_rw_end: cmd=18,addr=0x001d3750,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.845630: mmc_blk_rw_start: cmd=18,addr=0x001d15d0,size=0x00000100
+ <idle>-0 [000] ..s3 56.846655: mmc_blk_rw_end: cmd=18,addr=0x001d15d0,size=0x00000100
+ mmcqd/0-82 [001] ...1 56.847372: mmc_blk_rw_start: cmd=18,addr=0x001cf120,size=0x00000100
+ <idle>-0 [000] ..s3 56.848387: mmc_blk_rw_end: cmd=18,addr=0x001cf120,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.848652: mmc_blk_rw_start: cmd=18,addr=0x001cc498,size=0x00000100
+ UI-395 [000] ..s2 56.849701: mmc_blk_rw_end: cmd=18,addr=0x001cc498,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.853069: mmc_blk_rw_start: cmd=18,addr=0x001cef08,size=0x000000b0
+ <idle>-0 [000] ..s3 56.853834: mmc_blk_rw_end: cmd=18,addr=0x001cef08,size=0x000000b0
+ mmcqd/0-82 [000] ...1 56.854772: mmc_blk_rw_start: cmd=18,addr=0x001cf340,size=0x000000b0
+ <idle>-0 [000] ..s3 56.855503: mmc_blk_rw_end: cmd=18,addr=0x001cf340,size=0x000000b0
+ mmcqd/0-82 [000] ...1 56.855902: mmc_blk_rw_start: cmd=18,addr=0x001cf560,size=0x00000100
+ <idle>-0 [000] ..s3 56.856920: mmc_blk_rw_end: cmd=18,addr=0x001cf560,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.857426: mmc_blk_rw_start: cmd=18,addr=0x001d5340,size=0x000000b8
+ <idle>-0 [000] ..s3 56.858165: mmc_blk_rw_end: cmd=18,addr=0x001d5340,size=0x000000b8
+ mmcqd/0-82 [000] ...1 56.858818: mmc_blk_rw_start: cmd=18,addr=0x001cf3f0,size=0x000000b8
+ kworker/0:1-23 [000] ..s2 56.859605: mmc_blk_rw_end: cmd=18,addr=0x001cf3f0,size=0x000000b8
+ mmcqd/0-82 [000] ...1 56.864629: mmc_blk_rw_start: cmd=18,addr=0x001d3908,size=0x00000100
+ <...>-95 [000] ..s3 56.865633: mmc_blk_rw_end: cmd=18,addr=0x001d3908,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.866118: mmc_blk_rw_start: cmd=18,addr=0x001cc3f0,size=0x000000a8
+ Binder_2-130 [000] ..s2 56.866844: mmc_blk_rw_end: cmd=18,addr=0x001cc3f0,size=0x000000a8
+ mmcqd/0-82 [000] ...1 56.868586: mmc_blk_rw_start: cmd=18,addr=0x001d3aa8,size=0x00000088
+ <idle>-0 [000] ..s3 56.869318: mmc_blk_rw_end: cmd=18,addr=0x001d3aa8,size=0x00000088
+ mmcqd/0-82 [000] ...1 56.869655: mmc_blk_rw_start: cmd=18,addr=0x001ccf38,size=0x000000d0
+ <idle>-0 [000] ..s3 56.870499: mmc_blk_rw_end: cmd=18,addr=0x001ccf38,size=0x000000d0
+ mmcqd/0-82 [000] ...1 56.870776: mmc_blk_rw_start: cmd=18,addr=0x001cea50,size=0x00000080
+ <idle>-0 [000] ..s3 56.871323: mmc_blk_rw_end: cmd=18,addr=0x001cea50,size=0x00000080
+ mmcqd/0-82 [000] ...1 56.871650: mmc_blk_rw_start: cmd=18,addr=0x001cc2d0,size=0x00000100
+ <idle>-0 [000] ..s3 56.872658: mmc_blk_rw_end: cmd=18,addr=0x001cc2d0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.872765: mmc_blk_rw_start: cmd=18,addr=0x001d3850,size=0x000000b8
+ <idle>-0 [000] ..s3 56.873509: mmc_blk_rw_end: cmd=18,addr=0x001d3850,size=0x000000b8
+ mmcqd/0-82 [000] ...1 56.874190: mmc_blk_rw_start: cmd=18,addr=0x001d3a08,size=0x00000088
+ <idle>-0 [000] ..s3 56.874798: mmc_blk_rw_end: cmd=18,addr=0x001d3a08,size=0x00000088
+ mmcqd/0-82 [000] ...1 56.879190: mmc_blk_rw_start: cmd=18,addr=0x001cec48,size=0x00000100
+ <idle>-0 [000] ..s3 56.880192: mmc_blk_rw_end: cmd=18,addr=0x001cec48,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.880782: mmc_blk_rw_start: cmd=18,addr=0x001d11c8,size=0x000000f0
+ <idle>-0 [000] ..s3 56.881750: mmc_blk_rw_end: cmd=18,addr=0x001d11c8,size=0x000000f0
+ mmcqd/0-82 [000] ...1 56.882143: mmc_blk_rw_start: cmd=18,addr=0x001ccb30,size=0x00000100
+ Compiler-387 [000] ..s2 56.883123: mmc_blk_rw_end: cmd=18,addr=0x001ccb30,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.884709: mmc_blk_rw_start: cmd=18,addr=0x001cefb8,size=0x000000d0
+ <idle>-0 [000] ..s3 56.885617: mmc_blk_rw_end: cmd=18,addr=0x001cefb8,size=0x000000d0
+ mmcqd/0-82 [000] ...1 56.885963: mmc_blk_rw_start: cmd=18,addr=0x001cc598,size=0x00000090
+ <idle>-0 [000] ..s3 56.886669: mmc_blk_rw_end: cmd=18,addr=0x001cc598,size=0x00000090
+ mmcqd/0-82 [000] ...1 56.886972: mmc_blk_rw_start: cmd=18,addr=0x001cf088,size=0x00000098
+ <...>-1488 [000] ..s3 56.887678: mmc_blk_rw_end: cmd=18,addr=0x001cf088,size=0x00000098
+ mmcqd/0-82 [000] ...1 56.887794: mmc_blk_rw_start: cmd=18,addr=0x001cf660,size=0x00000100
+ <idle>-0 [000] ..s3 56.888813: mmc_blk_rw_end: cmd=18,addr=0x001cf660,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.888906: mmc_blk_rw_start: cmd=18,addr=0x00b88260,size=0x00000008
+ <idle>-0 [000] ..s3 56.889033: mmc_blk_rw_end: cmd=18,addr=0x00b88260,size=0x00000008
+ mmcqd/0-82 [000] ...1 56.889423: mmc_blk_rw_start: cmd=18,addr=0x001d45e8,size=0x00000100
+ <idle>-0 [000] ..s3 56.890499: mmc_blk_rw_end: cmd=18,addr=0x001d45e8,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.891533: mmc_blk_rw_start: cmd=18,addr=0x001ce380,size=0x000000d0
+ <idle>-0 [000] ..s3 56.892387: mmc_blk_rw_end: cmd=18,addr=0x001ce380,size=0x000000d0
+ mmcqd/0-82 [000] ...1 56.893152: mmc_blk_rw_start: cmd=18,addr=0x001d8e10,size=0x000000b0
+ <idle>-0 [000] ..s3 56.893861: mmc_blk_rw_end: cmd=18,addr=0x001d8e10,size=0x000000b0
+ mmcqd/0-82 [000] ...1 56.894806: mmc_blk_rw_start: cmd=18,addr=0x00544c90,size=0x00000100
+ <idle>-0 [000] ..s3 56.895846: mmc_blk_rw_end: cmd=18,addr=0x00544c90,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.896175: mmc_blk_rw_start: cmd=18,addr=0x005441a8,size=0x00000100
+ <idle>-0 [000] ..s3 56.897158: mmc_blk_rw_end: cmd=18,addr=0x005441a8,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.897495: mmc_blk_rw_start: cmd=18,addr=0x001d9dc8,size=0x00000100
+ <idle>-0 [000] ..s3 56.898518: mmc_blk_rw_end: cmd=18,addr=0x001d9dc8,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.898781: mmc_blk_rw_start: cmd=18,addr=0x001d5798,size=0x000000a0
+ WindowManager-396 [000] ..s2 56.899508: mmc_blk_rw_end: cmd=18,addr=0x001d5798,size=0x000000a0
+ mmcqd/0-82 [000] ...1 56.900612: mmc_blk_rw_start: cmd=18,addr=0x001d3140,size=0x00000100
+ WindowManager-396 [000] ..s2 56.901656: mmc_blk_rw_end: cmd=18,addr=0x001d3140,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.901925: mmc_blk_rw_start: cmd=18,addr=0x001d6530,size=0x00000100
+ <...>-204 [000] ..s2 56.902901: mmc_blk_rw_end: cmd=18,addr=0x001d6530,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.903030: mmc_blk_rw_start: cmd=18,addr=0x001d8320,size=0x00000100
+ <idle>-0 [000] ..s3 56.903994: mmc_blk_rw_end: cmd=18,addr=0x001d8320,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.904278: mmc_blk_rw_start: cmd=18,addr=0x001d9d20,size=0x000000a8
+ <idle>-0 [000] ..s3 56.904943: mmc_blk_rw_end: cmd=18,addr=0x001d9d20,size=0x000000a8
+ mmcqd/0-82 [000] ...1 56.906275: mmc_blk_rw_start: cmd=18,addr=0x005449e0,size=0x00000100
+ <idle>-0 [000] ..s3 56.907247: mmc_blk_rw_end: cmd=18,addr=0x005449e0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.907674: mmc_blk_rw_start: cmd=18,addr=0x005437c0,size=0x00000100
+ <idle>-0 [000] ..s3 56.908631: mmc_blk_rw_end: cmd=18,addr=0x005437c0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.910838: mmc_blk_rw_start: cmd=18,addr=0x001ccd78,size=0x000000c0
+ <idle>-0 [000] ..s3 56.911723: mmc_blk_rw_end: cmd=18,addr=0x001ccd78,size=0x000000c0
+ mmcqd/0-82 [000] ...1 56.912234: mmc_blk_rw_start: cmd=18,addr=0x001d6278,size=0x000000b8
+ <idle>-0 [000] ..s3 56.912999: mmc_blk_rw_end: cmd=18,addr=0x001d6278,size=0x000000b8
+ mmcqd/0-82 [000] ...1 56.935470: mmc_blk_rw_start: cmd=18,addr=0x001cd370,size=0x00000100
+ <idle>-0 [000] ..s3 56.936581: mmc_blk_rw_end: cmd=18,addr=0x001cd370,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.937169: mmc_blk_rw_start: cmd=18,addr=0x001d3c70,size=0x000000f0
+ <idle>-0 [000] ..s3 56.938142: mmc_blk_rw_end: cmd=18,addr=0x001d3c70,size=0x000000f0
+ mmcqd/0-82 [000] ...1 56.939187: mmc_blk_rw_start: cmd=18,addr=0x001ceb98,size=0x000000b0
+ <idle>-0 [000] ..s3 56.940006: mmc_blk_rw_end: cmd=18,addr=0x001ceb98,size=0x000000b0
+ mmcqd/0-82 [000] ...1 56.940382: mmc_blk_rw_start: cmd=18,addr=0x001cdad8,size=0x00000100
+ <idle>-0 [000] ..s3 56.941418: mmc_blk_rw_end: cmd=18,addr=0x001cdad8,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.941715: mmc_blk_rw_start: cmd=18,addr=0x001d3a90,size=0x00000018
+ <idle>-0 [000] ..s3 56.941974: mmc_blk_rw_end: cmd=18,addr=0x001d3a90,size=0x00000018
+ mmcqd/0-82 [000] ...1 56.942388: mmc_blk_rw_start: cmd=18,addr=0x001cf850,size=0x00000100
+ <idle>-0 [000] ..s3 56.943362: mmc_blk_rw_end: cmd=18,addr=0x001cf850,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.943778: mmc_blk_rw_start: cmd=18,addr=0x001cc828,size=0x000000c8
+ <idle>-0 [000] ..s3 56.944676: mmc_blk_rw_end: cmd=18,addr=0x001cc828,size=0x000000c8
+ mmcqd/0-82 [000] ...1 56.945026: mmc_blk_rw_start: cmd=18,addr=0x001d0358,size=0x00000100
+ <idle>-0 [000] ..s3 56.946053: mmc_blk_rw_end: cmd=18,addr=0x001d0358,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.946416: mmc_blk_rw_start: cmd=18,addr=0x001d3e60,size=0x000000a8
+ <idle>-0 [000] ..s3 56.947118: mmc_blk_rw_end: cmd=18,addr=0x001d3e60,size=0x000000a8
+ mmcqd/0-82 [000] ...1 56.947455: mmc_blk_rw_start: cmd=18,addr=0x001d40c8,size=0x00000100
+ <idle>-0 [000] ..s3 56.948489: mmc_blk_rw_end: cmd=18,addr=0x001d40c8,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.948831: mmc_blk_rw_start: cmd=18,addr=0x001d41f0,size=0x00000100
+ <idle>-0 [000] ..s3 56.949854: mmc_blk_rw_end: cmd=18,addr=0x001d41f0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.950189: mmc_blk_rw_start: cmd=18,addr=0x001d3f08,size=0x00000088
+ <idle>-0 [000] ..s3 56.950786: mmc_blk_rw_end: cmd=18,addr=0x001d3f08,size=0x00000088
+ mmcqd/0-82 [000] ...1 56.951156: mmc_blk_rw_start: cmd=18,addr=0x001d4460,size=0x00000100
+ <idle>-0 [000] ..s3 56.952161: mmc_blk_rw_end: cmd=18,addr=0x001d4460,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.954210: mmc_blk_rw_start: cmd=18,addr=0x001d1c90,size=0x000000e0
+ <idle>-0 [000] .Ns3 56.955120: mmc_blk_rw_end: cmd=18,addr=0x001d1c90,size=0x000000e0
+ mmcqd/0-82 [000] ...1 56.956111: mmc_blk_rw_start: cmd=18,addr=0x001d1db8,size=0x00000100
+ Compiler-1495 [000] ..s2 56.957170: mmc_blk_rw_end: cmd=18,addr=0x001d1db8,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.958861: mmc_blk_rw_start: cmd=18,addr=0x001ccc30,size=0x00000100
+ Compiler-1495 [000] ..s2 56.959885: mmc_blk_rw_end: cmd=18,addr=0x001ccc30,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.960795: mmc_blk_rw_start: cmd=18,addr=0x001cd0a0,size=0x00000100
+ <idle>-0 [000] ..s3 56.961838: mmc_blk_rw_end: cmd=18,addr=0x001cd0a0,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.965080: mmc_blk_rw_start: cmd=18,addr=0x001cfc08,size=0x00000100
+ <...>-1534 [000] ..s3 56.966104: mmc_blk_rw_end: cmd=18,addr=0x001cfc08,size=0x00000100
+ mmcqd/0-82 [000] ...1 56.969245: mmc_blk_rw_start: cmd=18,addr=0x001d1d70,size=0x00000048
+ <...>-1534 [000] ..s2 56.969681: mmc_blk_rw_end: cmd=18,addr=0x001d1d70,size=0x00000048
+ mmcqd/0-82 [000] ...1 56.978217: mmc_blk_rw_start: cmd=18,addr=0x001d19f8,size=0x000000b8
+ <...>-1534 [000] ..s4 56.979048: mmc_blk_rw_end: cmd=18,addr=0x001d19f8,size=0x000000b8
+ mmcqd/0-82 [000] ...1 56.989267: mmc_blk_rw_start: cmd=18,addr=0x00545fd0,size=0x00000100
+ <idle>-0 [000] ..s3 56.990384: mmc_blk_rw_end: cmd=18,addr=0x00545fd0,size=0x00000100
+ mmcqd/0-82 [001] ...1 56.990930: mmc_blk_rw_start: cmd=18,addr=0x001ceb00,size=0x00000098
+ <idle>-0 [000] ..s3 56.991576: mmc_blk_rw_end: cmd=18,addr=0x001ceb00,size=0x00000098
+ mmcqd/0-82 [000] ...1 56.997991: mmc_blk_rw_start: cmd=18,addr=0x001cf760,size=0x00000080
+ <idle>-0 [000] ..s3 56.998591: mmc_blk_rw_end: cmd=18,addr=0x001cf760,size=0x00000080
+ mmcqd/0-82 [000] ...1 56.999603: mmc_blk_rw_start: cmd=18,addr=0x001d0458,size=0x000000c8
+ <idle>-0 [000] ..s3 57.000459: mmc_blk_rw_end: cmd=18,addr=0x001d0458,size=0x000000c8
+ mmcqd/0-82 [000] ...1 57.000920: mmc_blk_rw_start: cmd=18,addr=0x001d2680,size=0x00000100
+ <idle>-0 [000] ..s3 57.001914: mmc_blk_rw_end: cmd=18,addr=0x001d2680,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.002233: mmc_blk_rw_start: cmd=18,addr=0x001cf4a8,size=0x00000088
+ <idle>-0 [000] ..s3 57.002917: mmc_blk_rw_end: cmd=18,addr=0x001cf4a8,size=0x00000088
+ mmcqd/0-82 [000] ...1 57.003455: mmc_blk_rw_start: cmd=18,addr=0x001cf220,size=0x00000020
+ <idle>-0 [000] ..s3 57.003677: mmc_blk_rw_end: cmd=18,addr=0x001cf220,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.004798: mmc_blk_rw_start: cmd=18,addr=0x001d7ae8,size=0x00000100
+ <idle>-0 [000] ..s3 57.005940: mmc_blk_rw_end: cmd=18,addr=0x001d7ae8,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.006242: mmc_blk_rw_start: cmd=18,addr=0x001d8420,size=0x00000088
+ <idle>-0 [000] ..s3 57.006811: mmc_blk_rw_end: cmd=18,addr=0x001d8420,size=0x00000088
+ mmcqd/0-82 [000] ...1 57.014360: mmc_blk_rw_start: cmd=18,addr=0x00b88258,size=0x00000008
+ <idle>-0 [000] ..s3 57.014509: mmc_blk_rw_end: cmd=18,addr=0x00b88258,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.015519: mmc_blk_rw_start: cmd=18,addr=0x001d41c8,size=0x00000028
+ <idle>-0 [000] ..s3 57.015851: mmc_blk_rw_end: cmd=18,addr=0x001d41c8,size=0x00000028
+ mmcqd/0-82 [000] ...1 57.016743: mmc_blk_rw_start: cmd=18,addr=0x001d22d8,size=0x00000100
+ <idle>-0 [000] ..s3 57.017853: mmc_blk_rw_end: cmd=18,addr=0x001d22d8,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.018187: mmc_blk_rw_start: cmd=18,addr=0x001d3c30,size=0x00000040
+ <idle>-0 [000] ..s3 57.018535: mmc_blk_rw_end: cmd=18,addr=0x001d3c30,size=0x00000040
+ mmcqd/0-82 [000] ...1 57.019173: mmc_blk_rw_start: cmd=18,addr=0x001cdbd8,size=0x00000080
+ <idle>-0 [000] ..s3 57.019773: mmc_blk_rw_end: cmd=18,addr=0x001cdbd8,size=0x00000080
+ mmcqd/0-82 [000] ...1 57.020398: mmc_blk_rw_start: cmd=18,addr=0x001d4560,size=0x00000088
+ <idle>-0 [000] ..s3 57.020992: mmc_blk_rw_end: cmd=18,addr=0x001d4560,size=0x00000088
+ mmcqd/0-82 [000] ...1 57.022153: mmc_blk_rw_start: cmd=18,addr=0x001ced68,size=0x000000a0
+ <idle>-0 [000] ..s3 57.022895: mmc_blk_rw_end: cmd=18,addr=0x001ced68,size=0x000000a0
+ mmcqd/0-82 [000] ...1 57.023353: mmc_blk_rw_start: cmd=18,addr=0x001cca90,size=0x000000a0
+ <idle>-0 [000] ..s3 57.024100: mmc_blk_rw_end: cmd=18,addr=0x001cca90,size=0x000000a0
+ mmcqd/0-82 [000] ...1 57.025959: mmc_blk_rw_start: cmd=18,addr=0x00544ae0,size=0x00000098
+ <idle>-0 [000] ..s3 57.026594: mmc_blk_rw_end: cmd=18,addr=0x00544ae0,size=0x00000098
+ mmcqd/0-82 [000] ...1 57.027610: mmc_blk_rw_start: cmd=18,addr=0x001ce810,size=0x00000100
+ <idle>-0 [000] ..s3 57.028584: mmc_blk_rw_end: cmd=18,addr=0x001ce810,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.028628: mmc_blk_rw_start: cmd=18,addr=0x001cd008,size=0x00000098
+ <...>-1488 [000] ..s2 57.029283: mmc_blk_rw_end: cmd=18,addr=0x001cd008,size=0x00000098
+ mmcqd/0-82 [000] ...1 57.029304: mmc_blk_rw_start: cmd=18,addr=0x001cca80,size=0x00000010
+ <...>-1531 [000] ..s2 57.029488: mmc_blk_rw_end: cmd=18,addr=0x001cca80,size=0x00000010
+ mmcqd/0-82 [000] ...1 57.034193: mmc_blk_rw_start: cmd=18,addr=0x001ccd30,size=0x00000048
+ <idle>-0 [000] ..s3 57.034599: mmc_blk_rw_end: cmd=18,addr=0x001ccd30,size=0x00000048
+ mmcqd/0-82 [000] ...1 57.034644: mmc_blk_rw_start: cmd=18,addr=0x001d13b8,size=0x00000100
+ <idle>-0 [000] ..s3 57.035681: mmc_blk_rw_end: cmd=18,addr=0x001d13b8,size=0x00000100
+ mmcqd/0-82 [001] ...1 57.039204: mmc_blk_rw_start: cmd=18,addr=0x001cd680,size=0x00000090
+ <idle>-0 [000] ..s3 57.039835: mmc_blk_rw_end: cmd=18,addr=0x001cd680,size=0x00000090
+ mmcqd/0-82 [000] ...1 57.040145: mmc_blk_rw_start: cmd=18,addr=0x001d33a0,size=0x000000d8
+ <idle>-0 [000] ..s3 57.041015: mmc_blk_rw_end: cmd=18,addr=0x001d33a0,size=0x000000d8
+ mmcqd/0-82 [000] ...1 57.044216: mmc_blk_rw_start: cmd=25,addr=0x002c6530,size=0x00000048
+ <idle>-0 [000] ..s3 57.045285: mmc_blk_rw_end: cmd=25,addr=0x002c6530,size=0x00000048
+ mmcqd/0-82 [000] ...1 57.046053: mmc_blk_rw_start: cmd=25,addr=0x002c6578,size=0x00000008
+ <idle>-0 [000] ..s3 57.046113: mmc_blk_rw_end: cmd=25,addr=0x002c6578,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.046937: mmc_blk_rw_start: cmd=25,addr=0x002c6580,size=0x00000008
+ <idle>-0 [000] ..s3 57.046997: mmc_blk_rw_end: cmd=25,addr=0x002c6580,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.047945: mmc_blk_rw_start: cmd=25,addr=0x002c6588,size=0x00000030
+ <idle>-0 [000] ..s3 57.048141: mmc_blk_rw_end: cmd=25,addr=0x002c6588,size=0x00000030
+ mmcqd/0-82 [000] ...1 57.048855: mmc_blk_rw_start: cmd=25,addr=0x002c65b8,size=0x00000008
+ <idle>-0 [000] ..s3 57.048913: mmc_blk_rw_end: cmd=25,addr=0x002c65b8,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.049547: mmc_blk_rw_start: cmd=18,addr=0x001cead0,size=0x00000030
+ <idle>-0 [000] ..s3 57.049858: mmc_blk_rw_end: cmd=18,addr=0x001cead0,size=0x00000030
+ mmcqd/0-82 [000] ...1 57.050791: mmc_blk_rw_start: cmd=18,addr=0x001cd470,size=0x00000080
+ <idle>-0 [000] ..s3 57.051398: mmc_blk_rw_end: cmd=18,addr=0x001cd470,size=0x00000080
+ mmcqd/0-82 [000] ...1 57.054193: mmc_blk_rw_start: cmd=18,addr=0x00b88248,size=0x00000008
+ <...>-1488 [000] ..s2 57.054408: mmc_blk_rw_end: cmd=18,addr=0x00b88248,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.054487: mmc_blk_rw_start: cmd=18,addr=0x001ce1a0,size=0x00000090
+ <...>-1488 [000] ..s2 57.055128: mmc_blk_rw_end: cmd=18,addr=0x001ce1a0,size=0x00000090
+ mmcqd/0-82 [000] ...1 57.055512: mmc_blk_rw_start: cmd=18,addr=0x00b87298,size=0x00000008
+ <idle>-0 [000] ..s3 57.055640: mmc_blk_rw_end: cmd=18,addr=0x00b87298,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.055658: mmc_blk_rw_start: cmd=18,addr=0x00b91248,size=0x00000008
+ <idle>-0 [000] ..s3 57.055845: mmc_blk_rw_end: cmd=18,addr=0x00b91248,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.055894: mmc_blk_rw_start: cmd=18,addr=0x00b93138,size=0x00000008
+ <idle>-0 [000] ..s3 57.056031: mmc_blk_rw_end: cmd=18,addr=0x00b93138,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.056073: mmc_blk_rw_start: cmd=18,addr=0x001ce230,size=0x00000050
+ <...>-1488 [000] ..s2 57.056486: mmc_blk_rw_end: cmd=18,addr=0x001ce230,size=0x00000050
+ mmcqd/0-82 [000] ...1 57.056730: mmc_blk_rw_start: cmd=18,addr=0x00b93120,size=0x00000008
+ <idle>-0 [000] ..s3 57.056857: mmc_blk_rw_end: cmd=18,addr=0x00b93120,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.056946: mmc_blk_rw_start: cmd=18,addr=0x00b87290,size=0x00000008
+ <...>-1488 [000] ..s2 57.057066: mmc_blk_rw_end: cmd=18,addr=0x00b87290,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.057083: mmc_blk_rw_start: cmd=18,addr=0x00b88240,size=0x00000008
+ <...>-1488 [000] ..s3 57.057204: mmc_blk_rw_end: cmd=18,addr=0x00b88240,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.059204: mmc_blk_rw_start: cmd=18,addr=0x00544448,size=0x00000100
+ <idle>-0 [000] ..s3 57.060309: mmc_blk_rw_end: cmd=18,addr=0x00544448,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.060443: mmc_blk_rw_start: cmd=18,addr=0x001d53f8,size=0x00000028
+ <...>-1488 [000] ..s4 57.060791: mmc_blk_rw_end: cmd=18,addr=0x001d53f8,size=0x00000028
+ mmcqd/0-82 [000] ...1 57.061081: mmc_blk_rw_start: cmd=18,addr=0x001ced48,size=0x00000020
+ <idle>-0 [000] ..s3 57.061342: mmc_blk_rw_end: cmd=18,addr=0x001ced48,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.061580: mmc_blk_rw_start: cmd=18,addr=0x001ce668,size=0x00000100
+ <idle>-0 [000] ..s3 57.062605: mmc_blk_rw_end: cmd=18,addr=0x001ce668,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.062882: mmc_blk_rw_start: cmd=18,addr=0x001ce520,size=0x00000100
+ <idle>-0 [000] ..s3 57.063843: mmc_blk_rw_end: cmd=18,addr=0x001ce520,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.064177: mmc_blk_rw_start: cmd=25,addr=0x002c65c0,size=0x00000030
+ <...>-1488 [000] ..s2 57.064365: mmc_blk_rw_end: cmd=25,addr=0x002c65c0,size=0x00000030
+ mmcqd/0-82 [000] ...1 57.065042: mmc_blk_rw_start: cmd=25,addr=0x002c65f0,size=0x00000008
+ <...>-1488 [000] ..s3 57.065098: mmc_blk_rw_end: cmd=25,addr=0x002c65f0,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.066113: mmc_blk_rw_start: cmd=25,addr=0x002c65f8,size=0x00000030
+ <idle>-0 [000] .Ns3 57.066320: mmc_blk_rw_end: cmd=25,addr=0x002c65f8,size=0x00000030
+ mmcqd/0-82 [000] ...1 57.067085: mmc_blk_rw_start: cmd=25,addr=0x002c6628,size=0x00000008
+ <idle>-0 [000] ..s3 57.067144: mmc_blk_rw_end: cmd=25,addr=0x002c6628,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.067995: mmc_blk_rw_start: cmd=25,addr=0x00b98110,size=0x00000008
+ <idle>-0 [000] ..s3 57.068056: mmc_blk_rw_end: cmd=25,addr=0x00b98110,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.068894: mmc_blk_rw_start: cmd=25,addr=0x002c6630,size=0x00000020
+ <idle>-0 [000] ..s3 57.069029: mmc_blk_rw_end: cmd=25,addr=0x002c6630,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.069653: mmc_blk_rw_start: cmd=25,addr=0x002c6650,size=0x00000008
+ <idle>-0 [000] ..s3 57.069712: mmc_blk_rw_end: cmd=25,addr=0x002c6650,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.070613: mmc_blk_rw_start: cmd=25,addr=0x002c6658,size=0x00000030
+ <idle>-0 [000] ..s3 57.070798: mmc_blk_rw_end: cmd=25,addr=0x002c6658,size=0x00000030
+ mmcqd/0-82 [000] ...1 57.071612: mmc_blk_rw_start: cmd=25,addr=0x002c6688,size=0x00000008
+ <idle>-0 [000] ..s3 57.071670: mmc_blk_rw_end: cmd=25,addr=0x002c6688,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.072584: mmc_blk_rw_start: cmd=25,addr=0x00b98118,size=0x00000008
+ <idle>-0 [000] ..s3 57.072660: mmc_blk_rw_end: cmd=25,addr=0x00b98118,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.073492: mmc_blk_rw_start: cmd=25,addr=0x002c6690,size=0x00000020
+ <idle>-0 [000] ..s3 57.073643: mmc_blk_rw_end: cmd=25,addr=0x002c6690,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.074337: mmc_blk_rw_start: cmd=25,addr=0x002c66b0,size=0x00000008
+ <idle>-0 [000] ..s3 57.074413: mmc_blk_rw_end: cmd=25,addr=0x002c66b0,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.075439: mmc_blk_rw_start: cmd=25,addr=0x002c66b8,size=0x00000040
+ <idle>-0 [000] ..s3 57.075814: mmc_blk_rw_end: cmd=25,addr=0x002c66b8,size=0x00000040
+ mmcqd/0-82 [000] ...1 57.077220: mmc_blk_rw_start: cmd=25,addr=0x002c66f8,size=0x00000008
+ <idle>-0 [000] ..s3 57.077296: mmc_blk_rw_end: cmd=25,addr=0x002c66f8,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.078134: mmc_blk_rw_start: cmd=25,addr=0x002c6700,size=0x00000008
+ <idle>-0 [000] ..s3 57.078210: mmc_blk_rw_end: cmd=25,addr=0x002c6700,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.079207: mmc_blk_rw_start: cmd=18,addr=0x001cd810,size=0x000000b0
+ <idle>-0 [000] ..s3 57.079920: mmc_blk_rw_end: cmd=18,addr=0x001cd810,size=0x000000b0
+ mmcqd/0-82 [000] ...1 57.102577: mmc_blk_rw_start: cmd=18,addr=0x001d55a8,size=0x00000020
+ <idle>-0 [000] ..s3 57.102988: mmc_blk_rw_end: cmd=18,addr=0x001d55a8,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.105262: mmc_blk_rw_start: cmd=18,addr=0x00343b00,size=0x00000020
+ <...>-1488 [000] ..s2 57.105606: mmc_blk_rw_end: cmd=18,addr=0x00343b00,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.106150: mmc_blk_rw_start: cmd=18,addr=0x00b872a0,size=0x00000008
+ <...>-1488 [000] ..s2 57.106340: mmc_blk_rw_end: cmd=18,addr=0x00b872a0,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.106360: mmc_blk_rw_start: cmd=18,addr=0x00b912a0,size=0x00000008
+ <...>-1525 [000] ..s2 57.106549: mmc_blk_rw_end: cmd=18,addr=0x00b912a0,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.106745: mmc_blk_rw_start: cmd=18,addr=0x00343b78,size=0x00000008
+ <...>-1488 [000] ..s2 57.106876: mmc_blk_rw_end: cmd=18,addr=0x00343b78,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.107430: mmc_blk_rw_start: cmd=18,addr=0x00343b80,size=0x00000008
+ <...>-1488 [000] ..s2 57.107559: mmc_blk_rw_end: cmd=18,addr=0x00343b80,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.108843: mmc_blk_rw_start: cmd=18,addr=0x00343b20,size=0x00000040
+ <...>-1525 [000] ..s2 57.109237: mmc_blk_rw_end: cmd=18,addr=0x00343b20,size=0x00000040
+ mmcqd/0-82 [000] ...1 57.110414: mmc_blk_rw_start: cmd=18,addr=0x001cf530,size=0x00000030
+ <idle>-0 [000] ..s3 57.110809: mmc_blk_rw_end: cmd=18,addr=0x001cf530,size=0x00000030
+ mmcqd/0-82 [000] ...1 57.110880: mmc_blk_rw_start: cmd=18,addr=0x001cc028,size=0x00000100
+ <idle>-0 [000] ..s3 57.111960: mmc_blk_rw_end: cmd=18,addr=0x001cc028,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.112794: mmc_blk_rw_start: cmd=18,addr=0x001d14b8,size=0x00000100
+ <...>-1488 [000] ..s2 57.113838: mmc_blk_rw_end: cmd=18,addr=0x001d14b8,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.114825: mmc_blk_rw_start: cmd=18,addr=0x001d46e8,size=0x00000100
+ <...>-1488 [000] ..s2 57.115915: mmc_blk_rw_end: cmd=18,addr=0x001d46e8,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.115997: mmc_blk_rw_start: cmd=18,addr=0x001cd8c0,size=0x00000010
+ <...>-1488 [000] ..s3 57.116180: mmc_blk_rw_end: cmd=18,addr=0x001cd8c0,size=0x00000010
+ mmcqd/0-82 [000] ...1 57.119197: mmc_blk_rw_start: cmd=18,addr=0x00b91258,size=0x00000020
+ <...>-1529 [000] ..s2 57.119555: mmc_blk_rw_end: cmd=18,addr=0x00b91258,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.120544: mmc_blk_rw_start: cmd=18,addr=0x00b91250,size=0x00000008
+ <idle>-0 [000] .Ns4 57.120694: mmc_blk_rw_end: cmd=18,addr=0x00b91250,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.120710: mmc_blk_rw_start: cmd=18,addr=0x00b91360,size=0x00000018
+ <...>-1525 [000] ..s2 57.120911: mmc_blk_rw_end: cmd=18,addr=0x00b91360,size=0x00000018
+ mmcqd/0-82 [000] ...1 57.124398: mmc_blk_rw_start: cmd=18,addr=0x00b91278,size=0x00000010
+ <idle>-0 [000] ..s3 57.124605: mmc_blk_rw_end: cmd=18,addr=0x00b91278,size=0x00000010
+ mmcqd/0-82 [000] ...1 57.134837: mmc_blk_rw_start: cmd=18,addr=0x001d2840,size=0x00000100
+ <...>-1488 [000] ..s2 57.135881: mmc_blk_rw_end: cmd=18,addr=0x001d2840,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.138549: mmc_blk_rw_start: cmd=18,addr=0x001ce048,size=0x00000058
+ <...>-1523 [000] ..s2 57.139016: mmc_blk_rw_end: cmd=18,addr=0x001ce048,size=0x00000058
+ mmcqd/0-82 [000] ...1 57.139371: mmc_blk_rw_start: cmd=18,addr=0x001ce620,size=0x00000048
+ Binder_9-663 [000] ..s2 57.139720: mmc_blk_rw_end: cmd=18,addr=0x001ce620,size=0x00000048
+ mmcqd/0-82 [000] ...1 57.144191: mmc_blk_rw_start: cmd=18,addr=0x001d9468,size=0x000000d0
+ <idle>-0 [000] ..s3 57.145085: mmc_blk_rw_end: cmd=18,addr=0x001d9468,size=0x000000d0
+ mmcqd/0-82 [000] ...1 57.145455: mmc_blk_rw_start: cmd=18,addr=0x001d3f90,size=0x00000100
+ <idle>-0 [000] ..s3 57.146436: mmc_blk_rw_end: cmd=18,addr=0x001d3f90,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.146515: mmc_blk_rw_start: cmd=18,addr=0x001cdea0,size=0x000000a8
+ <idle>-0 [000] ..s3 57.147224: mmc_blk_rw_end: cmd=18,addr=0x001cdea0,size=0x000000a8
+ mmcqd/0-82 [000] ...1 57.152107: mmc_blk_rw_start: cmd=18,addr=0x005449a0,size=0x00000008
+ <...>-1488 [000] ..s2 57.152257: mmc_blk_rw_end: cmd=18,addr=0x005449a0,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.154192: mmc_blk_rw_start: cmd=18,addr=0x001d3040,size=0x00000100
+ <idle>-0 [000] ..s3 57.155162: mmc_blk_rw_end: cmd=18,addr=0x001d3040,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.162409: mmc_blk_rw_start: cmd=18,addr=0x0035a7e0,size=0x00000100
+ <...>-1488 [000] ..s2 57.163463: mmc_blk_rw_end: cmd=18,addr=0x0035a7e0,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.177438: mmc_blk_rw_start: cmd=18,addr=0x0013faa0,size=0x00000008
+ <idle>-0 [000] ..s3 57.177673: mmc_blk_rw_end: cmd=18,addr=0x0013faa0,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.204547: mmc_blk_rw_start: cmd=18,addr=0x001d9a88,size=0x00000100
+ <...>-1488 [000] ..s2 57.205593: mmc_blk_rw_end: cmd=18,addr=0x001d9a88,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.205939: mmc_blk_rw_start: cmd=18,addr=0x001d97d0,size=0x00000100
+ <...>-85 [000] ..s3 57.206922: mmc_blk_rw_end: cmd=18,addr=0x001d97d0,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.207744: mmc_blk_rw_start: cmd=18,addr=0x001d2780,size=0x000000a8
+ <idle>-0 [000] ..s3 57.208525: mmc_blk_rw_end: cmd=18,addr=0x001d2780,size=0x000000a8
+ mmcqd/0-82 [000] ...1 57.208869: mmc_blk_rw_start: cmd=18,addr=0x001d2940,size=0x00000100
+ <idle>-0 [000] ..s3 57.209819: mmc_blk_rw_end: cmd=18,addr=0x001d2940,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.209871: mmc_blk_rw_start: cmd=18,addr=0x001d2c78,size=0x00000100
+ <idle>-0 [000] ..s3 57.210890: mmc_blk_rw_end: cmd=18,addr=0x001d2c78,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.211390: mmc_blk_rw_start: cmd=18,addr=0x001d9ca8,size=0x00000078
+ <idle>-0 [000] ..s3 57.212014: mmc_blk_rw_end: cmd=18,addr=0x001d9ca8,size=0x00000078
+ mmcqd/0-82 [000] ...1 57.212429: mmc_blk_rw_start: cmd=18,addr=0x001d2a40,size=0x00000058
+ <idle>-0 [000] ..s3 57.212840: mmc_blk_rw_end: cmd=18,addr=0x001d2a40,size=0x00000058
+ mmcqd/0-82 [000] ...1 57.212887: mmc_blk_rw_start: cmd=18,addr=0x001d2b98,size=0x000000a0
+ <idle>-0 [000] ..s3 57.213629: mmc_blk_rw_end: cmd=18,addr=0x001d2b98,size=0x000000a0
+ mmcqd/0-82 [000] ...1 57.214172: mmc_blk_rw_start: cmd=18,addr=0x0013fe48,size=0x00000008
+ <idle>-0 [000] ..s3 57.214305: mmc_blk_rw_end: cmd=18,addr=0x0013fe48,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.214405: mmc_blk_rw_start: cmd=18,addr=0x001d2828,size=0x00000018
+ <...>-1488 [000] ..s2 57.214626: mmc_blk_rw_end: cmd=18,addr=0x001d2828,size=0x00000018
+ mmcqd/0-82 [000] ...1 57.214992: mmc_blk_rw_start: cmd=18,addr=0x001d98d0,size=0x00000100
+ <idle>-0 [000] ..s3 57.215970: mmc_blk_rw_end: cmd=18,addr=0x001d98d0,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.216111: mmc_blk_rw_start: cmd=18,addr=0x001d99d0,size=0x000000b8
+ <idle>-0 [000] .Ns3 57.216876: mmc_blk_rw_end: cmd=18,addr=0x001d99d0,size=0x000000b8
+ mmcqd/0-82 [001] ...1 57.217019: mmc_blk_rw_start: cmd=18,addr=0x001d9b88,size=0x00000020
+ <idle>-0 [000] ..s3 57.217344: mmc_blk_rw_end: cmd=18,addr=0x001d9b88,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.218411: mmc_blk_rw_start: cmd=18,addr=0x001d42f0,size=0x00000090
+ <idle>-0 [000] ..s3 57.219073: mmc_blk_rw_end: cmd=18,addr=0x001d42f0,size=0x00000090
+ mmcqd/0-82 [000] ...1 57.219314: mmc_blk_rw_start: cmd=18,addr=0x001d2ef0,size=0x000000b0
+ <idle>-0 [000] ..s3 57.220056: mmc_blk_rw_end: cmd=18,addr=0x001d2ef0,size=0x000000b0
+ mmcqd/0-82 [000] ...1 57.220313: mmc_blk_rw_start: cmd=18,addr=0x001d4380,size=0x000000e0
+ <idle>-0 [000] ..s3 57.221180: mmc_blk_rw_end: cmd=18,addr=0x001d4380,size=0x000000e0
+ mmcqd/0-82 [000] ...1 57.221384: mmc_blk_rw_start: cmd=18,addr=0x001d2fa0,size=0x000000a0
+ <idle>-0 [000] ..s3 57.222072: mmc_blk_rw_end: cmd=18,addr=0x001d2fa0,size=0x000000a0
+ mmcqd/0-82 [000] ...1 57.223422: mmc_blk_rw_start: cmd=18,addr=0x001cbf80,size=0x000000a8
+ <idle>-0 [000] ..s3 57.224200: mmc_blk_rw_end: cmd=18,addr=0x001cbf80,size=0x000000a8
+ mmcqd/0-82 [000] ...1 57.224509: mmc_blk_rw_start: cmd=18,addr=0x001d0098,size=0x00000100
+ <idle>-0 [000] ..s3 57.225557: mmc_blk_rw_end: cmd=18,addr=0x001d0098,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.225794: mmc_blk_rw_start: cmd=18,addr=0x001cff78,size=0x00000100
+ <idle>-0 [000] ..s3 57.226801: mmc_blk_rw_end: cmd=18,addr=0x001cff78,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.227092: mmc_blk_rw_start: cmd=18,addr=0x001d0078,size=0x00000020
+ <idle>-0 [000] ..s3 57.227402: mmc_blk_rw_end: cmd=18,addr=0x001d0078,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.227628: mmc_blk_rw_start: cmd=18,addr=0x001d9130,size=0x00000090
+ <idle>-0 [000] ..s3 57.228243: mmc_blk_rw_end: cmd=18,addr=0x001d9130,size=0x00000090
+ mmcqd/0-82 [000] ...1 57.228522: mmc_blk_rw_start: cmd=18,addr=0x001cf958,size=0x00000100
+ <idle>-0 [000] ..s3 57.229530: mmc_blk_rw_end: cmd=18,addr=0x001cf958,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.229794: mmc_blk_rw_start: cmd=18,addr=0x001d0288,size=0x000000d0
+ <idle>-0 [000] ..s3 57.230655: mmc_blk_rw_end: cmd=18,addr=0x001d0288,size=0x000000d0
+ mmcqd/0-82 [000] ...1 57.230854: mmc_blk_rw_start: cmd=18,addr=0x001cf7e0,size=0x00000070
+ <idle>-0 [000] ..s3 57.231357: mmc_blk_rw_end: cmd=18,addr=0x001cf7e0,size=0x00000070
+ mmcqd/0-82 [000] ...1 57.232991: mmc_blk_rw_start: cmd=18,addr=0x001d16d0,size=0x00000068
+ <idle>-0 [000] ..s3 57.233489: mmc_blk_rw_end: cmd=18,addr=0x001d16d0,size=0x00000068
+ mmcqd/0-82 [000] ...1 57.233879: mmc_blk_rw_start: cmd=18,addr=0x001cdc58,size=0x00000010
+ <idle>-0 [000] ..s3 57.234057: mmc_blk_rw_end: cmd=18,addr=0x001cdc58,size=0x00000010
+ mmcqd/0-82 [000] ...1 57.234417: mmc_blk_rw_start: cmd=18,addr=0x001d01a0,size=0x000000e8
+ <idle>-0 [000] ..s3 57.235343: mmc_blk_rw_end: cmd=18,addr=0x001d01a0,size=0x000000e8
+ mmcqd/0-82 [000] ...1 57.235572: mmc_blk_rw_start: cmd=18,addr=0x001d0578,size=0x000000d8
+ <idle>-0 [000] ..s3 57.236437: mmc_blk_rw_end: cmd=18,addr=0x001d0578,size=0x000000d8
+ mmcqd/0-82 [000] ...1 57.238214: mmc_blk_rw_start: cmd=18,addr=0x001cd1a0,size=0x000000c8
+ <idle>-0 [000] ..s3 57.239060: mmc_blk_rw_end: cmd=18,addr=0x001cd1a0,size=0x000000c8
+ mmcqd/0-82 [001] ...1 57.239429: mmc_blk_rw_start: cmd=18,addr=0x001cc8f0,size=0x00000090
+ <idle>-0 [000] ..s3 57.240094: mmc_blk_rw_end: cmd=18,addr=0x001cc8f0,size=0x00000090
+ mmcqd/0-82 [000] ...1 57.240493: mmc_blk_rw_start: cmd=18,addr=0x001d9008,size=0x00000100
+ <idle>-0 [000] ..s3 57.241469: mmc_blk_rw_end: cmd=18,addr=0x001d9008,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.243860: mmc_blk_rw_start: cmd=18,addr=0x001d1838,size=0x000000a0
+ <idle>-0 [000] ..s3 57.244560: mmc_blk_rw_end: cmd=18,addr=0x001d1838,size=0x000000a0
+ mmcqd/0-82 [000] ...1 57.245037: mmc_blk_rw_start: cmd=18,addr=0x001cd268,size=0x000000e0
+ <idle>-0 [000] ..s3 57.245971: mmc_blk_rw_end: cmd=18,addr=0x001cd268,size=0x000000e0
+ mmcqd/0-82 [000] ...1 57.246252: mmc_blk_rw_start: cmd=18,addr=0x001cddc8,size=0x000000d8
+ <idle>-0 [000] ..s3 57.247134: mmc_blk_rw_end: cmd=18,addr=0x001cddc8,size=0x000000d8
+ mmcqd/0-82 [000] ...1 57.247428: mmc_blk_rw_start: cmd=18,addr=0x001d4090,size=0x00000038
+ <idle>-0 [000] ..s3 57.247754: mmc_blk_rw_end: cmd=18,addr=0x001d4090,size=0x00000038
+ mmcqd/0-82 [000] ...1 57.247854: mmc_blk_rw_start: cmd=18,addr=0x001d0520,size=0x00000058
+ <idle>-0 [000] ..s3 57.248258: mmc_blk_rw_end: cmd=18,addr=0x001d0520,size=0x00000058
+ mmcqd/0-82 [000] ...1 57.248574: mmc_blk_rw_start: cmd=18,addr=0x001cfd08,size=0x000000e8
+ <idle>-0 [000] ..s3 57.249475: mmc_blk_rw_end: cmd=18,addr=0x001cfd08,size=0x000000e8
+ mmcqd/0-82 [000] ...1 57.249726: mmc_blk_rw_start: cmd=18,addr=0x001cfaa8,size=0x00000100
+ <idle>-0 [000] ..s3 57.250796: mmc_blk_rw_end: cmd=18,addr=0x001cfaa8,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.251114: mmc_blk_rw_start: cmd=18,addr=0x001cfba8,size=0x00000060
+ <idle>-0 [000] ..s3 57.251695: mmc_blk_rw_end: cmd=18,addr=0x001cfba8,size=0x00000060
+ mmcqd/0-82 [000] ...1 57.252516: mmc_blk_rw_start: cmd=18,addr=0x001cfdf0,size=0x00000100
+ <idle>-0 [000] ..s3 57.253564: mmc_blk_rw_end: cmd=18,addr=0x001cfdf0,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.253905: mmc_blk_rw_start: cmd=18,addr=0x001ce450,size=0x000000b0
+ <idle>-0 [000] ..s3 57.254612: mmc_blk_rw_end: cmd=18,addr=0x001ce450,size=0x000000b0
+ mmcqd/0-82 [000] ...1 57.255259: mmc_blk_rw_start: cmd=18,addr=0x001d0198,size=0x00000008
+ <idle>-0 [000] ..s3 57.255413: mmc_blk_rw_end: cmd=18,addr=0x001d0198,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.256613: mmc_blk_rw_start: cmd=18,addr=0x001d1f28,size=0x00000100
+ <idle>-0 [000] ..s3 57.257654: mmc_blk_rw_end: cmd=18,addr=0x001d1f28,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.259196: mmc_blk_rw_start: cmd=18,addr=0x0013fe08,size=0x00000040
+ <idle>-0 [000] ..s3 57.259737: mmc_blk_rw_end: cmd=18,addr=0x0013fe08,size=0x00000040
+ mmcqd/0-82 [000] ...1 57.259779: mmc_blk_rw_start: cmd=18,addr=0x0013fe50,size=0x00000018
+ <idle>-0 [000] ..s3 57.260033: mmc_blk_rw_end: cmd=18,addr=0x0013fe50,size=0x00000018
+ mmcqd/0-82 [000] ...1 57.260076: mmc_blk_rw_start: cmd=18,addr=0x001d0b78,size=0x00000100
+ <...>-1488 [000] ..s2 57.261095: mmc_blk_rw_end: cmd=18,addr=0x001d0b78,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.261370: mmc_blk_rw_start: cmd=18,addr=0x001d2c38,size=0x00000040
+ <...>-1488 [000] ..s2 57.261739: mmc_blk_rw_end: cmd=18,addr=0x001d2c38,size=0x00000040
+ mmcqd/0-82 [001] ...1 57.262839: mmc_blk_rw_start: cmd=18,addr=0x001d96c0,size=0x00000100
+ <...>-1488 [000] ..s2 57.263907: mmc_blk_rw_end: cmd=18,addr=0x001d96c0,size=0x00000100
+ mmcqd/0-82 [001] ...1 57.264945: mmc_blk_rw_start: cmd=18,addr=0x001d2440,size=0x00000100
+ <...>-1488 [000] ..s2 57.265992: mmc_blk_rw_end: cmd=18,addr=0x001d2440,size=0x00000100
+ mmcqd/0-82 [001] ...1 57.290040: mmc_blk_rw_start: cmd=18,addr=0x001d9678,size=0x00000048
+ <...>-1488 [000] ..s2 57.290472: mmc_blk_rw_end: cmd=18,addr=0x001d9678,size=0x00000048
+ mmcqd/0-82 [001] ...1 57.302592: mmc_blk_rw_start: cmd=18,addr=0x001cda70,size=0x00000068
+ <idle>-0 [000] ..s3 57.303140: mmc_blk_rw_end: cmd=18,addr=0x001cda70,size=0x00000068
+ mmcqd/0-82 [000] ...1 57.309317: mmc_blk_rw_start: cmd=18,addr=0x001d0a80,size=0x000000f8
+ <idle>-0 [000] ..s3 57.310291: mmc_blk_rw_end: cmd=18,addr=0x001d0a80,size=0x000000f8
+ mmcqd/0-82 [000] ...1 57.310613: mmc_blk_rw_start: cmd=18,addr=0x001d0df0,size=0x00000100
+ <idle>-0 [000] ..s3 57.311611: mmc_blk_rw_end: cmd=18,addr=0x001d0df0,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.311878: mmc_blk_rw_start: cmd=18,addr=0x001d0ef0,size=0x00000098
+ <idle>-0 [000] ..s3 57.312534: mmc_blk_rw_end: cmd=18,addr=0x001d0ef0,size=0x00000098
+ mmcqd/0-82 [000] ...1 57.315086: mmc_blk_rw_start: cmd=18,addr=0x001cfa58,size=0x00000050
+ <idle>-0 [000] ..s3 57.315561: mmc_blk_rw_end: cmd=18,addr=0x001cfa58,size=0x00000050
+ mmcqd/0-82 [000] ...1 57.316185: mmc_blk_rw_start: cmd=18,addr=0x001ce910,size=0x00000040
+ <...>-1523 [000] ..s2 57.316510: mmc_blk_rw_end: cmd=18,addr=0x001ce910,size=0x00000040
+ mmcqd/0-82 [000] ...1 57.319192: mmc_blk_rw_start: cmd=18,addr=0x001d0978,size=0x00000100
+ <idle>-0 [000] ..s3 57.320214: mmc_blk_rw_end: cmd=18,addr=0x001d0978,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.320264: mmc_blk_rw_start: cmd=18,addr=0x001d0c78,size=0x00000100
+ <...>-1523 [000] ..s2 57.321292: mmc_blk_rw_end: cmd=18,addr=0x001d0c78,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.323769: mmc_blk_rw_start: cmd=18,addr=0x001d2d78,size=0x00000078
+ <idle>-0 [000] ..s3 57.324361: mmc_blk_rw_end: cmd=18,addr=0x001d2d78,size=0x00000078
+ mmcqd/0-82 [000] ...1 57.327321: mmc_blk_rw_start: cmd=18,addr=0x001cc3d0,size=0x00000020
+ <...>-1523 [000] ..s2 57.327591: mmc_blk_rw_end: cmd=18,addr=0x001cc3d0,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.327617: mmc_blk_rw_start: cmd=18,addr=0x001cd5f0,size=0x00000090
+ <idle>-0 [000] ..s3 57.328264: mmc_blk_rw_end: cmd=18,addr=0x001cd5f0,size=0x00000090
+ mmcqd/0-82 [000] ...1 57.328300: mmc_blk_rw_start: cmd=18,addr=0x001ce500,size=0x00000020
+ <idle>-0 [000] ..s3 57.328518: mmc_blk_rw_end: cmd=18,addr=0x001ce500,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.371192: mmc_blk_rw_start: cmd=18,addr=0x001d2178,size=0x00000100
+ <...>-1488 [000] ..s2 57.372229: mmc_blk_rw_end: cmd=18,addr=0x001d2178,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.372428: mmc_blk_rw_start: cmd=18,addr=0x001d2278,size=0x00000060
+ <...>-1488 [000] ..s2 57.372913: mmc_blk_rw_end: cmd=18,addr=0x001d2278,size=0x00000060
+ mmcqd/0-82 [000] ...1 57.382172: mmc_blk_rw_start: cmd=18,addr=0x001d18d8,size=0x00000100
+ <...>-1547 [000] ..s2 57.383225: mmc_blk_rw_end: cmd=18,addr=0x001d18d8,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.391840: mmc_blk_rw_start: cmd=18,addr=0x001d1eb8,size=0x00000070
+ <...>-1488 [000] ..s2 57.392423: mmc_blk_rw_end: cmd=18,addr=0x001d1eb8,size=0x00000070
+ mmcqd/0-82 [000] ...1 57.394518: mmc_blk_rw_start: cmd=18,addr=0x00545750,size=0x00000100
+ <...>-1488 [000] ..s2 57.395564: mmc_blk_rw_end: cmd=18,addr=0x00545750,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.396101: mmc_blk_rw_start: cmd=18,addr=0x00545850,size=0x00000100
+ <...>-1545 [000] ..s2 57.397066: mmc_blk_rw_end: cmd=18,addr=0x00545850,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.397915: mmc_blk_rw_start: cmd=18,addr=0x00545950,size=0x00000100
+ Binder_A-669 [000] ..s2 57.398901: mmc_blk_rw_end: cmd=18,addr=0x00545950,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.429423: mmc_blk_rw_start: cmd=18,addr=0x00344700,size=0x00000020
+ <...>-1559 [000] ..s4 57.429771: mmc_blk_rw_end: cmd=18,addr=0x00344700,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.430206: mmc_blk_rw_start: cmd=18,addr=0x00344720,size=0x00000040
+ <...>-1559 [000] ..s4 57.430606: mmc_blk_rw_end: cmd=18,addr=0x00344720,size=0x00000040
+ mmcqd/0-82 [000] ...1 57.430705: mmc_blk_rw_start: cmd=18,addr=0x00344760,size=0x00000080
+ <...>-1559 [000] ..s3 57.431313: mmc_blk_rw_end: cmd=18,addr=0x00344760,size=0x00000080
+ mmcqd/0-82 [000] ...1 57.431392: mmc_blk_rw_start: cmd=18,addr=0x003447e0,size=0x00000020
+ <...>-1488 [000] ..s3 57.431645: mmc_blk_rw_end: cmd=18,addr=0x003447e0,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.434201: mmc_blk_rw_start: cmd=18,addr=0x00343f00,size=0x00000020
+ <...>-1488 [000] ..s2 57.434457: mmc_blk_rw_end: cmd=18,addr=0x00343f00,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.434904: mmc_blk_rw_start: cmd=18,addr=0x00b91298,size=0x00000008
+ <...>-1488 [000] ..s2 57.435094: mmc_blk_rw_end: cmd=18,addr=0x00b91298,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.435116: mmc_blk_rw_start: cmd=18,addr=0x00b914b0,size=0x00000010
+ <...>-1488 [000] ..s2 57.435277: mmc_blk_rw_end: cmd=18,addr=0x00b914b0,size=0x00000010
+ mmcqd/0-82 [000] ...1 57.436381: mmc_blk_rw_start: cmd=18,addr=0x00343f20,size=0x00000040
+ <...>-1488 [000] ..s2 57.436784: mmc_blk_rw_end: cmd=18,addr=0x00343f20,size=0x00000040
+ mmcqd/0-82 [000] ...1 57.436813: mmc_blk_rw_start: cmd=18,addr=0x00343f60,size=0x00000060
+ <...>-1488 [000] ..s2 57.437329: mmc_blk_rw_end: cmd=18,addr=0x00343f60,size=0x00000060
+ mmcqd/0-82 [000] ...1 57.439210: mmc_blk_rw_start: cmd=18,addr=0x001d0f88,size=0x00000098
+ <...>-1488 [000] ..s2 57.439983: mmc_blk_rw_end: cmd=18,addr=0x001d0f88,size=0x00000098
+ mmcqd/0-82 [000] ...1 57.458813: mmc_blk_rw_start: cmd=18,addr=0x00b912b0,size=0x00000020
+ <...>-1523 [000] ..s2 57.459127: mmc_blk_rw_end: cmd=18,addr=0x00b912b0,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.459557: mmc_blk_rw_start: cmd=18,addr=0x00b912a8,size=0x00000008
+ <...>-1557 [000] ..s2 57.459684: mmc_blk_rw_end: cmd=18,addr=0x00b912a8,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.459704: mmc_blk_rw_start: cmd=18,addr=0x001d6630,size=0x000000a0
+ <...>-1557 [000] ..s3 57.460432: mmc_blk_rw_end: cmd=18,addr=0x001d6630,size=0x000000a0
+ mmcqd/0-82 [000] ...1 57.460733: mmc_blk_rw_start: cmd=18,addr=0x001d3240,size=0x00000080
+ <...>-1557 [000] ..s2 57.461264: mmc_blk_rw_end: cmd=18,addr=0x001d3240,size=0x00000080
+ mmcqd/0-82 [000] ...1 57.464247: mmc_blk_rw_start: cmd=18,addr=0x00b912d0,size=0x00000010
+ <...>-1523 [000] ..s2 57.464441: mmc_blk_rw_end: cmd=18,addr=0x00b912d0,size=0x00000010
+ mmcqd/0-82 [000] ...1 57.464469: mmc_blk_rw_start: cmd=18,addr=0x00b912e8,size=0x00000020
+ <...>-1523 [000] ..s2 57.464789: mmc_blk_rw_end: cmd=18,addr=0x00b912e8,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.466611: mmc_blk_rw_start: cmd=18,addr=0x00b912e0,size=0x00000008
+ <...>-1523 [000] ..s2 57.466763: mmc_blk_rw_end: cmd=18,addr=0x00b912e0,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.485203: mmc_blk_rw_start: cmd=18,addr=0x00543ab8,size=0x00000100
+ <...>-1557 [000] ..s3 57.486350: mmc_blk_rw_end: cmd=18,addr=0x00543ab8,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.487748: mmc_blk_rw_start: cmd=18,addr=0x00543da8,size=0x00000100
+ <...>-1523 [000] ..s2 57.488841: mmc_blk_rw_end: cmd=18,addr=0x00543da8,size=0x00000100
+ mmcqd/0-82 [000] ...1 57.498275: mmc_blk_rw_start: cmd=18,addr=0x00543a20,size=0x00000098
+ Binder_2-130 [000] ..s2 57.499041: mmc_blk_rw_end: cmd=18,addr=0x00543a20,size=0x00000098
+ mmcqd/0-82 [000] ...1 57.515152: mmc_blk_rw_start: cmd=18,addr=0x001cd348,size=0x00000028
+ <...>-1559 [000] ..s2 57.515467: mmc_blk_rw_end: cmd=18,addr=0x001cd348,size=0x00000028
+ mmcqd/0-82 [000] ...1 57.516495: mmc_blk_rw_start: cmd=18,addr=0x001d92c0,size=0x00000010
+ <...>-1559 [000] ..s3 57.516782: mmc_blk_rw_end: cmd=18,addr=0x001d92c0,size=0x00000010
+ mmcqd/0-82 [000] ...1 57.555361: mmc_blk_rw_start: cmd=18,addr=0x001d0d78,size=0x00000078
+ <...>-1488 [000] ..s2 57.555949: mmc_blk_rw_end: cmd=18,addr=0x001d0d78,size=0x00000078
+ mmcqd/0-82 [000] ...1 57.556157: mmc_blk_rw_start: cmd=18,addr=0x001cfef0,size=0x00000088
+ Compiler-1495 [000] ..s3 57.556774: mmc_blk_rw_end: cmd=18,addr=0x001cfef0,size=0x00000088
+ mmcqd/0-82 [000] ...1 57.565912: mmc_blk_rw_start: cmd=18,addr=0x001d32c0,size=0x000000c8
+ <...>-1557 [000] ..s3 57.566737: mmc_blk_rw_end: cmd=18,addr=0x001d32c0,size=0x000000c8
+ mmcqd/0-82 [000] ...1 57.614954: mmc_blk_rw_start: cmd=18,addr=0x001d0840,size=0x00000080
+ <...>-1559 [000] ..s3 57.615517: mmc_blk_rw_end: cmd=18,addr=0x001d0840,size=0x00000080
+ mmcqd/0-82 [000] ...1 57.648037: mmc_blk_rw_start: cmd=18,addr=0x001d19d8,size=0x00000020
+ <...>-1559 [000] ..s2 57.648383: mmc_blk_rw_end: cmd=18,addr=0x001d19d8,size=0x00000020
+ mmcqd/0-82 [000] ...1 57.693082: mmc_blk_rw_start: cmd=25,addr=0x00b98120,size=0x00000008
+ <idle>-0 [000] ..s3 57.693171: mmc_blk_rw_end: cmd=25,addr=0x00b98120,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.708695: mmc_blk_rw_start: cmd=25,addr=0x00b98128,size=0x00000008
+ <...>-1541 [000] ..s2 57.708790: mmc_blk_rw_end: cmd=25,addr=0x00b98128,size=0x00000008
+ mmcqd/0-82 [000] ...1 57.714395: mmc_blk_rw_start: cmd=25,addr=0x002c6708,size=0x00000068
+ <...>-1541 [000] ..s4 57.715838: mmc_blk_rw_end: cmd=25,addr=0x002c6708,size=0x00000068
+ mmcqd/0-82 [000] ...1 57.717987: mmc_blk_rw_start: cmd=25,addr=0x002c6770,size=0x00000008
+ <...>-1541 [000] ..s2 57.718057: mmc_blk_rw_end: cmd=25,addr=0x002c6770,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.084817: mmc_blk_rw_start: cmd=18,addr=0x001d81e8,size=0x00000100
+ Compiler-387 [000] ..s2 58.086066: mmc_blk_rw_end: cmd=18,addr=0x001d81e8,size=0x00000100
+ mmcqd/0-82 [000] ...1 58.088028: mmc_blk_rw_start: cmd=18,addr=0x001d59c8,size=0x00000100
+ <idle>-0 [000] ..s3 58.089180: mmc_blk_rw_end: cmd=18,addr=0x001d59c8,size=0x00000100
+ mmcqd/0-82 [000] ...1 58.090030: mmc_blk_rw_start: cmd=18,addr=0x001d5ae0,size=0x00000100
+ <idle>-0 [000] ..s3 58.091133: mmc_blk_rw_end: cmd=18,addr=0x001d5ae0,size=0x00000100
+ mmcqd/0-82 [000] ...1 58.092466: mmc_blk_rw_start: cmd=18,addr=0x001d61d8,size=0x000000a0
+ <idle>-0 [000] ..s3 58.093289: mmc_blk_rw_end: cmd=18,addr=0x001d61d8,size=0x000000a0
+ mmcqd/0-82 [000] ...1 58.094858: mmc_blk_rw_start: cmd=18,addr=0x001d5e20,size=0x00000100
+ <idle>-0 [000] ..s3 58.095933: mmc_blk_rw_end: cmd=18,addr=0x001d5e20,size=0x00000100
+ mmcqd/0-82 [000] ...1 58.097221: mmc_blk_rw_start: cmd=18,addr=0x001d5ac8,size=0x00000018
+ <idle>-0 [000] ..s3 58.097634: mmc_blk_rw_end: cmd=18,addr=0x001d5ac8,size=0x00000018
+ mmcqd/0-82 [000] ...1 58.575553: mmc_blk_rw_start: cmd=25,addr=0x002c6778,size=0x00000058
+ <idle>-0 [000] ..s3 58.576045: mmc_blk_rw_end: cmd=25,addr=0x002c6778,size=0x00000058
+ mmcqd/0-82 [000] ...1 58.578793: mmc_blk_rw_start: cmd=25,addr=0x002c67d0,size=0x00000008
+ mmcqd/0-82 [000] ..s3 58.578935: mmc_blk_rw_end: cmd=25,addr=0x002c67d0,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.580809: mmc_blk_rw_start: cmd=25,addr=0x002c67d8,size=0x00000008
+ mmcqd/0-82 [000] ..s2 58.580958: mmc_blk_rw_end: cmd=25,addr=0x002c67d8,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.583739: mmc_blk_rw_start: cmd=25,addr=0x002c67e0,size=0x00000030
+ <idle>-0 [000] ..s3 58.584041: mmc_blk_rw_end: cmd=25,addr=0x002c67e0,size=0x00000030
+ mmcqd/0-82 [000] ...1 58.585137: mmc_blk_rw_start: cmd=25,addr=0x002c6810,size=0x00000008
+ kworker/0:2-48 [000] ..s3 58.585311: mmc_blk_rw_end: cmd=25,addr=0x002c6810,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.588080: mmc_blk_rw_start: cmd=18,addr=0x00b93130,size=0x00000008
+ <idle>-0 [000] ..s3 58.588375: mmc_blk_rw_end: cmd=18,addr=0x00b93130,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.589839: mmc_blk_rw_start: cmd=18,addr=0x00b93128,size=0x00000008
+ <idle>-0 [000] ..s4 58.590078: mmc_blk_rw_end: cmd=18,addr=0x00b93128,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.594680: mmc_blk_rw_start: cmd=25,addr=0x002c6818,size=0x00000038
+ <idle>-0 [000] ..s3 58.595009: mmc_blk_rw_end: cmd=25,addr=0x002c6818,size=0x00000038
+ mmcqd/0-82 [000] ...1 58.596248: mmc_blk_rw_start: cmd=25,addr=0x002c6850,size=0x00000008
+ mmcqd/0-82 [000] ..s2 58.596389: mmc_blk_rw_end: cmd=25,addr=0x002c6850,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.599773: mmc_blk_rw_start: cmd=25,addr=0x002c6858,size=0x00000030
+ <idle>-0 [000] ..s3 58.600194: mmc_blk_rw_end: cmd=25,addr=0x002c6858,size=0x00000030
+ mmcqd/0-82 [000] ...1 58.601507: mmc_blk_rw_start: cmd=25,addr=0x002c6888,size=0x00000008
+ kworker/0:2-48 [000] ..s4 58.601625: mmc_blk_rw_end: cmd=25,addr=0x002c6888,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.604459: mmc_blk_rw_start: cmd=25,addr=0x00b991f0,size=0x00000008
+ kworker/0:2-48 [000] ..s4 58.604654: mmc_blk_rw_end: cmd=25,addr=0x00b991f0,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.609374: mmc_blk_rw_start: cmd=25,addr=0x002c6890,size=0x00000020
+ <idle>-0 [000] ..s3 58.609576: mmc_blk_rw_end: cmd=25,addr=0x002c6890,size=0x00000020
+ mmcqd/0-82 [000] ...1 58.610551: mmc_blk_rw_start: cmd=25,addr=0x002c68b0,size=0x00000008
+ kworker/0:2-48 [000] ..s4 58.610669: mmc_blk_rw_end: cmd=25,addr=0x002c68b0,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.612541: mmc_blk_rw_start: cmd=25,addr=0x002c68b8,size=0x00000030
+ <idle>-0 [000] ..s3 58.612794: mmc_blk_rw_end: cmd=25,addr=0x002c68b8,size=0x00000030
+ mmcqd/0-82 [000] ...1 58.613930: mmc_blk_rw_start: cmd=25,addr=0x002c68e8,size=0x00000008
+ kworker/0:2-48 [000] ..s4 58.614049: mmc_blk_rw_end: cmd=25,addr=0x002c68e8,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.615695: mmc_blk_rw_start: cmd=25,addr=0x00b991f8,size=0x00000008
+ kworker/0:2-48 [000] ..s4 58.615817: mmc_blk_rw_end: cmd=25,addr=0x00b991f8,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.617071: mmc_blk_rw_start: cmd=25,addr=0x002c68f0,size=0x00000020
+ <idle>-0 [000] ..s3 58.617275: mmc_blk_rw_end: cmd=25,addr=0x002c68f0,size=0x00000020
+ mmcqd/0-82 [000] ...1 58.618373: mmc_blk_rw_start: cmd=25,addr=0x002c6910,size=0x00000008
+ <idle>-0 [000] ..s3 58.618571: mmc_blk_rw_end: cmd=25,addr=0x002c6910,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.621280: mmc_blk_rw_start: cmd=25,addr=0x002c6918,size=0x00000048
+ <idle>-0 [000] ..s3 58.621673: mmc_blk_rw_end: cmd=25,addr=0x002c6918,size=0x00000048
+ mmcqd/0-82 [000] ...1 58.622708: mmc_blk_rw_start: cmd=25,addr=0x002c6960,size=0x00000008
+ <idle>-0 [000] ..s3 58.622821: mmc_blk_rw_end: cmd=25,addr=0x002c6960,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.624060: mmc_blk_rw_start: cmd=25,addr=0x002c6968,size=0x00000008
+ <idle>-0 [000] ..s4 58.624249: mmc_blk_rw_end: cmd=25,addr=0x002c6968,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.724886: mmc_blk_rw_start: cmd=18,addr=0x005439a0,size=0x00000010
+ Binder_1-391 [000] ..s2 58.725161: mmc_blk_rw_end: cmd=18,addr=0x005439a0,size=0x00000010
+ mmcqd/0-82 [000] ...1 58.741803: mmc_blk_rw_start: cmd=18,addr=0x005474b8,size=0x00000008
+ Compiler-1495 [000] ..s3 58.742041: mmc_blk_rw_end: cmd=18,addr=0x005474b8,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.774047: mmc_blk_rw_start: cmd=18,addr=0x00b91398,size=0x00000018
+ <idle>-0 [000] ..s3 58.774338: mmc_blk_rw_end: cmd=18,addr=0x00b91398,size=0x00000018
+ mmcqd/0-82 [000] ...1 58.774417: mmc_blk_rw_start: cmd=18,addr=0x00b913c0,size=0x00000008
+ <...>-1563 [000] ..s2 58.774583: mmc_blk_rw_end: cmd=18,addr=0x00b913c0,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.778354: mmc_blk_rw_start: cmd=18,addr=0x00b913b0,size=0x00000010
+ <idle>-0 [000] .Ns3 58.778590: mmc_blk_rw_end: cmd=18,addr=0x00b913b0,size=0x00000010
+ mmcqd/0-82 [000] ...1 58.778749: mmc_blk_rw_start: cmd=18,addr=0x00b91390,size=0x00000008
+ mmcqd/0-82 [000] ..s4 58.778956: mmc_blk_rw_end: cmd=18,addr=0x00b91390,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.818682: mmc_blk_rw_start: cmd=18,addr=0x00b91438,size=0x00000008
+ <idle>-0 [000] ..s3 58.818842: mmc_blk_rw_end: cmd=18,addr=0x00b91438,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.821591: mmc_blk_rw_start: cmd=18,addr=0x00b91440,size=0x00000008
+ <idle>-0 [000] ..s3 58.821747: mmc_blk_rw_end: cmd=18,addr=0x00b91440,size=0x00000008
+ mmcqd/0-82 [000] ...1 58.821801: mmc_blk_rw_start: cmd=18,addr=0x00b91410,size=0x00000018
+ <idle>-0 [000] ..s3 58.822033: mmc_blk_rw_end: cmd=18,addr=0x00b91410,size=0x00000018
+ mmcqd/0-82 [000] ...1 58.824678: mmc_blk_rw_start: cmd=18,addr=0x00b91428,size=0x00000010
+ <idle>-0 [000] ..s3 58.824889: mmc_blk_rw_end: cmd=18,addr=0x00b91428,size=0x00000010
+ mmcqd/0-82 [000] ...1 58.824943: mmc_blk_rw_start: cmd=18,addr=0x00b91408,size=0x00000008
+ <idle>-0 [000] ..s3 58.825089: mmc_blk_rw_end: cmd=18,addr=0x00b91408,size=0x00000008
+ mmcqd/0-82 [000] ...1 59.707934: mmc_blk_rw_start: cmd=25,addr=0x00b99200,size=0x00000008
+ UI-395 [000] ..s2 59.708025: mmc_blk_rw_end: cmd=25,addr=0x00b99200,size=0x00000008
+ mmcqd/0-82 [000] ...1 59.709282: mmc_blk_rw_start: cmd=25,addr=0x002c6970,size=0x00000070
+ <idle>-0 [000] .Ns3 59.709727: mmc_blk_rw_end: cmd=25,addr=0x002c6970,size=0x00000070
+ mmcqd/0-82 [000] ...1 59.710588: mmc_blk_rw_start: cmd=25,addr=0x002c69e0,size=0x00000008
+ Binder_4-434 [000] ..s2 59.710645: mmc_blk_rw_end: cmd=25,addr=0x002c69e0,size=0x00000008
+ mmcqd/0-82 [000] ...1 59.714209: mmc_blk_rw_start: cmd=25,addr=0x00b99208,size=0x00000008
+ <...>-1541 [000] ..s2 59.714294: mmc_blk_rw_end: cmd=25,addr=0x00b99208,size=0x00000008
+ mmcqd/0-82 [000] ...1 59.721000: mmc_blk_rw_start: cmd=25,addr=0x002c69e8,size=0x00000050
+ adbd-1470 [000] ..s2 59.722370: mmc_blk_rw_end: cmd=25,addr=0x002c69e8,size=0x00000050
+ mmcqd/0-82 [000] ...1 59.725148: mmc_blk_rw_start: cmd=25,addr=0x002c6a38,size=0x00000008
+ <...>-1541 [000] .Ns3 59.725219: mmc_blk_rw_end: cmd=25,addr=0x002c6a38,size=0x00000008
+ mmcqd/0-82 [000] ...1 59.727335: mmc_blk_rw_start: cmd=25,addr=0x00b99210,size=0x00000008
+ UI-395 [000] ..s2 59.727424: mmc_blk_rw_end: cmd=25,addr=0x00b99210,size=0x00000008
+ mmcqd/0-82 [000] ...1 59.729033: mmc_blk_rw_start: cmd=25,addr=0x002c6a40,size=0x00000050
+ <...>-607 [000] ..s2 59.729377: mmc_blk_rw_end: cmd=25,addr=0x002c6a40,size=0x00000050
+ mmcqd/0-82 [000] ...1 59.731558: mmc_blk_rw_start: cmd=25,addr=0x002c6a90,size=0x00000008
+ <...>-1541 [000] ..s4 59.731617: mmc_blk_rw_end: cmd=25,addr=0x002c6a90,size=0x00000008
+ mmcqd/0-82 [000] ...1 59.792023: mmc_blk_rw_start: cmd=18,addr=0x001b9460,size=0x00000008
+ Binder_3-566 [000] ..s2 59.792250: mmc_blk_rw_end: cmd=18,addr=0x001b9460,size=0x00000008
+ mmcqd/0-82 [000] ...1 60.715097: mmc_blk_rw_start: cmd=18,addr=0x001cdd68,size=0x00000060
+ <idle>-0 [000] ..s3 60.715744: mmc_blk_rw_end: cmd=18,addr=0x001cdd68,size=0x00000060
+ mmcqd/0-82 [000] ...1 62.025279: mmc_blk_rw_start: cmd=18,addr=0x00346400,size=0x00000008
+ <idle>-0 [000] ..s4 62.025583: mmc_blk_rw_end: cmd=18,addr=0x00346400,size=0x00000008
+ mmcqd/0-82 [000] ...1 62.037473: mmc_blk_rw_start: cmd=18,addr=0x00b91460,size=0x00000010
+ <idle>-0 [000] ..s3 62.037922: mmc_blk_rw_end: cmd=18,addr=0x00b91460,size=0x00000010
+ mmcqd/0-82 [000] ...1 62.039874: mmc_blk_rw_start: cmd=18,addr=0x00347c00,size=0x00000018
+ <idle>-0 [000] ..s3 62.040414: mmc_blk_rw_end: cmd=18,addr=0x00347c00,size=0x00000018
+ mmcqd/0-82 [000] ...1 62.040972: mmc_blk_rw_start: cmd=18,addr=0x00b91470,size=0x00000010
+ <idle>-0 [000] ..s3 62.041143: mmc_blk_rw_end: cmd=18,addr=0x00b91470,size=0x00000010
+ mmcqd/0-82 [000] ...1 62.041491: mmc_blk_rw_start: cmd=18,addr=0x00b91480,size=0x00000010
+ <idle>-0 [000] ..s3 62.041660: mmc_blk_rw_end: cmd=18,addr=0x00b91480,size=0x00000010
+ mmcqd/0-82 [000] ...1 62.054430: mmc_blk_rw_start: cmd=25,addr=0x00542080,size=0x00000008
+ <idle>-0 [000] ..s3 62.054527: mmc_blk_rw_end: cmd=25,addr=0x00542080,size=0x00000008
+ mmcqd/0-82 [000] ...1 62.055112: mmc_blk_rw_start: cmd=25,addr=0x005420d0,size=0x00000010
+ <idle>-0 [000] ..s3 62.055225: mmc_blk_rw_end: cmd=25,addr=0x005420d0,size=0x00000010
+ mmcqd/0-82 [000] ...1 62.055726: mmc_blk_rw_start: cmd=25,addr=0x005420e8,size=0x00000008
+ mmcqd/0-82 [000] ..s3 62.055809: mmc_blk_rw_end: cmd=25,addr=0x005420e8,size=0x00000008
+ mmcqd/0-82 [000] ...1 62.056385: mmc_blk_rw_start: cmd=25,addr=0x00542108,size=0x00000020
+ <idle>-0 [000] .Ns3 62.056544: mmc_blk_rw_end: cmd=25,addr=0x00542108,size=0x00000020
+ mmcqd/0-82 [000] ...1 62.057231: mmc_blk_rw_start: cmd=25,addr=0x00542130,size=0x00000010
+ <idle>-0 [000] ..s3 62.057342: mmc_blk_rw_end: cmd=25,addr=0x00542130,size=0x00000010
+ mmcqd/0-82 [000] ...1 62.057850: mmc_blk_rw_start: cmd=25,addr=0x00543740,size=0x00000008
+ mmcqd/0-82 [000] ..s2 62.057929: mmc_blk_rw_end: cmd=25,addr=0x00543740,size=0x00000008
+ mmcqd/0-82 [000] ...1 62.058526: mmc_blk_rw_start: cmd=25,addr=0x00543760,size=0x00000008
+ <idle>-0 [000] ..s4 62.058609: mmc_blk_rw_end: cmd=25,addr=0x00543760,size=0x00000008
+ mmcqd/0-82 [000] ...1 62.059193: mmc_blk_rw_start: cmd=25,addr=0x005437b8,size=0x00000008
+ mmcqd/0-82 [000] ..s3 62.059274: mmc_blk_rw_end: cmd=25,addr=0x005437b8,size=0x00000008
+ mmcqd/0-82 [000] ...1 62.059876: mmc_blk_rw_start: cmd=25,addr=0x00544180,size=0x00000008
+ <idle>-0 [000] ..s4 62.059960: mmc_blk_rw_end: cmd=25,addr=0x00544180,size=0x00000008
+ mmcqd/0-82 [000] ...1 62.060559: mmc_blk_rw_start: cmd=25,addr=0x00544920,size=0x00000008
+ mmcqd/0-82 [000] ..s3 62.060638: mmc_blk_rw_end: cmd=25,addr=0x00544920,size=0x00000008
+ mmcqd/0-82 [000] ...1 62.061313: mmc_blk_rw_start: cmd=25,addr=0x00b98130,size=0x00000010
+ <idle>-0 [000] ..s3 62.061423: mmc_blk_rw_end: cmd=25,addr=0x00b98130,size=0x00000010
+ mmcqd/0-82 [000] ...1 64.790558: mmc_blk_rw_start: cmd=18,addr=0x001ae238,size=0x00000010
+ <idle>-0 [000] ..s3 64.790938: mmc_blk_rw_end: cmd=18,addr=0x001ae238,size=0x00000010
+ mmcqd/0-82 [000] ...1 64.839610: mmc_blk_rw_start: cmd=18,addr=0x0002a148,size=0x00000008
+ <idle>-0 [000] .Ns4 64.839860: mmc_blk_rw_end: cmd=18,addr=0x0002a148,size=0x00000008
+ mmcqd/0-82 [000] ...1 64.844165: mmc_blk_erase_start: cmd=3,addr=0x0002f0a8,size=0x0003af58
+ mmcqd/0-82 [000] ...1 64.855674: mmc_blk_erase_end: cmd=3,addr=0x0002f0a8,size=0x0003af58
+ mmcqd/0-82 [001] ...1 64.860452: mmc_blk_rw_start: cmd=18,addr=0x0006a148,size=0x00000008
+ <idle>-0 [000] ..s3 64.860624: mmc_blk_rw_end: cmd=18,addr=0x0006a148,size=0x00000008
+ mmcqd/0-82 [000] ...1 64.860873: mmc_blk_erase_start: cmd=3,addr=0x0006ae98,size=0x0003f168
+ mmcqd/0-82 [000] ...1 64.872976: mmc_blk_erase_end: cmd=3,addr=0x0006ae98,size=0x0003f168
+ mmcqd/0-82 [001] ...1 64.877698: mmc_blk_rw_start: cmd=18,addr=0x000aa000,size=0x00000008
+ <idle>-0 [000] ..s3 64.877871: mmc_blk_rw_end: cmd=18,addr=0x000aa000,size=0x00000008
+ mmcqd/0-82 [000] ...1 64.878114: mmc_blk_erase_start: cmd=3,addr=0x000ab010,size=0x0003eff0
+ mmcqd/0-82 [000] ...1 64.890188: mmc_blk_erase_end: cmd=3,addr=0x000ab010,size=0x0003eff0
+ mmcqd/0-82 [001] ...1 64.895271: mmc_blk_rw_start: cmd=18,addr=0x000ea148,size=0x00000008
+ <idle>-0 [000] ..s3 64.895441: mmc_blk_rw_end: cmd=18,addr=0x000ea148,size=0x00000008
+ mmcqd/0-82 [000] ...1 64.895691: mmc_blk_erase_start: cmd=3,addr=0x000eae90,size=0x0003f170
+ mmcqd/0-82 [000] ...1 64.907802: mmc_blk_erase_end: cmd=3,addr=0x000eae90,size=0x0003f170
+ mmcqd/0-82 [001] ...1 64.912733: mmc_blk_rw_start: cmd=18,addr=0x0012a000,size=0x00000008
+ <idle>-0 [000] ..s3 64.912903: mmc_blk_rw_end: cmd=18,addr=0x0012a000,size=0x00000008
+ mmcqd/0-82 [000] ...1 64.913123: mmc_blk_erase_start: cmd=3,addr=0x0012ad48,size=0x000072b8
+ mmcqd/0-82 [000] ...1 64.916366: mmc_blk_erase_end: cmd=3,addr=0x0012ad48,size=0x000072b8
+ mmcqd/0-82 [000] ...1 64.917057: mmc_blk_erase_start: cmd=3,addr=0x00308958,size=0x000006a8
+ mmcqd/0-82 [000] ...1 64.918223: mmc_blk_erase_end: cmd=3,addr=0x00308958,size=0x000006a8
+ mmcqd/0-82 [000] ...1 64.918307: mmc_blk_erase_start: cmd=3,addr=0x0030a1f0,size=0x00000610
+ mmcqd/0-82 [000] ...1 64.919345: mmc_blk_erase_end: cmd=3,addr=0x0030a1f0,size=0x00000610
+ mmcqd/0-82 [000] ...1 64.919426: mmc_blk_erase_start: cmd=3,addr=0x0030cb28,size=0x000004d8
+ mmcqd/0-82 [000] ...1 64.920372: mmc_blk_erase_end: cmd=3,addr=0x0030cb28,size=0x000004d8
+ mmcqd/0-82 [000] ...1 64.920445: mmc_blk_erase_start: cmd=3,addr=0x0030eb88,size=0x00000478
+ mmcqd/0-82 [000] ...1 64.921343: mmc_blk_erase_end: cmd=3,addr=0x0030eb88,size=0x00000478
+ mmcqd/0-82 [000] ...1 64.921414: mmc_blk_erase_start: cmd=3,addr=0x00310790,size=0x00000870
+ mmcqd/0-82 [000] ...1 64.922467: mmc_blk_erase_end: cmd=3,addr=0x00310790,size=0x00000870
+ mmcqd/0-82 [000] ...1 64.922556: mmc_blk_erase_start: cmd=3,addr=0x00311a88,size=0x00000578
+ mmcqd/0-82 [000] ...1 64.923503: mmc_blk_erase_end: cmd=3,addr=0x00311a88,size=0x00000578
+ mmcqd/0-82 [000] ...1 64.923581: mmc_blk_erase_start: cmd=3,addr=0x00317048,size=0x00002fb8
+ mmcqd/0-82 [000] ...1 64.925475: mmc_blk_erase_end: cmd=3,addr=0x00317048,size=0x00002fb8
+ mmcqd/0-82 [000] ...1 64.925765: mmc_blk_erase_start: cmd=3,addr=0x00347c18,size=0x00001108
+ mmcqd/0-82 [000] ...1 64.927235: mmc_blk_erase_end: cmd=3,addr=0x00347c18,size=0x00001108
+ mmcqd/0-82 [000] ...1 64.927364: mmc_blk_erase_start: cmd=3,addr=0x00349720,size=0x000005d0
+ mmcqd/0-82 [000] ...1 64.928362: mmc_blk_erase_end: cmd=3,addr=0x00349720,size=0x000005d0
+ mmcqd/0-82 [000] ...1 64.928439: mmc_blk_erase_start: cmd=3,addr=0x00349da0,size=0x000008b8
+ mmcqd/0-82 [000] ...1 64.930094: mmc_blk_erase_end: cmd=3,addr=0x00349da0,size=0x000008b8
+ mmcqd/0-82 [000] ...1 64.930184: mmc_blk_erase_start: cmd=3,addr=0x0034b000,size=0x00000b38
+ mmcqd/0-82 [000] ...1 64.931858: mmc_blk_erase_end: cmd=3,addr=0x0034b000,size=0x00000b38
+ mmcqd/0-82 [000] ...1 64.931961: mmc_blk_erase_start: cmd=3,addr=0x0034f000,size=0x00000c00
+ mmcqd/0-82 [000] ...1 64.933171: mmc_blk_erase_end: cmd=3,addr=0x0034f000,size=0x00000c00
+ mmcqd/0-82 [000] ...1 64.933280: mmc_blk_erase_start: cmd=3,addr=0x003510f8,size=0x00001dc0
+ mmcqd/0-82 [000] ...1 64.935361: mmc_blk_erase_end: cmd=3,addr=0x003510f8,size=0x00001dc0
+ mmcqd/0-82 [000] ...1 64.935545: mmc_blk_erase_start: cmd=3,addr=0x00352f78,size=0x00000690
+ mmcqd/0-82 [000] ...1 64.937124: mmc_blk_erase_end: cmd=3,addr=0x00352f78,size=0x00000690
+ mmcqd/0-82 [000] ...1 64.937204: mmc_blk_erase_start: cmd=3,addr=0x00357000,size=0x00001008
+ mmcqd/0-82 [000] ...1 64.938986: mmc_blk_erase_end: cmd=3,addr=0x00357000,size=0x00001008
+ mmcqd/0-82 [000] ...1 64.939146: mmc_blk_erase_start: cmd=3,addr=0x00358800,size=0x00001400
+ mmcqd/0-82 [000] ...1 64.940462: mmc_blk_erase_end: cmd=3,addr=0x00358800,size=0x00001400
+ mmcqd/0-82 [000] ...1 64.940608: mmc_blk_erase_start: cmd=3,addr=0x0035d000,size=0x00000a00
+ mmcqd/0-82 [000] ...1 64.941711: mmc_blk_erase_end: cmd=3,addr=0x0035d000,size=0x00000a00
+ mmcqd/0-82 [000] ...1 64.941808: mmc_blk_erase_start: cmd=3,addr=0x0035e528,size=0x00000ad8
+ mmcqd/0-82 [000] ...1 64.942915: mmc_blk_erase_end: cmd=3,addr=0x0035e528,size=0x00000ad8
+ mmcqd/0-82 [000] ...1 64.943014: mmc_blk_erase_start: cmd=3,addr=0x00360000,size=0x00000800
+ mmcqd/0-82 [000] ...1 64.944178: mmc_blk_erase_end: cmd=3,addr=0x00360000,size=0x00000800
+ mmcqd/0-82 [000] ...1 64.944265: mmc_blk_erase_start: cmd=3,addr=0x00360a70,size=0x00000590
+ mmcqd/0-82 [000] ...1 64.945257: mmc_blk_erase_end: cmd=3,addr=0x00360a70,size=0x00000590
+ mmcqd/0-82 [000] ...1 64.945337: mmc_blk_erase_start: cmd=3,addr=0x00361170,size=0x00008e90
+ mmcqd/0-82 [000] ...1 64.949162: mmc_blk_erase_end: cmd=3,addr=0x00361170,size=0x00008e90
+ mmcqd/0-82 [000] ...1 64.949868: mmc_blk_erase_start: cmd=3,addr=0x0036d448,size=0x00002bb8
+ mmcqd/0-82 [000] ...1 64.951650: mmc_blk_erase_end: cmd=3,addr=0x0036d448,size=0x00002bb8
+ mmcqd/0-82 [000] ...1 64.951901: mmc_blk_erase_start: cmd=3,addr=0x00372320,size=0x00000ce0
+ mmcqd/0-82 [000] ...1 64.953019: mmc_blk_erase_end: cmd=3,addr=0x00372320,size=0x00000ce0
+ mmcqd/0-82 [000] ...1 64.953130: mmc_blk_erase_start: cmd=3,addr=0x00374118,size=0x00000ee8
+ mmcqd/0-82 [000] ...1 64.954322: mmc_blk_erase_end: cmd=3,addr=0x00374118,size=0x00000ee8
+ mmcqd/0-82 [000] ...1 64.954446: mmc_blk_erase_start: cmd=3,addr=0x00375bd0,size=0x0000c430
+ mmcqd/0-82 [000] ...1 64.960104: mmc_blk_erase_end: cmd=3,addr=0x00375bd0,size=0x0000c430
+ mmcqd/0-82 [000] ...1 64.960996: mmc_blk_rw_start: cmd=18,addr=0x00383ac8,size=0x00000008
+ <idle>-0 [000] ..s3 64.961164: mmc_blk_rw_end: cmd=18,addr=0x00383ac8,size=0x00000008
+ mmcqd/0-82 [000] ...1 64.961360: mmc_blk_erase_start: cmd=3,addr=0x00384ae8,size=0x00000520
+ mmcqd/0-82 [000] ...1 64.962923: mmc_blk_erase_end: cmd=3,addr=0x00384ae8,size=0x00000520
+ mmcqd/0-82 [000] ...1 64.962990: mmc_blk_erase_start: cmd=3,addr=0x00385190,size=0x00006778
+ mmcqd/0-82 [000] ...1 64.966548: mmc_blk_erase_end: cmd=3,addr=0x00385190,size=0x00006778
+ mmcqd/0-82 [000] ...1 64.966996: mmc_blk_erase_start: cmd=3,addr=0x0038bec0,size=0x00022140
+ mmcqd/0-82 [000] ...1 64.979761: mmc_blk_erase_end: cmd=3,addr=0x0038bec0,size=0x00022140
+ mmcqd/0-82 [000] ...1 64.981889: mmc_blk_erase_start: cmd=3,addr=0x003b1808,size=0x000107f8
+ mmcqd/0-82 [000] ...1 64.988880: mmc_blk_erase_end: cmd=3,addr=0x003b1808,size=0x000107f8
+ mmcqd/0-82 [000] ...1 64.990030: mmc_blk_rw_start: cmd=18,addr=0x003c2000,size=0x00000008
+ <idle>-0 [000] ..s3 64.990196: mmc_blk_rw_end: cmd=18,addr=0x003c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 64.990399: mmc_blk_erase_start: cmd=3,addr=0x003c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.002436: mmc_blk_erase_end: cmd=3,addr=0x003c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.006530: mmc_blk_rw_start: cmd=18,addr=0x00403ac8,size=0x00000008
+ <idle>-0 [000] ..s3 65.006696: mmc_blk_rw_end: cmd=18,addr=0x00403ac8,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.006904: mmc_blk_erase_start: cmd=3,addr=0x00404ac0,size=0x0003d540
+ mmcqd/0-82 [000] ...1 65.018401: mmc_blk_erase_end: cmd=3,addr=0x00404ac0,size=0x0003d540
+ mmcqd/0-82 [000] ...1 65.022323: mmc_blk_rw_start: cmd=18,addr=0x00442000,size=0x00000008
+ <idle>-0 [000] ..s3 65.022490: mmc_blk_rw_end: cmd=18,addr=0x00442000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.022695: mmc_blk_erase_start: cmd=3,addr=0x00443000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 65.034731: mmc_blk_erase_end: cmd=3,addr=0x00443000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 65.038992: mmc_blk_rw_start: cmd=18,addr=0x00483ac8,size=0x00000008
+ <idle>-0 [000] ..s3 65.039163: mmc_blk_rw_end: cmd=18,addr=0x00483ac8,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.039441: mmc_blk_erase_start: cmd=3,addr=0x00484ac0,size=0x0003d540
+ mmcqd/0-82 [000] ...1 65.051022: mmc_blk_erase_end: cmd=3,addr=0x00484ac0,size=0x0003d540
+ mmcqd/0-82 [000] ...1 65.054504: mmc_blk_rw_start: cmd=18,addr=0x004c2000,size=0x00000008
+ <idle>-0 [000] ..s3 65.054666: mmc_blk_rw_end: cmd=18,addr=0x004c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.054850: mmc_blk_erase_start: cmd=3,addr=0x004c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.066849: mmc_blk_erase_end: cmd=3,addr=0x004c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.070240: mmc_blk_rw_start: cmd=18,addr=0x00503ac8,size=0x00000008
+ <idle>-0 [000] ..s3 65.070402: mmc_blk_rw_end: cmd=18,addr=0x00503ac8,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.070586: mmc_blk_erase_start: cmd=3,addr=0x00504ac0,size=0x0003d540
+ mmcqd/0-82 [000] ...1 65.082108: mmc_blk_erase_end: cmd=3,addr=0x00504ac0,size=0x0003d540
+ mmcqd/0-82 [000] ...1 65.085540: mmc_blk_rw_start: cmd=18,addr=0x00542000,size=0x00000008
+ <idle>-0 [000] ..s3 65.085704: mmc_blk_rw_end: cmd=18,addr=0x00542000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.085878: mmc_blk_erase_start: cmd=3,addr=0x00546158,size=0x00001360
+ mmcqd/0-82 [000] ...1 65.087692: mmc_blk_erase_end: cmd=3,addr=0x00546158,size=0x00001360
+ mmcqd/0-82 [000] ...1 65.087792: mmc_blk_erase_start: cmd=3,addr=0x005477b0,size=0x00000950
+ mmcqd/0-82 [000] ...1 65.088834: mmc_blk_erase_end: cmd=3,addr=0x005477b0,size=0x00000950
+ mmcqd/0-82 [000] ...1 65.088915: mmc_blk_erase_start: cmd=3,addr=0x00548268,size=0x00039d98
+ mmcqd/0-82 [000] ...1 65.099331: mmc_blk_erase_end: cmd=3,addr=0x00548268,size=0x00039d98
+ mmcqd/0-82 [000] ...1 65.102484: mmc_blk_rw_start: cmd=18,addr=0x00582000,size=0x00000008
+ <idle>-0 [000] ..s3 65.102697: mmc_blk_rw_end: cmd=18,addr=0x00582000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.102950: mmc_blk_erase_start: cmd=3,addr=0x00584008,size=0x00000ff8
+ mmcqd/0-82 [000] ...1 65.104144: mmc_blk_erase_end: cmd=3,addr=0x00584008,size=0x00000ff8
+ mmcqd/0-82 [000] ...1 65.104234: mmc_blk_erase_start: cmd=3,addr=0x005856b8,size=0x00000948
+ mmcqd/0-82 [000] ...1 65.105273: mmc_blk_erase_end: cmd=3,addr=0x005856b8,size=0x00000948
+ mmcqd/0-82 [000] ...1 65.105341: mmc_blk_erase_start: cmd=3,addr=0x005866c0,size=0x00000e30
+ mmcqd/0-82 [000] ...1 65.106438: mmc_blk_erase_end: cmd=3,addr=0x005866c0,size=0x00000e30
+ mmcqd/0-82 [000] ...1 65.106524: mmc_blk_erase_start: cmd=3,addr=0x00587508,size=0x00000800
+ mmcqd/0-82 [000] ...1 65.108103: mmc_blk_erase_end: cmd=3,addr=0x00587508,size=0x00000800
+ mmcqd/0-82 [000] ...1 65.108179: mmc_blk_erase_start: cmd=3,addr=0x00587d68,size=0x0003a298
+ mmcqd/0-82 [000] ...1 65.118631: mmc_blk_erase_end: cmd=3,addr=0x00587d68,size=0x0003a298
+ mmcqd/0-82 [000] ...1 65.121820: mmc_blk_rw_start: cmd=18,addr=0x005c2000,size=0x00000008
+ <idle>-0 [000] ..s3 65.121982: mmc_blk_rw_end: cmd=18,addr=0x005c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.122166: mmc_blk_erase_start: cmd=3,addr=0x005c3000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 65.134174: mmc_blk_erase_end: cmd=3,addr=0x005c3000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 65.137513: mmc_blk_rw_start: cmd=18,addr=0x00602000,size=0x00000008
+ <idle>-0 [000] ..s3 65.137675: mmc_blk_rw_end: cmd=18,addr=0x00602000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.137858: mmc_blk_erase_start: cmd=3,addr=0x00602ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.149874: mmc_blk_erase_end: cmd=3,addr=0x00602ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.153212: mmc_blk_rw_start: cmd=18,addr=0x00642000,size=0x00000008
+ <idle>-0 [000] ..s3 65.153374: mmc_blk_rw_end: cmd=18,addr=0x00642000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.153556: mmc_blk_erase_start: cmd=3,addr=0x00642ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.165578: mmc_blk_erase_end: cmd=3,addr=0x00642ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.169139: mmc_blk_rw_start: cmd=18,addr=0x00682000,size=0x00000008
+ <idle>-0 [000] ..s3 65.169302: mmc_blk_rw_end: cmd=18,addr=0x00682000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.169483: mmc_blk_erase_start: cmd=3,addr=0x00682ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.181507: mmc_blk_erase_end: cmd=3,addr=0x00682ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.185105: mmc_blk_rw_start: cmd=18,addr=0x006c2000,size=0x00000008
+ <idle>-0 [000] ..s3 65.185267: mmc_blk_rw_end: cmd=18,addr=0x006c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.185450: mmc_blk_erase_start: cmd=3,addr=0x006c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.204743: mmc_blk_erase_end: cmd=3,addr=0x006c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.208326: mmc_blk_rw_start: cmd=18,addr=0x00702000,size=0x00000008
+ <idle>-0 [000] ..s3 65.208489: mmc_blk_rw_end: cmd=18,addr=0x00702000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.208671: mmc_blk_erase_start: cmd=3,addr=0x00703180,size=0x0003ee80
+ mmcqd/0-82 [000] ...1 65.220673: mmc_blk_erase_end: cmd=3,addr=0x00703180,size=0x0003ee80
+ mmcqd/0-82 [000] ...1 65.224277: mmc_blk_rw_start: cmd=18,addr=0x00742000,size=0x00000008
+ <idle>-0 [000] ..s3 65.224440: mmc_blk_rw_end: cmd=18,addr=0x00742000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.224623: mmc_blk_erase_start: cmd=3,addr=0x00743098,size=0x0003ef68
+ mmcqd/0-82 [000] ...1 65.236666: mmc_blk_erase_end: cmd=3,addr=0x00743098,size=0x0003ef68
+ mmcqd/0-82 [000] ...1 65.240177: mmc_blk_rw_start: cmd=18,addr=0x00782000,size=0x00000008
+ <idle>-0 [000] ..s3 65.240340: mmc_blk_rw_end: cmd=18,addr=0x00782000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.240521: mmc_blk_erase_start: cmd=3,addr=0x00783000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 65.252559: mmc_blk_erase_end: cmd=3,addr=0x00783000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 65.256080: mmc_blk_rw_start: cmd=18,addr=0x007c2000,size=0x00000008
+ <idle>-0 [000] ..s3 65.256241: mmc_blk_rw_end: cmd=18,addr=0x007c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.256423: mmc_blk_erase_start: cmd=3,addr=0x007c30d0,size=0x0003ef30
+ mmcqd/0-82 [000] ...1 65.268445: mmc_blk_erase_end: cmd=3,addr=0x007c30d0,size=0x0003ef30
+ mmcqd/0-82 [000] ...1 65.271804: mmc_blk_rw_start: cmd=18,addr=0x00802000,size=0x00000008
+ <idle>-0 [000] ..s3 65.271968: mmc_blk_rw_end: cmd=18,addr=0x00802000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.272151: mmc_blk_erase_start: cmd=3,addr=0x00803010,size=0x0003eff0
+ mmcqd/0-82 [000] ...1 65.284198: mmc_blk_erase_end: cmd=3,addr=0x00803010,size=0x0003eff0
+ mmcqd/0-82 [000] ...1 65.287616: mmc_blk_rw_start: cmd=18,addr=0x00842000,size=0x00000008
+ <idle>-0 [000] ..s3 65.287778: mmc_blk_rw_end: cmd=18,addr=0x00842000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.287959: mmc_blk_erase_start: cmd=3,addr=0x00842ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.299984: mmc_blk_erase_end: cmd=3,addr=0x00842ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.303613: mmc_blk_rw_start: cmd=18,addr=0x00882000,size=0x00000008
+ <idle>-0 [000] ..s3 65.303775: mmc_blk_rw_end: cmd=18,addr=0x00882000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.303957: mmc_blk_erase_start: cmd=3,addr=0x00882ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.316036: mmc_blk_erase_end: cmd=3,addr=0x00882ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.319544: mmc_blk_rw_start: cmd=18,addr=0x008c2000,size=0x00000008
+ <idle>-0 [000] ..s3 65.319756: mmc_blk_rw_end: cmd=18,addr=0x008c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.320008: mmc_blk_erase_start: cmd=3,addr=0x008c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.332066: mmc_blk_erase_end: cmd=3,addr=0x008c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.335494: mmc_blk_rw_start: cmd=18,addr=0x00903ac8,size=0x00000008
+ <idle>-0 [000] ..s3 65.335656: mmc_blk_rw_end: cmd=18,addr=0x00903ac8,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.335841: mmc_blk_erase_start: cmd=3,addr=0x00904ac0,size=0x0003d540
+ mmcqd/0-82 [000] ...1 65.347297: mmc_blk_erase_end: cmd=3,addr=0x00904ac0,size=0x0003d540
+ mmcqd/0-82 [000] ...1 65.350772: mmc_blk_rw_start: cmd=18,addr=0x00942000,size=0x00000008
+ <idle>-0 [000] ..s3 65.350934: mmc_blk_rw_end: cmd=18,addr=0x00942000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.351115: mmc_blk_erase_start: cmd=3,addr=0x00942ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.363095: mmc_blk_erase_end: cmd=3,addr=0x00942ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.366656: mmc_blk_rw_start: cmd=18,addr=0x00983ac8,size=0x00000008
+ <idle>-0 [000] ..s3 65.366818: mmc_blk_rw_end: cmd=18,addr=0x00983ac8,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.366999: mmc_blk_erase_start: cmd=3,addr=0x00984ac0,size=0x0003d540
+ mmcqd/0-82 [000] ...1 65.378413: mmc_blk_erase_end: cmd=3,addr=0x00984ac0,size=0x0003d540
+ mmcqd/0-82 [000] ...1 65.381966: mmc_blk_rw_start: cmd=18,addr=0x009c2000,size=0x00000008
+ <idle>-0 [000] ..s3 65.382127: mmc_blk_rw_end: cmd=18,addr=0x009c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.382310: mmc_blk_erase_start: cmd=3,addr=0x009c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.394379: mmc_blk_erase_end: cmd=3,addr=0x009c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.397815: mmc_blk_rw_start: cmd=18,addr=0x00a02000,size=0x00000008
+ <idle>-0 [000] ..s3 65.397978: mmc_blk_rw_end: cmd=18,addr=0x00a02000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.398162: mmc_blk_erase_start: cmd=3,addr=0x00a02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.410211: mmc_blk_erase_end: cmd=3,addr=0x00a02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.413546: mmc_blk_rw_start: cmd=18,addr=0x00a42000,size=0x00000008
+ <idle>-0 [000] ..s3 65.413708: mmc_blk_rw_end: cmd=18,addr=0x00a42000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.413888: mmc_blk_erase_start: cmd=3,addr=0x00a42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.425781: mmc_blk_erase_end: cmd=3,addr=0x00a42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.429337: mmc_blk_rw_start: cmd=18,addr=0x00a82000,size=0x00000008
+ <idle>-0 [000] ..s3 65.429499: mmc_blk_rw_end: cmd=18,addr=0x00a82000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.429680: mmc_blk_erase_start: cmd=3,addr=0x00a82ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.441736: mmc_blk_erase_end: cmd=3,addr=0x00a82ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.445303: mmc_blk_rw_start: cmd=18,addr=0x00ac2000,size=0x00000008
+ <idle>-0 [000] ..s3 65.445465: mmc_blk_rw_end: cmd=18,addr=0x00ac2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.445648: mmc_blk_erase_start: cmd=3,addr=0x00ac2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.457715: mmc_blk_erase_end: cmd=3,addr=0x00ac2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.461193: mmc_blk_rw_start: cmd=18,addr=0x00b02000,size=0x00000008
+ <idle>-0 [000] ..s3 65.461405: mmc_blk_rw_end: cmd=18,addr=0x00b02000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.461664: mmc_blk_erase_start: cmd=3,addr=0x00b02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.473758: mmc_blk_erase_end: cmd=3,addr=0x00b02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.477284: mmc_blk_erase_start: cmd=3,addr=0x00b43010,size=0x0003eff0
+ mmcqd/0-82 [000] ...1 65.489346: mmc_blk_erase_end: cmd=3,addr=0x00b43010,size=0x0003eff0
+ mmcqd/0-82 [000] ...1 65.492611: mmc_blk_erase_start: cmd=3,addr=0x00b83100,size=0x00000f00
+ mmcqd/0-82 [000] ...1 65.493769: mmc_blk_erase_end: cmd=3,addr=0x00b83100,size=0x00000f00
+ mmcqd/0-82 [000] ...1 65.493857: mmc_blk_erase_start: cmd=3,addr=0x00b85c30,size=0x00000480
+ mmcqd/0-82 [000] ...1 65.494702: mmc_blk_erase_end: cmd=3,addr=0x00b85c30,size=0x00000480
+ mmcqd/0-82 [000] ...1 65.494754: mmc_blk_erase_start: cmd=3,addr=0x00b86160,size=0x00000fa0
+ mmcqd/0-82 [000] ...1 65.495904: mmc_blk_erase_end: cmd=3,addr=0x00b86160,size=0x00000fa0
+ mmcqd/0-82 [000] ...1 65.495991: mmc_blk_erase_start: cmd=3,addr=0x00b872a8,size=0x00000e00
+ mmcqd/0-82 [000] ...1 65.497626: mmc_blk_erase_end: cmd=3,addr=0x00b872a8,size=0x00000e00
+ mmcqd/0-82 [000] ...1 65.497708: mmc_blk_erase_start: cmd=3,addr=0x00b88278,size=0x00001078
+ mmcqd/0-82 [000] ...1 65.498870: mmc_blk_erase_end: cmd=3,addr=0x00b88278,size=0x00001078
+ mmcqd/0-82 [000] ...1 65.498961: mmc_blk_erase_start: cmd=3,addr=0x00b89320,size=0x000016e8
+ mmcqd/0-82 [000] ...1 65.500863: mmc_blk_erase_end: cmd=3,addr=0x00b89320,size=0x000016e8
+ mmcqd/0-82 [000] ...1 65.500975: mmc_blk_erase_start: cmd=3,addr=0x00b8aa28,size=0x00000660
+ mmcqd/0-82 [000] ...1 65.502494: mmc_blk_erase_end: cmd=3,addr=0x00b8aa28,size=0x00000660
+ mmcqd/0-82 [000] ...1 65.502552: mmc_blk_erase_start: cmd=3,addr=0x00b8b108,size=0x00000f60
+ mmcqd/0-82 [000] ...1 65.504262: mmc_blk_erase_end: cmd=3,addr=0x00b8b108,size=0x00000f60
+ mmcqd/0-82 [000] ...1 65.504350: mmc_blk_erase_start: cmd=3,addr=0x00b8c138,size=0x00000f88
+ mmcqd/0-82 [000] ...1 65.505501: mmc_blk_erase_end: cmd=3,addr=0x00b8c138,size=0x00000f88
+ mmcqd/0-82 [000] ...1 65.505588: mmc_blk_erase_start: cmd=3,addr=0x00b8d0e0,size=0x00000fd0
+ mmcqd/0-82 [000] ...1 65.506685: mmc_blk_erase_end: cmd=3,addr=0x00b8d0e0,size=0x00000fd0
+ mmcqd/0-82 [000] ...1 65.506776: mmc_blk_erase_start: cmd=3,addr=0x00b8e0f8,size=0x00000f70
+ mmcqd/0-82 [000] ...1 65.508408: mmc_blk_erase_end: cmd=3,addr=0x00b8e0f8,size=0x00000f70
+ mmcqd/0-82 [000] ...1 65.508496: mmc_blk_erase_start: cmd=3,addr=0x00b8f070,size=0x00001770
+ mmcqd/0-82 [000] ...1 65.509835: mmc_blk_erase_end: cmd=3,addr=0x00b8f070,size=0x00001770
+ mmcqd/0-82 [000] ...1 65.509946: mmc_blk_erase_start: cmd=3,addr=0x00b907f0,size=0x00000870
+ mmcqd/0-82 [000] ...1 65.510983: mmc_blk_erase_end: cmd=3,addr=0x00b907f0,size=0x00000870
+ mmcqd/0-82 [000] ...1 65.511048: mmc_blk_erase_start: cmd=3,addr=0x00b914c0,size=0x00000d28
+ mmcqd/0-82 [000] ...1 65.512622: mmc_blk_erase_end: cmd=3,addr=0x00b914c0,size=0x00000d28
+ mmcqd/0-82 [000] ...1 65.512701: mmc_blk_erase_start: cmd=3,addr=0x00b921f0,size=0x00000e88
+ mmcqd/0-82 [000] ...1 65.514392: mmc_blk_erase_end: cmd=3,addr=0x00b921f0,size=0x00000e88
+ mmcqd/0-82 [000] ...1 65.514482: mmc_blk_erase_start: cmd=3,addr=0x00b930d0,size=0x00000fd8
+ mmcqd/0-82 [000] ...1 65.516232: mmc_blk_erase_end: cmd=3,addr=0x00b930d0,size=0x00000fd8
+ mmcqd/0-82 [000] ...1 65.516320: mmc_blk_erase_start: cmd=3,addr=0x00b940e0,size=0x00001048
+ mmcqd/0-82 [000] ...1 65.518068: mmc_blk_erase_end: cmd=3,addr=0x00b940e0,size=0x00001048
+ mmcqd/0-82 [000] ...1 65.518158: mmc_blk_erase_start: cmd=3,addr=0x00b95130,size=0x00000fa8
+ mmcqd/0-82 [000] ...1 65.519867: mmc_blk_erase_end: cmd=3,addr=0x00b95130,size=0x00000fa8
+ mmcqd/0-82 [000] ...1 65.519954: mmc_blk_erase_start: cmd=3,addr=0x00b962e0,size=0x000004b8
+ mmcqd/0-82 [000] ...1 65.521465: mmc_blk_erase_end: cmd=3,addr=0x00b962e0,size=0x000004b8
+ mmcqd/0-82 [000] ...1 65.521517: mmc_blk_erase_start: cmd=3,addr=0x00b96840,size=0x000008f0
+ mmcqd/0-82 [000] ...1 65.522552: mmc_blk_erase_end: cmd=3,addr=0x00b96840,size=0x000008f0
+ mmcqd/0-82 [000] ...1 65.522618: mmc_blk_erase_start: cmd=3,addr=0x00b97458,size=0x00000ba8
+ mmcqd/0-82 [000] ...1 65.523659: mmc_blk_erase_end: cmd=3,addr=0x00b97458,size=0x00000ba8
+ mmcqd/0-82 [000] ...1 65.523745: mmc_blk_erase_start: cmd=3,addr=0x00b9a000,size=0x00028000
+ mmcqd/0-82 [000] ...1 65.528268: mmc_blk_erase_end: cmd=3,addr=0x00b9a000,size=0x00028000
+ mmcqd/0-82 [000] ...1 65.530508: mmc_blk_rw_start: cmd=18,addr=0x00bc2000,size=0x00000008
+ <idle>-0 [000] ..s3 65.530669: mmc_blk_rw_end: cmd=18,addr=0x00bc2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.530852: mmc_blk_erase_start: cmd=3,addr=0x00bc2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.542925: mmc_blk_erase_end: cmd=3,addr=0x00bc2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.546510: mmc_blk_rw_start: cmd=18,addr=0x00c02000,size=0x00000008
+ <idle>-0 [000] ..s3 65.546673: mmc_blk_rw_end: cmd=18,addr=0x00c02000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.546729: mmc_blk_rw_start: cmd=25,addr=0x002c6a98,size=0x00000058
+ <idle>-0 [000] ..s3 65.547168: mmc_blk_rw_end: cmd=25,addr=0x002c6a98,size=0x00000058
+ mmcqd/0-82 [000] ...1 65.547855: mmc_blk_rw_start: cmd=25,addr=0x002c6af0,size=0x00000008
+ <idle>-0 [000] ..s3 65.547938: mmc_blk_rw_end: cmd=25,addr=0x002c6af0,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.548643: mmc_blk_erase_start: cmd=3,addr=0x00c02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.560697: mmc_blk_erase_end: cmd=3,addr=0x00c02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.564290: mmc_blk_rw_start: cmd=18,addr=0x00c42000,size=0x00000008
+ <idle>-0 [000] ..s3 65.564452: mmc_blk_rw_end: cmd=18,addr=0x00c42000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.564635: mmc_blk_erase_start: cmd=3,addr=0x00c42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.576689: mmc_blk_erase_end: cmd=3,addr=0x00c42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.580050: mmc_blk_rw_start: cmd=18,addr=0x00c82000,size=0x00000008
+ <idle>-0 [000] ..s3 65.580211: mmc_blk_rw_end: cmd=18,addr=0x00c82000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.580392: mmc_blk_erase_start: cmd=3,addr=0x00c82ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.593009: mmc_blk_erase_end: cmd=3,addr=0x00c82ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.596373: mmc_blk_rw_start: cmd=18,addr=0x00cc2000,size=0x00000008
+ <idle>-0 [000] ..s3 65.596537: mmc_blk_rw_end: cmd=18,addr=0x00cc2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.596719: mmc_blk_erase_start: cmd=3,addr=0x00cc3000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 65.609463: mmc_blk_erase_end: cmd=3,addr=0x00cc3000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 65.612802: mmc_blk_rw_start: cmd=18,addr=0x00d02000,size=0x00000008
+ <idle>-0 [000] ..s3 65.612963: mmc_blk_rw_end: cmd=18,addr=0x00d02000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.613147: mmc_blk_erase_start: cmd=3,addr=0x00d02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.625991: mmc_blk_erase_end: cmd=3,addr=0x00d02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.629539: mmc_blk_rw_start: cmd=18,addr=0x00d42000,size=0x00000008
+ <idle>-0 [000] ..s3 65.629700: mmc_blk_rw_end: cmd=18,addr=0x00d42000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.629879: mmc_blk_erase_start: cmd=3,addr=0x00d42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.642728: mmc_blk_erase_end: cmd=3,addr=0x00d42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.646085: mmc_blk_rw_start: cmd=18,addr=0x00d82000,size=0x00000008
+ <idle>-0 [000] ..s3 65.646246: mmc_blk_rw_end: cmd=18,addr=0x00d82000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.646428: mmc_blk_erase_start: cmd=3,addr=0x00d82ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.659272: mmc_blk_erase_end: cmd=3,addr=0x00d82ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.662916: mmc_blk_rw_start: cmd=18,addr=0x00dc2000,size=0x00000008
+ <idle>-0 [000] ..s3 65.663083: mmc_blk_rw_end: cmd=18,addr=0x00dc2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.663297: mmc_blk_erase_start: cmd=3,addr=0x00dc2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.676145: mmc_blk_erase_end: cmd=3,addr=0x00dc2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.679765: mmc_blk_rw_start: cmd=18,addr=0x00e02000,size=0x00000008
+ <idle>-0 [000] ..s3 65.679928: mmc_blk_rw_end: cmd=18,addr=0x00e02000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.680119: mmc_blk_erase_start: cmd=3,addr=0x00e02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.692956: mmc_blk_erase_end: cmd=3,addr=0x00e02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.696314: mmc_blk_rw_start: cmd=18,addr=0x00e42000,size=0x00000008
+ <idle>-0 [000] ..s3 65.696476: mmc_blk_rw_end: cmd=18,addr=0x00e42000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.696658: mmc_blk_erase_start: cmd=3,addr=0x00e42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.709458: mmc_blk_erase_end: cmd=3,addr=0x00e42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.712997: mmc_blk_rw_start: cmd=18,addr=0x00e82000,size=0x00000008
+ <idle>-0 [000] ..s3 65.713159: mmc_blk_rw_end: cmd=18,addr=0x00e82000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.713339: mmc_blk_erase_start: cmd=3,addr=0x00e82ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.726167: mmc_blk_erase_end: cmd=3,addr=0x00e82ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.729808: mmc_blk_rw_start: cmd=18,addr=0x00ec2000,size=0x00000008
+ <idle>-0 [000] ..s3 65.729969: mmc_blk_rw_end: cmd=18,addr=0x00ec2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.730151: mmc_blk_erase_start: cmd=3,addr=0x00ec2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.742962: mmc_blk_erase_end: cmd=3,addr=0x00ec2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.746523: mmc_blk_rw_start: cmd=18,addr=0x00f03ac8,size=0x00000008
+ <idle>-0 [000] ..s3 65.746736: mmc_blk_rw_end: cmd=18,addr=0x00f03ac8,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.746997: mmc_blk_erase_start: cmd=3,addr=0x00f04ac0,size=0x0003d540
+ mmcqd/0-82 [000] ...1 65.759333: mmc_blk_erase_end: cmd=3,addr=0x00f04ac0,size=0x0003d540
+ mmcqd/0-82 [000] ...1 65.762585: mmc_blk_rw_start: cmd=18,addr=0x00f42000,size=0x00000008
+ <idle>-0 [000] ..s3 65.762746: mmc_blk_rw_end: cmd=18,addr=0x00f42000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.762928: mmc_blk_erase_start: cmd=3,addr=0x00f42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.775775: mmc_blk_erase_end: cmd=3,addr=0x00f42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.779190: mmc_blk_rw_start: cmd=18,addr=0x00f82000,size=0x00000008
+ <idle>-0 [000] ..s3 65.779354: mmc_blk_rw_end: cmd=18,addr=0x00f82000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.779536: mmc_blk_erase_start: cmd=3,addr=0x00f83008,size=0x0003eff8
+ mmcqd/0-82 [000] ...1 65.792334: mmc_blk_erase_end: cmd=3,addr=0x00f83008,size=0x0003eff8
+ mmcqd/0-82 [000] ...1 65.795718: mmc_blk_rw_start: cmd=18,addr=0x00fc2000,size=0x00000008
+ <idle>-0 [000] ..s3 65.795880: mmc_blk_rw_end: cmd=18,addr=0x00fc2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.796061: mmc_blk_erase_start: cmd=3,addr=0x00fc3010,size=0x0003eff0
+ mmcqd/0-82 [000] ...1 65.808910: mmc_blk_erase_end: cmd=3,addr=0x00fc3010,size=0x0003eff0
+ mmcqd/0-82 [000] ...1 65.812397: mmc_blk_rw_start: cmd=18,addr=0x01002000,size=0x00000008
+ <idle>-0 [000] ..s3 65.812559: mmc_blk_rw_end: cmd=18,addr=0x01002000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.812741: mmc_blk_erase_start: cmd=3,addr=0x01002ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.825541: mmc_blk_erase_end: cmd=3,addr=0x01002ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.828878: mmc_blk_rw_start: cmd=18,addr=0x01042000,size=0x00000008
+ <idle>-0 [000] ..s3 65.829040: mmc_blk_rw_end: cmd=18,addr=0x01042000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.829243: mmc_blk_erase_start: cmd=3,addr=0x01042ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.848483: mmc_blk_erase_end: cmd=3,addr=0x01042ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.852064: mmc_blk_rw_start: cmd=18,addr=0x01082000,size=0x00000008
+ <idle>-0 [000] ..s3 65.852225: mmc_blk_rw_end: cmd=18,addr=0x01082000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.852405: mmc_blk_erase_start: cmd=3,addr=0x01082ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.865241: mmc_blk_erase_end: cmd=3,addr=0x01082ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.868741: mmc_blk_rw_start: cmd=18,addr=0x010c2000,size=0x00000008
+ <idle>-0 [000] ..s3 65.868903: mmc_blk_rw_end: cmd=18,addr=0x010c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.869104: mmc_blk_erase_start: cmd=3,addr=0x010c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.881967: mmc_blk_erase_end: cmd=3,addr=0x010c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.885518: mmc_blk_rw_start: cmd=18,addr=0x01102000,size=0x00000008
+ <idle>-0 [000] ..s3 65.885679: mmc_blk_rw_end: cmd=18,addr=0x01102000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.885861: mmc_blk_erase_start: cmd=3,addr=0x01102ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.898719: mmc_blk_erase_end: cmd=3,addr=0x01102ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.902088: mmc_blk_rw_start: cmd=18,addr=0x01142000,size=0x00000008
+ <idle>-0 [000] ..s3 65.902250: mmc_blk_rw_end: cmd=18,addr=0x01142000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.902431: mmc_blk_erase_start: cmd=3,addr=0x01142ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.915275: mmc_blk_erase_end: cmd=3,addr=0x01142ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.918619: mmc_blk_rw_start: cmd=18,addr=0x01182000,size=0x00000008
+ <idle>-0 [000] ..s3 65.918781: mmc_blk_rw_end: cmd=18,addr=0x01182000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.918963: mmc_blk_erase_start: cmd=3,addr=0x01182ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.931861: mmc_blk_erase_end: cmd=3,addr=0x01182ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.935374: mmc_blk_rw_start: cmd=18,addr=0x011c2000,size=0x00000008
+ <idle>-0 [000] ..s3 65.935536: mmc_blk_rw_end: cmd=18,addr=0x011c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.935718: mmc_blk_erase_start: cmd=3,addr=0x011c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.948584: mmc_blk_erase_end: cmd=3,addr=0x011c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.952113: mmc_blk_rw_start: cmd=18,addr=0x01202000,size=0x00000008
+ <idle>-0 [000] ..s3 65.952275: mmc_blk_rw_end: cmd=18,addr=0x01202000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.952457: mmc_blk_erase_start: cmd=3,addr=0x01202ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.965256: mmc_blk_erase_end: cmd=3,addr=0x01202ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.968807: mmc_blk_rw_start: cmd=18,addr=0x01242000,size=0x00000008
+ <idle>-0 [000] ..s3 65.968969: mmc_blk_rw_end: cmd=18,addr=0x01242000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.969174: mmc_blk_erase_start: cmd=3,addr=0x01242ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.982055: mmc_blk_erase_end: cmd=3,addr=0x01242ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.985654: mmc_blk_rw_start: cmd=18,addr=0x01282000,size=0x00000008
+ <idle>-0 [000] ..s3 65.985816: mmc_blk_rw_end: cmd=18,addr=0x01282000,size=0x00000008
+ mmcqd/0-82 [000] ...1 65.985994: mmc_blk_erase_start: cmd=3,addr=0x01282ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 65.998829: mmc_blk_erase_end: cmd=3,addr=0x01282ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.002211: mmc_blk_rw_start: cmd=18,addr=0x012c2000,size=0x00000008
+ <idle>-0 [000] ..s3 66.002372: mmc_blk_rw_end: cmd=18,addr=0x012c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.002549: mmc_blk_erase_start: cmd=3,addr=0x012c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.015395: mmc_blk_erase_end: cmd=3,addr=0x012c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.018738: mmc_blk_rw_start: cmd=18,addr=0x01302000,size=0x00000008
+ <idle>-0 [000] ..s3 66.018899: mmc_blk_rw_end: cmd=18,addr=0x01302000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.019109: mmc_blk_erase_start: cmd=3,addr=0x01302ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.031822: mmc_blk_erase_end: cmd=3,addr=0x01302ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.035182: mmc_blk_rw_start: cmd=18,addr=0x01342000,size=0x00000008
+ <idle>-0 [000] ..s3 66.035344: mmc_blk_rw_end: cmd=18,addr=0x01342000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.035526: mmc_blk_erase_start: cmd=3,addr=0x01342ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.048386: mmc_blk_erase_end: cmd=3,addr=0x01342ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.051777: mmc_blk_rw_start: cmd=18,addr=0x01382000,size=0x00000008
+ <idle>-0 [000] ..s3 66.051938: mmc_blk_rw_end: cmd=18,addr=0x01382000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.052119: mmc_blk_erase_start: cmd=3,addr=0x01382ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.064933: mmc_blk_erase_end: cmd=3,addr=0x01382ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.068266: mmc_blk_rw_start: cmd=18,addr=0x013c2000,size=0x00000008
+ <idle>-0 [000] ..s3 66.068428: mmc_blk_rw_end: cmd=18,addr=0x013c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.068610: mmc_blk_erase_start: cmd=3,addr=0x013c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.081409: mmc_blk_erase_end: cmd=3,addr=0x013c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.084838: mmc_blk_rw_start: cmd=18,addr=0x01402000,size=0x00000008
+ <idle>-0 [000] ..s3 66.085004: mmc_blk_rw_end: cmd=18,addr=0x01402000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.085192: mmc_blk_erase_start: cmd=3,addr=0x01403000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 66.097986: mmc_blk_erase_end: cmd=3,addr=0x01403000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 66.101443: mmc_blk_rw_start: cmd=18,addr=0x01442000,size=0x00000008
+ <idle>-0 [000] ..s3 66.101605: mmc_blk_rw_end: cmd=18,addr=0x01442000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.101787: mmc_blk_erase_start: cmd=3,addr=0x01442ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.114633: mmc_blk_erase_end: cmd=3,addr=0x01442ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.118042: mmc_blk_rw_start: cmd=18,addr=0x01482000,size=0x00000008
+ <idle>-0 [000] ..s3 66.118204: mmc_blk_rw_end: cmd=18,addr=0x01482000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.118386: mmc_blk_erase_start: cmd=3,addr=0x01482ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.131232: mmc_blk_erase_end: cmd=3,addr=0x01482ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.134684: mmc_blk_rw_start: cmd=18,addr=0x014c2000,size=0x00000008
+ <idle>-0 [000] ..s3 66.134845: mmc_blk_rw_end: cmd=18,addr=0x014c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.135026: mmc_blk_erase_start: cmd=3,addr=0x014c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.147837: mmc_blk_erase_end: cmd=3,addr=0x014c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.151424: mmc_blk_rw_start: cmd=18,addr=0x01502000,size=0x00000008
+ <idle>-0 [000] ..s3 66.151586: mmc_blk_rw_end: cmd=18,addr=0x01502000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.151768: mmc_blk_erase_start: cmd=3,addr=0x01502ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.164628: mmc_blk_erase_end: cmd=3,addr=0x01502ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.167964: mmc_blk_rw_start: cmd=18,addr=0x01542000,size=0x00000008
+ <idle>-0 [000] ..s3 66.168125: mmc_blk_rw_end: cmd=18,addr=0x01542000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.168300: mmc_blk_erase_start: cmd=3,addr=0x01542ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.181084: mmc_blk_erase_end: cmd=3,addr=0x01542ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.184504: mmc_blk_rw_start: cmd=18,addr=0x01582000,size=0x00000008
+ <idle>-0 [000] ..s3 66.184666: mmc_blk_rw_end: cmd=18,addr=0x01582000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.184837: mmc_blk_erase_start: cmd=3,addr=0x01582ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.197739: mmc_blk_erase_end: cmd=3,addr=0x01582ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.201126: mmc_blk_erase_start: cmd=3,addr=0x015c3008,size=0x0003eff8
+ mmcqd/0-82 [000] ...1 66.213978: mmc_blk_erase_end: cmd=3,addr=0x015c3008,size=0x0003eff8
+ mmcqd/0-82 [000] ...1 66.217400: mmc_blk_rw_start: cmd=18,addr=0x01602000,size=0x00000008
+ <idle>-0 [000] ..s3 66.217565: mmc_blk_rw_end: cmd=18,addr=0x01602000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.217746: mmc_blk_erase_start: cmd=3,addr=0x01603000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 66.230570: mmc_blk_erase_end: cmd=3,addr=0x01603000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 66.233942: mmc_blk_rw_start: cmd=18,addr=0x01642000,size=0x00000008
+ <idle>-0 [000] ..s3 66.234107: mmc_blk_rw_end: cmd=18,addr=0x01642000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.234290: mmc_blk_erase_start: cmd=3,addr=0x01642ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.247107: mmc_blk_erase_end: cmd=3,addr=0x01642ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.250616: mmc_blk_rw_start: cmd=18,addr=0x01682000,size=0x00000008
+ <idle>-0 [000] ..s3 66.250778: mmc_blk_rw_end: cmd=18,addr=0x01682000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.250962: mmc_blk_erase_start: cmd=3,addr=0x01682ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.263787: mmc_blk_erase_end: cmd=3,addr=0x01682ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.267219: mmc_blk_rw_start: cmd=18,addr=0x016c2000,size=0x00000008
+ <idle>-0 [000] ..s3 66.267380: mmc_blk_rw_end: cmd=18,addr=0x016c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.267561: mmc_blk_erase_start: cmd=3,addr=0x016c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.280363: mmc_blk_erase_end: cmd=3,addr=0x016c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.283772: mmc_blk_rw_start: cmd=18,addr=0x01703ac8,size=0x00000008
+ <idle>-0 [000] ..s3 66.283934: mmc_blk_rw_end: cmd=18,addr=0x01703ac8,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.284146: mmc_blk_erase_start: cmd=3,addr=0x01704ac0,size=0x0003d540
+ mmcqd/0-82 [000] ...1 66.296455: mmc_blk_erase_end: cmd=3,addr=0x01704ac0,size=0x0003d540
+ mmcqd/0-82 [000] ...1 66.299826: mmc_blk_rw_start: cmd=18,addr=0x01742000,size=0x00000008
+ <idle>-0 [000] ..s3 66.299991: mmc_blk_rw_end: cmd=18,addr=0x01742000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.300172: mmc_blk_erase_start: cmd=3,addr=0x01743000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 66.313018: mmc_blk_erase_end: cmd=3,addr=0x01743000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 66.316476: mmc_blk_rw_start: cmd=18,addr=0x01782000,size=0x00000008
+ <idle>-0 [000] ..s3 66.316641: mmc_blk_rw_end: cmd=18,addr=0x01782000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.316869: mmc_blk_erase_start: cmd=3,addr=0x01783000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 66.329795: mmc_blk_erase_end: cmd=3,addr=0x01783000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 66.333305: mmc_blk_rw_start: cmd=18,addr=0x017c2000,size=0x00000008
+ <idle>-0 [000] ..s3 66.333470: mmc_blk_rw_end: cmd=18,addr=0x017c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.333653: mmc_blk_erase_start: cmd=3,addr=0x017c3000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 66.346485: mmc_blk_erase_end: cmd=3,addr=0x017c3000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 66.349946: mmc_blk_rw_start: cmd=18,addr=0x01802000,size=0x00000008
+ <idle>-0 [000] ..s3 66.350111: mmc_blk_rw_end: cmd=18,addr=0x01802000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.350294: mmc_blk_erase_start: cmd=3,addr=0x01803020,size=0x0003efe0
+ mmcqd/0-82 [000] ...1 66.363089: mmc_blk_erase_end: cmd=3,addr=0x01803020,size=0x0003efe0
+ mmcqd/0-82 [000] ...1 66.366450: mmc_blk_rw_start: cmd=18,addr=0x01842000,size=0x00000008
+ <idle>-0 [000] ..s3 66.366611: mmc_blk_rw_end: cmd=18,addr=0x01842000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.366793: mmc_blk_erase_start: cmd=3,addr=0x01842ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.379653: mmc_blk_erase_end: cmd=3,addr=0x01842ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.382987: mmc_blk_rw_start: cmd=18,addr=0x01882000,size=0x00000008
+ <idle>-0 [000] ..s3 66.383152: mmc_blk_rw_end: cmd=18,addr=0x01882000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.383334: mmc_blk_erase_start: cmd=3,addr=0x01883000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 66.396156: mmc_blk_erase_end: cmd=3,addr=0x01883000,size=0x0003f000
+ mmcqd/0-82 [000] ...1 66.399533: mmc_blk_rw_start: cmd=18,addr=0x018c2000,size=0x00000008
+ <idle>-0 [000] ..s3 66.399695: mmc_blk_rw_end: cmd=18,addr=0x018c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.399877: mmc_blk_erase_start: cmd=3,addr=0x018c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.412722: mmc_blk_erase_end: cmd=3,addr=0x018c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.416159: mmc_blk_rw_start: cmd=18,addr=0x01902000,size=0x00000008
+ <idle>-0 [000] ..s3 66.416321: mmc_blk_rw_end: cmd=18,addr=0x01902000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.416501: mmc_blk_erase_start: cmd=3,addr=0x01902ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.429352: mmc_blk_erase_end: cmd=3,addr=0x01902ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.432979: mmc_blk_rw_start: cmd=18,addr=0x01942000,size=0x00000008
+ <idle>-0 [000] ..s3 66.433141: mmc_blk_rw_end: cmd=18,addr=0x01942000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.433322: mmc_blk_erase_start: cmd=3,addr=0x01942ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.446157: mmc_blk_erase_end: cmd=3,addr=0x01942ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.449711: mmc_blk_rw_start: cmd=18,addr=0x01982000,size=0x00000008
+ <idle>-0 [000] ..s3 66.449872: mmc_blk_rw_end: cmd=18,addr=0x01982000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.450054: mmc_blk_erase_start: cmd=3,addr=0x01982ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.462903: mmc_blk_erase_end: cmd=3,addr=0x01982ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.466393: mmc_blk_rw_start: cmd=18,addr=0x019c2000,size=0x00000008
+ <idle>-0 [000] ..s3 66.466555: mmc_blk_rw_end: cmd=18,addr=0x019c2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.466732: mmc_blk_erase_start: cmd=3,addr=0x019c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.479551: mmc_blk_erase_end: cmd=3,addr=0x019c2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.482884: mmc_blk_rw_start: cmd=18,addr=0x01a02000,size=0x00000008
+ <idle>-0 [000] ..s3 66.483045: mmc_blk_rw_end: cmd=18,addr=0x01a02000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.483223: mmc_blk_erase_start: cmd=3,addr=0x01a02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.496041: mmc_blk_erase_end: cmd=3,addr=0x01a02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.499568: mmc_blk_rw_start: cmd=18,addr=0x01a42000,size=0x00000008
+ <idle>-0 [000] ..s3 66.499730: mmc_blk_rw_end: cmd=18,addr=0x01a42000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.499915: mmc_blk_erase_start: cmd=3,addr=0x01a42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.512739: mmc_blk_erase_end: cmd=3,addr=0x01a42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.516246: mmc_blk_rw_start: cmd=18,addr=0x01a82000,size=0x00000008
+ <idle>-0 [000] ..s3 66.516408: mmc_blk_rw_end: cmd=18,addr=0x01a82000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.516590: mmc_blk_erase_start: cmd=3,addr=0x01a82ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.529394: mmc_blk_erase_end: cmd=3,addr=0x01a82ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.532936: mmc_blk_rw_start: cmd=18,addr=0x01ac2000,size=0x00000008
+ <idle>-0 [000] ..s3 66.533103: mmc_blk_rw_end: cmd=18,addr=0x01ac2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.533366: mmc_blk_erase_start: cmd=3,addr=0x01ac2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.551932: mmc_blk_erase_end: cmd=3,addr=0x01ac2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.555518: mmc_blk_rw_start: cmd=18,addr=0x01b02000,size=0x00000008
+ <idle>-0 [000] ..s3 66.555680: mmc_blk_rw_end: cmd=18,addr=0x01b02000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.555864: mmc_blk_erase_start: cmd=3,addr=0x01b02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.568720: mmc_blk_erase_end: cmd=3,addr=0x01b02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.572289: mmc_blk_rw_start: cmd=18,addr=0x01b42000,size=0x00000008
+ <idle>-0 [000] ..s3 66.572452: mmc_blk_rw_end: cmd=18,addr=0x01b42000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.572640: mmc_blk_erase_start: cmd=3,addr=0x01b42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.585472: mmc_blk_erase_end: cmd=3,addr=0x01b42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.589013: mmc_blk_rw_start: cmd=18,addr=0x01b82000,size=0x00000008
+ <idle>-0 [000] ..s3 66.589177: mmc_blk_rw_end: cmd=18,addr=0x01b82000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.589361: mmc_blk_erase_start: cmd=3,addr=0x01b82ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.602230: mmc_blk_erase_end: cmd=3,addr=0x01b82ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.605811: mmc_blk_rw_start: cmd=18,addr=0x01bc2000,size=0x00000008
+ <idle>-0 [000] ..s3 66.605978: mmc_blk_rw_end: cmd=18,addr=0x01bc2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.606237: mmc_blk_erase_start: cmd=3,addr=0x01bc2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.619123: mmc_blk_erase_end: cmd=3,addr=0x01bc2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.622525: mmc_blk_rw_start: cmd=18,addr=0x01c02000,size=0x00000008
+ <idle>-0 [000] ..s3 66.622686: mmc_blk_rw_end: cmd=18,addr=0x01c02000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.622869: mmc_blk_erase_start: cmd=3,addr=0x01c02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.635750: mmc_blk_erase_end: cmd=3,addr=0x01c02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.639180: mmc_blk_rw_start: cmd=18,addr=0x01c42000,size=0x00000008
+ <idle>-0 [000] ..s3 66.639341: mmc_blk_rw_end: cmd=18,addr=0x01c42000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.639524: mmc_blk_erase_start: cmd=3,addr=0x01c42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.652365: mmc_blk_erase_end: cmd=3,addr=0x01c42ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.655886: mmc_blk_rw_start: cmd=18,addr=0x01c82000,size=0x00000008
+ <idle>-0 [000] ..s3 66.656047: mmc_blk_rw_end: cmd=18,addr=0x01c82000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.656229: mmc_blk_erase_start: cmd=3,addr=0x01c82ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.669069: mmc_blk_erase_end: cmd=3,addr=0x01c82ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.672492: mmc_blk_rw_start: cmd=18,addr=0x01cc2000,size=0x00000008
+ <idle>-0 [000] ..s3 66.672653: mmc_blk_rw_end: cmd=18,addr=0x01cc2000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.672835: mmc_blk_erase_start: cmd=3,addr=0x01cc2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.685704: mmc_blk_erase_end: cmd=3,addr=0x01cc2ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.689362: mmc_blk_rw_start: cmd=18,addr=0x01d02000,size=0x00000008
+ <idle>-0 [000] ..s3 66.689523: mmc_blk_rw_end: cmd=18,addr=0x01d02000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.689706: mmc_blk_erase_start: cmd=3,addr=0x01d02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.702548: mmc_blk_erase_end: cmd=3,addr=0x01d02ff8,size=0x0003f008
+ mmcqd/0-82 [000] ...1 66.705996: mmc_blk_rw_start: cmd=18,addr=0x01d42000,size=0x00000008
+ <idle>-0 [000] ..s3 66.706158: mmc_blk_rw_end: cmd=18,addr=0x01d42000,size=0x00000008
+ mmcqd/0-82 [000] ...1 66.706330: mmc_blk_erase_start: cmd=3,addr=0x01d42ff8,size=0x00015008
+ mmcqd/0-82 [000] ...1 66.714103: mmc_blk_erase_end: cmd=3,addr=0x01d42ff8,size=0x00015008
+ mmcqd/0-82 [000] ...1 67.055083: mmc_blk_rw_start: cmd=25,addr=0x00346400,size=0x00000008
+ mmcqd/0-82 [000] ..s3 67.055305: mmc_blk_rw_end: cmd=25,addr=0x00346400,size=0x00000008
+ mmcqd/0-82 [000] ...1 72.055236: mmc_blk_rw_start: cmd=25,addr=0x00542008,size=0x00000008
+ mmcqd/0-82 [000] ..s3 72.055404: mmc_blk_rw_end: cmd=25,addr=0x00542008,size=0x00000008
+ mmcqd/0-82 [000] ...1 72.056094: mmc_blk_rw_start: cmd=25,addr=0x005420c0,size=0x00000008
+ mmcqd/0-82 [000] ..s3 72.056225: mmc_blk_rw_end: cmd=25,addr=0x005420c0,size=0x00000008
+ mmcqd/0-82 [000] ...1 72.056859: mmc_blk_rw_start: cmd=25,addr=0x005420d0,size=0x00000008
+ mmcqd/0-82 [000] ..s3 72.056987: mmc_blk_rw_end: cmd=25,addr=0x005420d0,size=0x00000008
+ mmcqd/0-82 [000] ...1 72.057657: mmc_blk_rw_start: cmd=25,addr=0x00542118,size=0x00000008
+ mmcqd/0-82 [000] ..s3 72.057785: mmc_blk_rw_end: cmd=25,addr=0x00542118,size=0x00000008
+ mmcqd/0-82 [000] ...1 72.058561: mmc_blk_rw_start: cmd=25,addr=0x00542128,size=0x00000008
+ mmcqd/0-82 [000] ..s2 72.058755: mmc_blk_rw_end: cmd=25,addr=0x00542128,size=0x00000008
+ mmcqd/0-82 [000] ...1 72.059645: mmc_blk_rw_start: cmd=25,addr=0x00542140,size=0x00000008
+ mmcqd/0-82 [000] ..s3 72.059835: mmc_blk_rw_end: cmd=25,addr=0x00542140,size=0x00000008
+ mmcqd/0-82 [000] ...1 72.060601: mmc_blk_rw_start: cmd=25,addr=0x00544198,size=0x00000008
+ mmcqd/0-82 [000] ..s3 72.060792: mmc_blk_rw_end: cmd=25,addr=0x00544198,size=0x00000008
+ mmcqd/0-82 [000] ...1 72.061673: mmc_blk_rw_start: cmd=25,addr=0x00b82000,size=0x00000008
+ mmcqd/0-82 [000] ..s3 72.061865: mmc_blk_rw_end: cmd=25,addr=0x00b82000,size=0x00000008
+ mmcqd/0-82 [000] ...1 72.062756: mmc_blk_rw_start: cmd=25,addr=0x002c2000,size=0x00000010
+ mmcqd/0-82 [000] ..s3 72.063006: mmc_blk_rw_end: cmd=25,addr=0x002c2000,size=0x00000010
+ mmcqd/0-82 [000] ...1 72.525587: mmc_blk_rw_start: cmd=25,addr=0x002c6af8,size=0x00000008
+ mmcqd/0-82 [000] ..s3 72.525813: mmc_blk_rw_end: cmd=25,addr=0x002c6af8,size=0x00000008
+ mmcqd/0-82 [000] ...1 120.323646: mmc_blk_rw_start: cmd=25,addr=0x00b98140,size=0x00000008
+ Compiler-1337 [000] ..s4 120.323786: mmc_blk_rw_end: cmd=25,addr=0x00b98140,size=0x00000008
+ mmcqd/0-82 [000] ...1 120.326162: mmc_blk_rw_start: cmd=25,addr=0x002c6b00,size=0x00000048
+ <idle>-0 [000] ..s3 120.326635: mmc_blk_rw_end: cmd=25,addr=0x002c6b00,size=0x00000048
+ mmcqd/0-82 [000] ...1 120.327595: mmc_blk_rw_start: cmd=25,addr=0x002c6b48,size=0x00000008
+ AsyncTask #1-777 [000] ..s3 120.327691: mmc_blk_rw_end: cmd=25,addr=0x002c6b48,size=0x00000008
+ mmcqd/0-82 [000] ...1 122.485441: mmc_blk_rw_start: cmd=25,addr=0x00b91298,size=0x00000008
+ mmcqd/0-82 [000] ..s2 122.485746: mmc_blk_rw_end: cmd=25,addr=0x00b91298,size=0x00000008
+ mmcqd/0-82 [000] ...1 122.486369: mmc_blk_rw_start: cmd=25,addr=0x00b914b0,size=0x00000010
+ mmcqd/0-82 [000] ..s2 122.486656: mmc_blk_rw_end: cmd=25,addr=0x00b914b0,size=0x00000010
+ mmcqd/0-82 [000] ...1 122.487231: mmc_blk_rw_start: cmd=25,addr=0x00542120,size=0x00000008
+ mmcqd/0-82 [000] ..s3 122.487473: mmc_blk_rw_end: cmd=25,addr=0x00542120,size=0x00000008
+ mmcqd/0-82 [000] ...1 125.545654: mmc_blk_rw_start: cmd=25,addr=0x002c6b50,size=0x00000048
+ <idle>-0 [000] ..s3 125.547111: mmc_blk_rw_end: cmd=25,addr=0x002c6b50,size=0x00000048
+ mmcqd/0-82 [000] ...1 125.550617: mmc_blk_rw_start: cmd=25,addr=0x002c6b98,size=0x00000008
+ <idle>-0 [000] ..s4 125.550855: mmc_blk_rw_end: cmd=25,addr=0x002c6b98,size=0x00000008
diff --git a/tests/pagingtest/Android.mk b/tests/pagingtest/Android.mk
new file mode 100644
index 0000000..23ffea1
--- /dev/null
+++ b/tests/pagingtest/Android.mk
@@ -0,0 +1,22 @@
+local_target_dir := $(TARGET_OUT_DATA)/local/tmp
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ pagingtest.c \
+ mmap_test.c \
+ pageinout_test.c \
+ thrashing_test.c
+
+LOCAL_CFLAGS := -std=gnu11
+
+LOCAL_MODULE:= pagingtest
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_MODULE_PATH := $(local_target_dir)
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := pagingtest
+LOCAL_MODULE_STEM_64 := pagingtest64
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/pagingtest/mmap_test.c b/tests/pagingtest/mmap_test.c
new file mode 100644
index 0000000..d0d9846
--- /dev/null
+++ b/tests/pagingtest/mmap_test.c
@@ -0,0 +1,51 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include "pagingtest.h"
+
+int mmap_test(int test_runs, unsigned long long alloc_size) {
+ void *buf;
+ int ret = -1;
+ int rc;
+ int i;
+ struct timeval begin_time, end_time, elapsed_time;
+ struct timeval total_time_mmap, total_time_munmap, total_time_in, total_time_out;
+
+ timerclear(&total_time_mmap);
+ timerclear(&total_time_munmap);
+ timerclear(&total_time_in);
+ timerclear(&total_time_out);
+
+ for (i = 0; i < test_runs; i++) {
+ gettimeofday(&begin_time, NULL);
+ buf = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ gettimeofday(&end_time, NULL);
+ if (buf == ((void *)-1)) {
+ fprintf(stderr, "Failed to mmap anonymous memory: %s\n", strerror(errno));
+ goto err_map;
+ }
+ timersub(&end_time, &begin_time, &elapsed_time);
+ timeradd(&total_time_mmap, &elapsed_time, &total_time_mmap);
+
+ gettimeofday(&begin_time, NULL);
+ munmap(buf, alloc_size);
+ gettimeofday(&end_time, NULL);
+ timersub(&end_time, &begin_time, &elapsed_time);
+ timeradd(&total_time_mmap, &elapsed_time, &total_time_mmap);
+ }
+
+ printf("mmap: %llu us\n", total_time_mmap.tv_sec * USEC_PER_SEC + total_time_mmap.tv_usec);
+ printf("munmap: %llu us\n", total_time_munmap.tv_sec * USEC_PER_SEC + total_time_munmap.tv_usec);
+
+ ret = 0;
+ goto end;
+err:
+ munmap(buf, alloc_size);
+end:
+err_map:
+ return ret;
+}
diff --git a/tests/pagingtest/pageinout_test.c b/tests/pagingtest/pageinout_test.c
new file mode 100644
index 0000000..887794e
--- /dev/null
+++ b/tests/pagingtest/pageinout_test.c
@@ -0,0 +1,104 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include "pagingtest.h"
+
+int pageinout_test(int test_runs, bool cache, unsigned long long file_size) {
+ int fd;
+ char tmpname[] = "pageinoutXXXXXX";
+ unsigned char *vec;
+ int i;
+ unsigned long long j;
+ volatile char *buf;
+ int ret = -1;
+ int rc;
+ struct timeval begin_time, end_time, elapsed_time, total_time_in, total_time_out;
+ long pagesize = sysconf(_SC_PAGE_SIZE);
+
+ timerclear(&total_time_in);
+ timerclear(&total_time_out);
+
+ fd = create_tmp_file(tmpname, file_size);
+ if (fd < 0) {
+ return -1;
+ }
+
+ vec = alloc_mincore_vec(file_size);
+ if (vec == NULL) {
+ goto err_alloc;
+ }
+
+ buf = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (buf == ((void *)-1)) {
+ fprintf(stderr, "Failed to mmap file: %s\n", strerror(errno));
+ goto err_mmap;
+ }
+
+ if (!check_caching((void *)buf, vec, file_size, false)) {
+ goto err;
+ }
+
+ if (!cache) {
+ //madvise and fadvise as random to prevent prefetching
+ rc = madvise((void *)buf, file_size, MADV_RANDOM) ||
+ posix_fadvise(fd, 0, file_size, POSIX_FADV_RANDOM);
+ if (rc) {
+ goto err;
+ }
+ }
+
+ for (i = 0; i < test_runs; i++) {
+ gettimeofday(&begin_time, NULL);
+ //read every page into the page cache
+ for (j = 0; j < file_size; j += pagesize) {
+ buf[j];
+ }
+ gettimeofday(&end_time, NULL);
+
+ timersub(&end_time, &begin_time, &elapsed_time);
+ timeradd(&total_time_in, &elapsed_time, &total_time_in);
+
+ if (!check_caching((void *)buf, vec, file_size, true)) {
+ goto err;
+ }
+
+ gettimeofday(&begin_time, NULL);
+ rc = madvise((void *)buf, file_size, MADV_DONTNEED) ||
+ posix_fadvise(fd, 0, file_size, POSIX_FADV_DONTNEED);
+ gettimeofday(&end_time, NULL);
+ if (rc) {
+ fprintf(stderr, "posix_fadvise/madvise DONTNEED failed\n");
+ goto err;
+ }
+
+ timersub(&end_time, &begin_time, &elapsed_time);
+ timeradd(&total_time_out, &elapsed_time, &total_time_out);
+
+ if (!check_caching((void *)buf, vec, file_size, false)) {
+ goto err;
+ }
+ }
+
+ printf("%scached page-in: %llu MB/s\n", cache ? "" : "un",
+ (file_size * test_runs * USEC_PER_SEC) /
+ (1024 * 1024 * (total_time_in.tv_sec * USEC_PER_SEC + total_time_in.tv_usec)));
+ printf("%scached page-out (clean): %llu MB/s\n", cache ? "" : "un",
+ (file_size * test_runs * USEC_PER_SEC) /
+ (1024 * 1024 * (total_time_out.tv_sec * USEC_PER_SEC + total_time_out.tv_usec)));
+
+ ret = 0;
+
+err:
+ munmap((void *)buf, file_size);
+err_mmap:
+ free(vec);
+err_alloc:
+ close(fd);
+ return ret;
+}
diff --git a/tests/pagingtest/pagingtest.c b/tests/pagingtest/pagingtest.c
new file mode 100644
index 0000000..158d8a3
--- /dev/null
+++ b/tests/pagingtest/pagingtest.c
@@ -0,0 +1,185 @@
+#include "pagingtest.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define TEST_RUNS 10
+#define ALLOC_SIZE (10 * 1024 * 1024)
+#define FILE_SIZE (10 * 1024 * 1024)
+
+int create_tmp_file(char *filename, off_t size) {
+ void *buf;
+ uint8_t *tmp_buf;
+ off_t tmp_size;
+ ssize_t rc;
+ int fd;
+ int urandom;
+
+ fd = mkstemp(filename);
+ if (fd < 0) {
+ fprintf(stderr, "unable to create temp file: %s\n", strerror(errno));
+ goto err_mkstemp;
+ }
+
+ urandom = open("/dev/urandom", O_RDONLY);
+ if (urandom < 0) {
+ fprintf(stderr, "unable to open urandom: %s\n", strerror(errno));
+ goto err_open;
+ }
+
+ if (unlink(filename)) {
+ fprintf(stderr, "unable to unlink temp file: %s\n", strerror(errno));
+ goto err_unlink;
+ }
+
+ if (ftruncate(fd, size)) {
+ fprintf(stderr, "unable to allocate temp file: %s\n", strerror(errno));
+ goto err_truncate;
+ }
+
+ buf = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0);
+ if (buf == (void *)-1) {
+ fprintf(stderr, "unable to mmap temp file: %s\n", strerror(errno));
+ goto err_mmap;
+ }
+
+ tmp_buf = buf;
+ tmp_size = size;
+ do {
+ rc = read(urandom, tmp_buf, tmp_size);
+
+ if (rc < 0) {
+ fprintf(stderr, "write random data failed: %s\n", strerror(errno));
+ goto err;
+ }
+
+ tmp_buf += rc;
+ tmp_size -= rc;
+ } while (tmp_size > 0);
+
+ if (madvise(buf, size, MADV_DONTNEED)) {
+ fprintf(stderr, "madvise DONTNEED failed: %s\n", strerror(errno));
+ goto err;
+ }
+
+ if (fsync(fd) < 0) {
+ fprintf(stderr, "fsync failed: %s\n", strerror(errno));
+ goto err;
+ }
+
+ rc = posix_fadvise(fd, 0, size, POSIX_FADV_DONTNEED);
+ if (rc) {
+ fprintf(stderr, "fadvise DONTNEED failed: %s\n", strerror(errno));
+ goto err;
+ }
+
+ munmap(buf, size);
+ close(urandom);
+ return fd;
+
+err:
+ munmap(buf, size);
+err_mmap:
+err_truncate:
+err_unlink:
+ close(urandom);
+err_open:
+ close(fd);
+err_mkstemp:
+ return -1;
+}
+
+unsigned char *alloc_mincore_vec(size_t size) {
+ unsigned char *vec;
+
+ vec = malloc(mincore_vec_len(size));
+ if (vec == NULL) {
+ fprintf(stderr, "malloc failed\n");
+ }
+
+ return vec;
+}
+
+bool check_caching(void *buf, unsigned char *vec, size_t size, bool is_cached) {
+ bool ret = true;
+ size_t i;
+
+ if (mincore(buf, size, vec)) {
+ fprintf(stderr, "mincore failed: %s\n", strerror(errno));
+ return false;
+ }
+
+ if (is_cached) {
+ for (i = 0; i < mincore_vec_len(size); i++) {
+ if (!(vec[i] & 0x1)) {
+ fprintf(stderr, "found an uncached page at page offset %zd\n", i);
+ ret = false;
+ }
+ }
+ } else {
+ for (i = 0; i < mincore_vec_len(size); i++) {
+ if (vec[i] & 0x1) {
+ fprintf(stderr, "found a cached page at page offset %zd\n", i);
+ ret = false;
+ }
+ }
+ }
+
+ return ret;
+}
+
+int main(int argc, char **argv) {
+ unsigned long long alloc_size = 0ULL;
+ unsigned long long file_size = 0ULL;
+ int test_runs = 0;
+ int rc;
+
+ //arguments: <program> [test_runs [alloc_size [file_size]]]
+ if (argc >= 2) {
+ test_runs = atoi(argv[1]);
+ }
+ if (test_runs <= 0) {
+ test_runs = TEST_RUNS;
+ }
+ if (argc >= 3) {
+ alloc_size = strtoull(argv[2], NULL, 10);
+ }
+ if (!alloc_size) {
+ alloc_size = ALLOC_SIZE;
+ }
+ if (argc >= 4) {
+ file_size = strtoull(argv[3], NULL, 10);
+ }
+ if (!file_size) {
+ file_size = FILE_SIZE;
+ }
+
+ rc = mmap_test(test_runs, alloc_size);
+ if (rc) {
+ return rc;
+ }
+ rc = pageinout_test(test_runs, true, file_size);
+ if (rc) {
+ return rc;
+ }
+ rc = pageinout_test(test_runs, false, file_size);
+ if (rc) {
+ return rc;
+ }
+ rc = thrashing_test(test_runs, true);
+ if (rc) {
+ return rc;
+ }
+ rc = thrashing_test(test_runs, false);
+
+ return rc;
+}
diff --git a/tests/pagingtest/pagingtest.h b/tests/pagingtest/pagingtest.h
new file mode 100644
index 0000000..a6f3d03
--- /dev/null
+++ b/tests/pagingtest/pagingtest.h
@@ -0,0 +1,20 @@
+#include <unistd.h>
+#include <stdbool.h>
+
+#ifndef __PAGINGTEST_H__
+#define __PAGINGTEST_H__
+#define USEC_PER_SEC 1000000ULL
+#define mincore_vec_len(size) (((size) + sysconf(_SC_PAGE_SIZE) - 1) / sysconf(_SC_PAGE_SIZE))
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+
+//Helpers
+int create_tmp_file(char *filename, off_t size);
+unsigned char *alloc_mincore_vec(size_t size);
+bool check_caching(void *buf, unsigned char *vec, size_t size, bool is_cached);
+
+//Tests
+int mmap_test(int test_runs, unsigned long long alloc_size);
+int pageinout_test(int test_runs, bool cache, unsigned long long file_size);
+int thrashing_test(int test_runs, bool cache);
+
+#endif //__PAGINGTEST_H__
diff --git a/tests/pagingtest/thrashing_test.c b/tests/pagingtest/thrashing_test.c
new file mode 100644
index 0000000..0f4547f
--- /dev/null
+++ b/tests/pagingtest/thrashing_test.c
@@ -0,0 +1,87 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include "pagingtest.h"
+
+#define LINESIZE 32
+
+int thrashing_test(int test_runs, bool cache) {
+ int fds[4] = {-1, -1, -1, -1};
+ char tmpnames[4][17] = { "thrashing1XXXXXX", "thrashing2XXXXXX", "thrashing3XXXXXX", "thrashing4XXXXXX" };
+ volatile char *bufs[4] = {0};
+ unsigned long long k;
+ int ret = -1;
+ struct timeval begin_time, end_time, elapsed_time, total_time;
+ unsigned long long filesize;
+ long num_pages;
+ long pagesize;
+
+ timerclear(&total_time);
+
+ num_pages = sysconf(_SC_PHYS_PAGES);
+ pagesize = sysconf(_SC_PAGE_SIZE);
+ if (num_pages < 0) {
+ fprintf(stderr, "failed to get the number of pages\n");
+ return -1;
+ }
+
+ filesize = num_pages * pagesize / (ARRAY_SIZE(fds) - 1);
+
+ for (size_t i = 0; i < ARRAY_SIZE(fds); i++) {
+ fds[i] = create_tmp_file(tmpnames[i], filesize);
+ if (fds[i] < 0) {
+ goto err_fd;
+ }
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(fds); i++) {
+ bufs[i] = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fds[i], 0);
+ if (bufs[i] == ((void *)-1)) {
+ fprintf(stderr, "Failed to mmap file: %s\n", strerror(errno));
+ goto err;
+ }
+ if (!cache) {
+ //madvise and fadvise as random to prevent prefetching
+ ret = madvise((void *)bufs[i], filesize, MADV_RANDOM) ||
+ posix_fadvise(fds[i], 0, filesize, POSIX_FADV_RANDOM);
+ if (ret) {
+ goto err;
+ }
+ }
+ }
+
+ for (int i = 0; i < test_runs; i++) {
+ for (size_t j = 0; j < ARRAY_SIZE(fds); j++) {
+ gettimeofday(&begin_time, NULL);
+ for (k = 0; k < filesize; k += pagesize) {
+ bufs[j][k];
+ }
+ gettimeofday(&end_time, NULL);
+
+ timersub(&end_time, &begin_time, &elapsed_time);
+ timeradd(&total_time, &elapsed_time, &total_time);
+ }
+ }
+
+ printf("%scached thrashing: %llu MB/s\n", cache ? "" : "un",
+ (filesize * ARRAY_SIZE(fds) * test_runs * USEC_PER_SEC) /
+ (1024 * 1024 * (total_time.tv_sec * USEC_PER_SEC + total_time.tv_usec)));
+
+ ret = 0;
+
+err:
+ for (size_t i = 0; i < ARRAY_SIZE(bufs) && bufs[i] != NULL; i++) {
+ munmap((void *)bufs[i], filesize);
+ }
+err_fd:
+ for (size_t i = 0; i < ARRAY_SIZE(fds) && fds[i] >= 0; i++) {
+ close(fds[i]);
+ }
+ return ret;
+}
diff --git a/tests/pftest/Android.mk b/tests/pftest/Android.mk
new file mode 100644
index 0000000..bedbd0c
--- /dev/null
+++ b/tests/pftest/Android.mk
@@ -0,0 +1,18 @@
+# Copyright 2010 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= pftest.c.arm
+
+
+LOCAL_SHARED_LIBRARIES := libc
+
+LOCAL_MODULE:= pftest
+
+LOCAL_MODULE_TAGS := optional
+
+## LOCAL_CFLAGS += -fstack-protector-all
+LOCAL_CFLAGS += -fomit-frame-pointer
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/pftest/pftest.c b/tests/pftest/pftest.c
new file mode 100644
index 0000000..f5af894
--- /dev/null
+++ b/tests/pftest/pftest.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+
+#define N_PAGES (4096)
+
+#define WARMUP (1<<10)
+
+#define WORKLOAD (1<<24)
+
+int numPagesList[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 12, 14, 16, 18, 20, 24, 28, 30, 32, 34, 48, 62, 64, 66, 80,
+ 96, 112, 128, 144, 160, 320, 480, 496, 512, 528, 544, 576, 640, 960,
+ 1024, 2048, 3072, 4000,
+};
+
+static unsigned long long stop_watch()
+{
+ struct timespec t;
+ t.tv_sec = t.tv_nsec = 0;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return t.tv_sec*1000000000ULL + t.tv_nsec;
+}
+
+int main()
+{
+ char *mem = malloc((N_PAGES+1) * 4096);
+ intptr_t *p;
+ int i;
+ unsigned int j;
+
+ /* Align to page start */
+ mem = (char *) ((intptr_t) (mem + 4096) & ~0xfff);
+
+ for (j = 0; j < sizeof(numPagesList)/sizeof(int); j++) {
+ int numPages = numPagesList[j];
+ int pageIdx = 0;
+ int entryOffset = 0;
+
+ /*
+ * page 0 page 1 page 2 .... page N
+ * ------ ------ ------ ------
+ * word 0 -> word 0 -> word 0 -> .... -> word 0 -> (page 0/word 0)
+ * : : : : :
+ * word 1023 word 1023 word 1023 : word 1023
+ */
+ for (i = 0; i < numPages; i++) {
+ int nextPageIdx = (pageIdx + 1) % numPages;
+ /* Looks like spread the pointer across cache lines introduce noise
+ * to get to the asymptote
+ * int nextEntryOffset = (entryOffset + 32) % 1024;
+ */
+ int nextEntryOffset = entryOffset;
+
+ if (i != numPages -1) {
+ *(intptr_t *) (mem + 4096 * pageIdx + entryOffset) =
+ (intptr_t) (mem + 4096 * nextPageIdx + nextEntryOffset);
+ } else {
+ /* Last page - form the cycle */
+ *(intptr_t *) (mem + 4096 * pageIdx + entryOffset) =
+ (intptr_t) &mem[0];
+ }
+
+ pageIdx = nextPageIdx;
+ entryOffset = nextEntryOffset;
+ }
+
+ /* Starting point of the pointer chase */
+ p = (intptr_t *) &mem[0];
+
+ /* Warmup (ie pre-thrash the memory system */
+ for (i = 0; i < WARMUP; i++) {
+ p = (intptr_t *) *p;
+ }
+
+ /* Real work */
+ unsigned long long t0 = stop_watch();
+ for (i = 0; i < WORKLOAD; i++) {
+ p = (intptr_t *) *p;
+ }
+ unsigned long long t1 = stop_watch();
+
+ /* To keep p from being optimized by gcc */
+ if (p)
+ printf("%d, %f\n", numPages, (float) (t1 - t0) / WORKLOAD);
+ }
+ return 0;
+}
diff --git a/tests/schedtest/Android.mk b/tests/schedtest/Android.mk
new file mode 100644
index 0000000..036c9fe
--- /dev/null
+++ b/tests/schedtest/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ schedtest.c
+
+LOCAL_MODULE := schedtest
+LOCAL_CFLAGS := -Wno-unused-parameter
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/schedtest/schedtest.c b/tests/schedtest/schedtest.c
new file mode 100644
index 0000000..73ffadc
--- /dev/null
+++ b/tests/schedtest/schedtest.c
@@ -0,0 +1,49 @@
+/*
+** Copyright 2008 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.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+ int i;
+
+ struct timeval tv1;
+ struct timeval tv2;
+ long max = 0;
+ long avg = 0;
+
+ for(i = 1; ; i++) {
+ gettimeofday(&tv1, NULL);
+ usleep(1000);
+ gettimeofday(&tv2, NULL);
+
+ long usec = (tv2.tv_sec - tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec;
+ avg += usec;
+
+ if (usec > max) max = usec;
+ if (!(i % 1000)) {
+ avg /= 1000;
+ printf("max %ld\tavg %ld\n", max, avg);
+ max = 0;
+ avg = 0;
+ }
+ }
+ return 0;
+}
diff --git a/tests/sdcard/Android.mk b/tests/sdcard/Android.mk
new file mode 100644
index 0000000..d1e06f2
--- /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/README b/tests/sdcard/README
new file mode 100644
index 0000000..210bb43
--- /dev/null
+++ b/tests/sdcard/README
@@ -0,0 +1,63 @@
+This directory contains tools to profile the sdcard performance.
+
+There are 2 parts to the tool:
+* A binary that runs on the device, exercises the sdcard and send
+ measurment data back to the host (sdcard_perf_test).
+* A host python script to plot the data.
+
+Additionally, there is script 'profile_sdcard.sh' that allows you
+to check how the sdcard scale with the number of processes.
+
+INSTALLATION
+============
+Build, install and mount debugfs. In this directory with a properly
+configured enviroment:
+
+ mm SDCARD_TESTS=1
+ adb remount
+ adb push $ANDROID_PRODUCT_OUT/system/bin/sdcard_perf_test /system/bin/sdcard_perf_test
+ adb shell mount -t debugfs none /sys/kernel/debug
+
+If you want to graph the results you need gnuplot and numpy:
+
+ sudo apt-get install gnuplot python-numpy python-numeric
+
+You need Gnuplot.py version 1.8 (not the one coming with ubuntu).
+Download it from the Gnuplot.py web site. Extract to a temp
+directory, chdir and run:
+
+ sudo python setup.py install
+
+
+INVOCATION
+==========
+
+Run a simple test:
+
+ adb shell sdcard_perf_test --test=write --size=1000 --chunk-size=100 --procnb=1 --iterations=100
+
+This test will write 1000kbyte (1M) files using writes of 100kbytes (so 10 writes per file) using
+only 1 process for 100 times (100 files will be written on the sdcard).
+The test will not call sync to flush the writes.
+At the end of the test, some stats for the 'open' and 'write' system calls are written.
+
+If you want to plot the data, you need to use the --dump option and provide a file:
+
+ adb shell sdcard_perf_test --test=write --size=1000 --chunk-size=100 --procnb=1 --iterations=100 --dump >/tmp/data.txt
+
+PLOTTING
+========
+
+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
+
diff --git a/tests/sdcard/plot_sdcard.py b/tests/sdcard/plot_sdcard.py
new file mode 100755
index 0000000..0959465
--- /dev/null
+++ b/tests/sdcard/plot_sdcard.py
@@ -0,0 +1,334 @@
+#!/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.]+-[^ ]+)', 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__':
+ if Gnuplot.__version__ != "1.8":
+ print "Gnuplot should be 1.8. See REAME file"
+ sys.exit(2)
+ main(sys.argv)
diff --git a/tests/sdcard/profile_sdcard.sh b/tests/sdcard/profile_sdcard.sh
new file mode 100755
index 0000000..4629c91
--- /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 0000000..c93c52b
--- /dev/null
+++ b/tests/sdcard/sdcard_perf_test.cpp
@@ -0,0 +1,737 @@
+/*
+ * 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 <fts.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 output 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'},
+ {"depth", required_argument, 0, 'D'},
+ {"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|traverse [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"
+ " -D --depth: Depth of directory tree to create for traversal.\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:D: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 'D': // tree depth
+ testCase->setTreeDepth(atoi(optarg));
+ 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, S_IRWXU);
+
+ 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, S_IRWXU); // 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, S_IRWXU);
+ 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;
+}
+
+bool writeTestFile(TestCase *testCase, const char* filename) {
+ int fd = open(filename, O_RDWR | O_CREAT, S_IRWXU);
+ if (fd < 0) {
+ fprintf(stderr, "open() failed: %s\n", strerror(errno));
+ return false;
+ }
+
+ bool res = false;
+
+ char * const chunk = new char[testCase->chunkSize()];
+ memset(chunk, 0xaa, testCase->chunkSize());
+
+ size_t left = testCase->dataSize();
+ 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;
+ }
+
+ while (chunk_size > 0) {
+ ssize_t s = write(fd, dest, chunk_size);
+ if (s < 0) {
+ fprintf(stderr, "write() failed: %s\n", strerror(errno));
+ goto fail;
+ }
+ chunk_size -= s;
+ dest += s;
+ }
+ }
+
+ res = true;
+fail:
+ close(fd);
+ delete[] chunk;
+ return res;
+}
+
+// ----------------------------------------------------------------------
+// TRAVERSE
+
+#define MAX_PATH 512
+
+// Creates a directory tree that is both deep and wide, and times
+// traversal using fts_open().
+bool testTraverse(TestCase *testCase) {
+ char path[MAX_PATH];
+ char filepath[MAX_PATH];
+ strcpy(path, kTestDir);
+
+ // Generate a deep directory hierarchy
+ size_t depth = testCase->treeDepth();
+ for (size_t i = 0; i < depth; i++) {
+ // Go deeper by appending onto current path
+ snprintf(path + strlen(path), MAX_PATH - strlen(path), "/dir%d", i);
+ mkdir(path, S_IRWXU);
+
+ // Create some files at this depth
+ strcpy(filepath, path);
+ int pathlen = strlen(path);
+ char* nameStart = filepath + pathlen;
+ for (size_t j = 0; j < depth; j++) {
+ snprintf(nameStart, MAX_PATH - pathlen, "/file%d", j);
+ writeTestFile(testCase, filepath);
+ }
+ }
+
+ testCase->signalParentAndWait();
+ testCase->testTimer()->start();
+
+ // Now traverse structure
+ size_t iter = testCase->iter();
+ for (size_t i = 0; i < iter; i++) {
+ testCase->traverseTimer()->start();
+
+ FTS *ftsp;
+ if ((ftsp = fts_open((char **) &kTestDir, FTS_LOGICAL | FTS_XDEV, NULL)) == NULL) {
+ fprintf(stderr, "fts_open() failed: %s\n", strerror(errno));
+ return false;
+ }
+
+ // Count discovered files
+ int dirs = 0, files = 0;
+
+ FTSENT *curr;
+ while ((curr = fts_read(ftsp)) != NULL) {
+ switch (curr->fts_info) {
+ case FTS_D:
+ dirs++;
+ break;
+ case FTS_F:
+ files++;
+ break;
+ }
+ }
+
+ fts_close(ftsp);
+
+ testCase->traverseTimer()->stop();
+
+ int expectedDirs = depth + 1;
+ if (expectedDirs != dirs) {
+ fprintf(stderr, "expected %d dirs, but found %d\n", expectedDirs, dirs);
+ return false;
+ }
+
+ int expectedFiles = depth * depth;
+ if (expectedFiles != files) {
+ fprintf(stderr, "expected %d files, but found %d\n", expectedFiles, files);
+ return false;
+ }
+ }
+
+ 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;
+ case TestCase::TRAVERSE:
+ testCase.mTestBody = testTraverse;
+ 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 0000000..77768d6
--- /dev/null
+++ b/tests/sdcard/stopwatch.cpp
@@ -0,0 +1,236 @@
+/*
+ * 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"
+#include <math.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), mDeviation(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 SizeKbytes\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");
+ size_t n = mDataLen / 2;
+ mDeltas= new double[n];
+ 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 < n; ++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 avgDuration = mDuration / n;
+ double diffSQ = 0.0;
+ for (size_t i = 0; i < n; ++i)
+ {
+ diffSQ += pow((mDeltas[i] - avgDuration), 2.0);
+ }
+ mDeviation = sqrt(diffSQ / n);
+}
+
+
+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, "# Standard deviation %s duration %f \n", mName, mDeviation);
+ 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 0000000..c54f257
--- /dev/null
+++ b/tests/sdcard/stopwatch.h
@@ -0,0 +1,156 @@
+/*
+ * 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 mDeviation;
+ 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 0000000..0182590
--- /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 0000000..3df79c1
--- /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 0000000..06fd71b
--- /dev/null
+++ b/tests/sdcard/testcase.cpp
@@ -0,0 +1,232 @@
+/*
+ * 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), mTreeDepth(8), 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);
+ if(traverseTimer()->used()) traverseTimer()->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());
+
+ mTraverseTimer = new StopWatch("traversal", 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;
+ if (strcmp(mName, "traverse") == 0) mType = TRAVERSE;
+
+ 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 0000000..e973d9a
--- /dev/null
+++ b/tests/sdcard/testcase.h
@@ -0,0 +1,169 @@
+/*
+ * 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, TRAVERSE};
+ 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; }
+
+ size_t treeDepth() const { return mTreeDepth; }
+ void setTreeDepth(size_t val) { mTreeDepth = 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; }
+ StopWatch *traverseTimer() { return mTraverseTimer; }
+
+ // 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 mTreeDepth;
+ 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.
+ StopWatch *mTraverseTimer; // Used to time each traversal.
+};
+
+} // namespace android_test
+
+#endif // SYSTEM_EXTRAS_TESTS_SDCARD_TESTCASE_H_
diff --git a/tests/storage/Android.mk b/tests/storage/Android.mk
new file mode 100644
index 0000000..462ebef
--- /dev/null
+++ b/tests/storage/Android.mk
@@ -0,0 +1,17 @@
+# Copyright 2013 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := opentest.c
+LOCAL_MODULE := opentest
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := wipe_blkdev.c
+LOCAL_MODULE := wipe_blkdev
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
diff --git a/tests/storage/opentest.c b/tests/storage/opentest.c
new file mode 100644
index 0000000..05d5586
--- /dev/null
+++ b/tests/storage/opentest.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int main(int argc, char *argv[])
+{
+ int i;
+ int nfiles;
+ int *fds;
+ char *dir;
+ struct stat statbuf;
+ char name[16];
+ struct rlimit rlim;
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: opentest <directory> <num_files>\n");
+ exit(1);
+ }
+
+ dir = argv[1];
+
+ nfiles = atoi(argv[2]);
+ if ((nfiles <= 0) || (nfiles > 65536)) {
+ fprintf(stderr, "num_files must be between 1 and 65536\n");
+ exit(1);
+ }
+
+ if (stat(dir, &statbuf)) {
+ fprintf(stderr, "Cannot stat %s\n", dir);
+ exit(1);
+ }
+
+ if (! S_ISDIR(statbuf.st_mode)) {
+ fprintf(stderr, "%s is not a directory!\n", dir);
+ exit(1);
+ }
+
+ if (access(dir, R_OK | W_OK)) {
+ fprintf(stderr, "No access to %s\n", dir);
+ exit(1);
+ }
+
+ fds = malloc(nfiles * sizeof(int));
+ if (fds == 0) {
+ fprintf(stderr, "Unable to malloc array of %d fds\n", nfiles);
+ exit(1);
+ }
+
+ if (chdir(dir)) {
+ fprintf(stderr, "Cannot chdir to %s\n", dir);
+ exit(1);
+ }
+
+ rlim.rlim_cur = nfiles + 10;
+ rlim.rlim_max = nfiles + 10;
+ if (setrlimit(RLIMIT_NOFILE, &rlim)) {
+ fprintf(stderr, "Unable to raise RLIMIT_NOFILE to %ld\n", rlim.rlim_cur);
+ exit(1);
+ }
+
+ for (i = 0; i < nfiles; i++) {
+ snprintf(name, sizeof(name), "%d", i);
+ fds[i] = open(name, O_WRONLY | O_CREAT, 0666);
+ if (fds[i] < 0) {
+ fprintf(stderr, "Unable to open %d fd\n", i);
+ exit(1);
+ }
+ }
+
+ /* Rely upon exit to cleanup! */
+ exit(0);
+}
+
+
diff --git a/tests/storage/wipe_blkdev.c b/tests/storage/wipe_blkdev.c
new file mode 100644
index 0000000..3cca7d2
--- /dev/null
+++ b/tests/storage/wipe_blkdev.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011, 2012 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <errno.h>
+
+typedef unsigned long long u64;
+
+#ifndef BLKDISCARD
+#define BLKDISCARD _IO(0x12,119)
+#endif
+
+#ifndef BLKSECDISCARD
+#define BLKSECDISCARD _IO(0x12,125)
+#endif
+
+static u64 get_block_device_size(int fd)
+{
+ u64 size = 0;
+ int ret;
+
+ ret = ioctl(fd, BLKGETSIZE64, &size);
+
+ if (ret)
+ return 0;
+
+ return size;
+}
+
+static int wipe_block_device(int fd, u64 len, int secure)
+{
+ u64 range[2];
+ int ret;
+ int req;
+
+ range[0] = 0;
+ range[1] = len;
+ if (secure) {
+ req = BLKSECDISCARD;
+ } else {
+ req = BLKDISCARD;
+ }
+
+ ret = ioctl(fd, req, &range);
+ if (ret < 0) {
+ fprintf(stderr, "%s discard failed, errno = %d\n",
+ secure ? "Secure" : "Nonsecure", errno);
+ }
+
+ return ret;
+}
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: wipe_blkdev [-s] <partition>\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ int secure = 0;
+ char *devname;
+ int fd;
+ u64 len;
+ struct stat statbuf;
+ int ret;
+
+ if ((argc != 2) && (argc != 3)) {
+ usage();
+ }
+
+ if (argc == 3) {
+ if (!strcmp(argv[1], "-s")) {
+ secure = 1;
+ devname = argv[2];
+ } else {
+ usage();
+ }
+ } else {
+ devname = argv[1];
+ }
+
+ fd = open(devname, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot open device %s\n", devname);
+ exit(1);
+ }
+
+ if (fstat(fd, &statbuf) < 0) {
+ fprintf(stderr, "Cannot stat %s\n", devname);
+ exit(1);
+ }
+
+ if (!S_ISBLK(statbuf.st_mode)) {
+ fprintf(stderr, "%s is not a block device\n", devname);
+ exit(1);
+ }
+
+ len = get_block_device_size(fd);
+
+ if (! len) {
+ fprintf(stderr, "Cannot get size of block device %s\n", devname);
+ exit(1);
+ }
+
+ ret = wipe_block_device(fd, len, secure);
+
+ close(fd);
+
+ return ret;
+}
diff --git a/tests/suspend_stress/Android.mk b/tests/suspend_stress/Android.mk
new file mode 100644
index 0000000..952f50f
--- /dev/null
+++ b/tests/suspend_stress/Android.mk
@@ -0,0 +1,9 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := suspend_stress.cpp
+LOCAL_MODULE := suspend_stress
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_STATIC_LIBRARIES := libc libcutils
+include $(BUILD_EXECUTABLE)
diff --git a/tests/suspend_stress/suspend_stress.cpp b/tests/suspend_stress/suspend_stress.cpp
new file mode 100644
index 0000000..517581c
--- /dev/null
+++ b/tests/suspend_stress/suspend_stress.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+
+#include <cutils/klog.h>
+
+#define NSEC_PER_SEC (1000*1000*1000)
+#define MSEC_PER_SEC 1000
+#define NSEC_PER_MSEC (NSEC_PER_SEC/MSEC_PER_SEC)
+
+long long timediff_ns(const struct timespec *a, const struct timespec *b) {
+ return ((long long)(a->tv_sec - b->tv_sec)) * NSEC_PER_SEC +
+ (a->tv_nsec - b->tv_nsec);
+}
+
+void usage(void)
+{
+ printf("usage: suspend_stress [ <options> ]\n"
+ "options:\n"
+ " -a,--abort abort test on late alarm\n"
+ " -c,--count=<count> number of times to suspend (default infinite)\n"
+ " -t,--time=<seconds> time to suspend for (default 5)\n"
+ );
+}
+
+int main(int argc, char **argv)
+{
+ int alarm_time = 5;
+ int count = -1;
+ bool abort_on_failure = false;
+
+ while (1) {
+ const static struct option long_options[] = {
+ {"abort", no_argument, 0, 'a'},
+ {"count", required_argument, 0, 'c'},
+ {"time", required_argument, 0, 't'},
+ };
+ int c = getopt_long(argc, argv, "ac:t:", long_options, NULL);
+ if (c < 0) {
+ break;
+ }
+
+ switch (c) {
+ case 'a':
+ abort_on_failure = true;
+ break;
+ case 'c':
+ count = strtoul(optarg, NULL, 0);
+ break;
+ case 't':
+ alarm_time = strtoul(optarg, NULL, 0);
+ break;
+ case '?':
+ usage();
+ exit(EXIT_FAILURE);
+ default:
+ abort();
+ }
+ }
+
+ klog_set_level(KLOG_INFO_LEVEL);
+
+ if (optind < argc) {
+ fprintf(stderr, "Unexpected argument: %s\n", argv[optind]);
+ usage();
+ exit(EXIT_FAILURE);
+ }
+
+ int fd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0);
+ if (fd < 0) {
+ perror("timerfd_create failed");
+ exit(EXIT_FAILURE);
+ }
+
+ struct itimerspec delay = itimerspec();
+ delay.it_value.tv_sec = alarm_time;
+ int i = 0;
+
+ int epoll_fd = epoll_create(1);
+ if (epoll_fd < 0) {
+ perror("epoll_create failed");
+ exit(EXIT_FAILURE);
+ }
+
+ struct epoll_event ev = epoll_event();
+ ev.events = EPOLLIN | EPOLLWAKEUP;
+ int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
+ if (ret < 0) {
+ perror("epoll_ctl failed");
+ exit(EXIT_FAILURE);
+ }
+
+ while (count != 0) {
+ struct timespec expected_time;
+ struct timespec actual_time;
+ uint64_t fired = 0;
+
+ ret = timerfd_settime(fd, 0, &delay, NULL);
+ if (ret < 0) {
+ perror("timerfd_settime failed");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = clock_gettime(CLOCK_BOOTTIME, &expected_time);
+ if (ret < 0) {
+ perror("failed to get time");
+ exit(EXIT_FAILURE);
+ }
+ expected_time.tv_sec += alarm_time;
+
+ ret = 0;
+ while (ret != 1) {
+ struct epoll_event out_ev;
+ ret = epoll_wait(epoll_fd, &out_ev, 1, -1);
+ if (ret < 0 && errno != EINTR) {
+ perror("epoll_wait failed");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ ssize_t bytes = read(fd, &fired, sizeof(fired));
+ if (bytes < 0) {
+ perror("read from timer fd failed");
+ exit(EXIT_FAILURE);
+ } else if (bytes < (ssize_t)sizeof(fired)) {
+ fprintf(stderr, "unexpected read from timer fd: %zd\n", bytes);
+ }
+
+ if (fired != 1) {
+ fprintf(stderr, "unexpected timer fd fired count: %" PRIu64 "\n", fired);
+ }
+
+ ret = clock_gettime(CLOCK_BOOTTIME, &actual_time);
+ if (ret < 0) {
+ perror("failed to get time");
+ exit(EXIT_FAILURE);
+ }
+
+ long long diff = timediff_ns(&actual_time, &expected_time);
+ if (llabs(diff) > NSEC_PER_SEC) {
+ fprintf(stderr, "alarm arrived %lld.%03lld seconds %s\n",
+ llabs(diff) / NSEC_PER_SEC,
+ (llabs(diff) / NSEC_PER_MSEC) % MSEC_PER_SEC,
+ diff > 0 ? "late" : "early");
+ KLOG_ERROR("suspend_stress", "alarm arrived %lld.%03lld seconds %s\n",
+ llabs(diff) / NSEC_PER_SEC,
+ (llabs(diff) / NSEC_PER_MSEC) % MSEC_PER_SEC,
+ diff > 0 ? "late" : "early");
+ if (abort_on_failure) {
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ time_t t = time(NULL);
+ i += fired;
+ printf("timer fired: %d at boottime %lld.%.3ld, %s", i,
+ (long long)actual_time.tv_sec,
+ actual_time.tv_nsec / NSEC_PER_MSEC,
+ ctime(&t));
+
+ KLOG_INFO("suspend_stress", "timer fired: %d at boottime %lld.%.3ld, %s", i,
+ (long long)actual_time.tv_sec,
+ actual_time.tv_nsec / NSEC_PER_MSEC,
+ ctime(&t));
+
+ if (count > 0)
+ count--;
+ }
+ return 0;
+}
diff --git a/tests/tcp_nuke_addr/Android.mk b/tests/tcp_nuke_addr/Android.mk
new file mode 100644
index 0000000..2eef608
--- /dev/null
+++ b/tests/tcp_nuke_addr/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := tcp_nuke_addr_test
+
+LOCAL_C_INCLUDES += frameworks/native/include external/libcxx/include
+LOCAL_CPPFLAGS += -std=c++11 -Wall -Werror
+LOCAL_SHARED_LIBRARIES := libc++
+LOCAL_SRC_FILES := tcp_nuke_addr_test.cpp
+LOCAL_MODULE_TAGS := eng tests
+
+include $(BUILD_NATIVE_TEST)
diff --git a/tests/tcp_nuke_addr/tcp_nuke_addr_test.cpp b/tests/tcp_nuke_addr/tcp_nuke_addr_test.cpp
new file mode 100644
index 0000000..587f768
--- /dev/null
+++ b/tests/tcp_nuke_addr/tcp_nuke_addr_test.cpp
@@ -0,0 +1,150 @@
+#include <arpa/inet.h>
+#include <linux/if.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <mutex>
+#include <thread>
+
+#include "utils/RWLock.h"
+
+// Defined only in ifc_utils.c, in the kernel, and in the NDK.
+#ifndef SIOCKILLADDR
+#define SIOCKILLADDR 0x8939
+#endif
+
+#ifndef TCP_LINGER2
+#define TCP_LINGER2 8
+#endif
+
+#define KILL_INTERVAL_MS 10
+#define CONNECT_THREADS 1
+
+#define PERROR_EXIT(msg) { do { perror((msg)); exit(1); } while (0); };
+
+
+// Ensures that sockets don't stay in TIME_WAIT state.
+void setSoLinger(int s) {
+ const struct linger l = {
+ 0, // off
+ 0, // 0 seconds
+ };
+ if (setsockopt(s, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) == -1) {
+ PERROR_EXIT("SO_LINGER");
+ }
+ const int nolinger = -1;
+ if (setsockopt(s, SOL_TCP, TCP_LINGER2, &nolinger, sizeof(nolinger)) == -1) {
+ PERROR_EXIT("TCP_LINGER2");
+ }
+}
+
+
+// Binds to a random port on a random loopback address. We don't just use 127.0.0.1 because we don't
+// want this test to kill unrelated connections on loopback.
+int bindRandomAddr() {
+ sockaddr_in sin;
+ sin.sin_family = AF_INET;
+ sin.sin_port = 0;
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ while (sin.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
+ arc4random_buf(
+ ((uint8_t *) &sin.sin_addr.s_addr) + 1,
+ sizeof(sin.sin_addr.s_addr) - 1);
+ }
+
+ int listensock;
+ if ((listensock = socket(AF_INET, SOCK_STREAM, 0)) == -1) PERROR_EXIT("listensock");
+ if (bind(listensock, (sockaddr *) &sin, sizeof(sin)) == -1) PERROR_EXIT("bind");
+ if (listen(listensock, 10) == -1) PERROR_EXIT("listen");
+
+ return listensock;
+}
+
+
+// Thread that calls SIOCKILLADDR in a loop.
+void killSockets(sockaddr_in listenaddr, int intervalMs, android::RWLock *lock) {
+ ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ listenaddr.sin_port = 0;
+ strncpy(ifr.ifr_name, "lo", strlen("lo"));
+ memcpy(&ifr.ifr_addr, &listenaddr, sizeof(listenaddr));
+
+ int ioctlsock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (ioctlsock == -1) PERROR_EXIT("ioctlsock");
+ while(true) {
+ lock->writeLock();
+ if (ioctl(ioctlsock, SIOCKILLADDR, &ifr) != 0) {
+ PERROR_EXIT("SIOCKILLADDR failed, did you run 32-bit userspace on a 64-bit kernel?");
+ }
+ lock->unlock();
+ std::this_thread::sleep_for(std::chrono::milliseconds(intervalMs));
+ }
+}
+
+
+// Thread that calls connect() in a loop.
+void connectLoop(sockaddr_in listenaddr, int listensock,
+ android::RWLock *lock, std::atomic<unsigned int> *attempts) {
+ while(true) {
+ int s = socket(AF_INET, SOCK_STREAM, 0);
+ setSoLinger(s);
+
+ // Don't call SIOCKILLADDR while connect() is running, or we'll end up with lots of
+ // connections in state FIN_WAITx or TIME_WAIT, which will then slow down future
+ // due to SYN retransmits.
+ lock->readLock();
+ if (connect(s, (sockaddr *) &listenaddr, sizeof(listenaddr)) == -1) PERROR_EXIT("connect");
+ lock->unlock();
+
+ send(s, "foo", 3, 0);
+ int acceptedsock = accept(listensock, NULL, 0);
+ if (close(acceptedsock) == -1) PERROR_EXIT("close");
+ if (close(s) == -1) PERROR_EXIT("close");
+
+ attempts->fetch_add(1);
+ }
+}
+
+
+// Thread that prints progress every second.
+void progressThread(std::atomic<unsigned int> *attempts) {
+ uint32_t elapsed = 0;
+ uint32_t total, previous = 0;
+ while (true) {
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ elapsed++;
+ total = attempts->load();
+ printf("%ds: %u cps, total %u\n", elapsed, total-previous, total);
+ fflush(stdout);
+ previous = total;
+ }
+}
+
+
+int main() {
+ int listensock = bindRandomAddr();
+ struct sockaddr_in sin;
+ socklen_t len = sizeof(sin);
+ if (getsockname(listensock, (sockaddr *) &sin, &len) == -1) PERROR_EXIT("getsockname");
+
+ printf("Using address %s:%d\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+
+ android::RWLock lock;
+ std::atomic<unsigned int> attempts;
+ attempts.store(0);
+
+ std::thread t0(killSockets, sin, KILL_INTERVAL_MS, &lock);
+ std::thread *connectThreads[CONNECT_THREADS];
+ for (size_t i = 0; i < CONNECT_THREADS; i++) {
+ connectThreads[i] = new std::thread(connectLoop, sin, listensock, &lock, &attempts);
+ }
+ std::thread t1(progressThread, &attempts);
+ t1.join();
+
+ return 0;
+}
diff --git a/tests/timetest/Android.mk b/tests/timetest/Android.mk
new file mode 100644
index 0000000..b2a1aa5
--- /dev/null
+++ b/tests/timetest/Android.mk
@@ -0,0 +1,42 @@
+# 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)
+
+# -----------------------------------------------------------------------------
+# Unit tests.
+# -----------------------------------------------------------------------------
+
+test_c_flags := \
+ -fstack-protector-all \
+ -g \
+ -Wall -Wextra \
+ -Werror \
+ -fno-builtin \
+ -std=gnu++11
+
+test_src_files := \
+ rtc_test.cpp
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := time-unit-tests
+LOCAL_MODULE_TAGS := tests
+LOCAL_CFLAGS += $(test_c_flags)
+LOCAL_SRC_FILES := $(test_src_files)
+include $(BUILD_NATIVE_TEST)
+
diff --git a/tests/timetest/rtc_test.cpp b/tests/timetest/rtc_test.cpp
new file mode 100644
index 0000000..26ca13a
--- /dev/null
+++ b/tests/timetest/rtc_test.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/rtc.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+static int hwtime(int flag, int request, struct rtc_time *tm) {
+ static const char rtc[] = "/dev/rtc0";
+
+ int ret = TEMP_FAILURE_RETRY(access(rtc, flag & O_WRONLY) ? W_OK : R_OK);
+ if (ret < 0) {
+ ret = -errno;
+ }
+ if (ret == -EACCES) {
+ return ret;
+ }
+
+ if (flag & O_WRONLY) {
+ struct stat st;
+ ret = TEMP_FAILURE_RETRY(stat(rtc, &st));
+ if (ret < 0) {
+ ret = -errno;
+ } else if (!(st.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))) {
+ ret = -EACCES;
+ }
+ }
+ if (ret == -EACCES) {
+ return ret;
+ }
+
+ do {
+ ret = TEMP_FAILURE_RETRY(open(rtc, flag));
+ if (ret < 0) {
+ ret = -errno;
+ }
+ } while (ret == -EBUSY);
+ if (ret < 0) {
+ return ret;
+ }
+
+ int fd = ret;
+ do {
+ ret = TEMP_FAILURE_RETRY(ioctl(fd, request, tm));
+ if (ret < 0) {
+ ret = -errno;
+ }
+ } while (ret == -EBUSY);
+ close(fd);
+ return ret;
+}
+
+static int rd_hwtime(struct rtc_time *tm) {
+ return hwtime(O_RDONLY, RTC_RD_TIME, tm);
+}
+
+static int set_hwtime(struct rtc_time *tm) {
+ return hwtime(O_WRONLY, RTC_SET_TIME, tm);
+}
+
+static void rtc_rollover(int start, int end) {
+ struct rtc_time roll;
+ memset(&roll, 0, sizeof(roll));
+ ASSERT_LE(0, rd_hwtime(&roll));
+ int mday[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ mday[1] = (roll.tm_year % 4) ? 28 : 29;
+ ASSERT_LE(0, roll.tm_sec);
+ ASSERT_GT(60, roll.tm_sec);
+ ASSERT_LE(0, roll.tm_min);
+ ASSERT_GT(60, roll.tm_min);
+ ASSERT_LE(0, roll.tm_hour);
+ ASSERT_GT(24, roll.tm_hour);
+ ASSERT_LE(0, roll.tm_mday);
+ ASSERT_GE(mday[roll.tm_mon], roll.tm_mday);
+ ASSERT_LE(0, roll.tm_mon);
+ ASSERT_GT(12, roll.tm_mon);
+ ASSERT_LE(0, roll.tm_year);
+ ASSERT_GT(138, roll.tm_year);
+
+ // Wait for granular clock
+ struct rtc_time save = roll;
+ static const useconds_t timeout_sleep = 10000;
+ static const int timeout_num = 2000000 / timeout_sleep;
+ int timeout;
+ for (timeout = timeout_num; timeout && (roll.tm_year == save.tm_year); --timeout) {
+ ASSERT_LE(0, rd_hwtime(&save));
+ usleep(timeout_sleep);
+ }
+
+ memset(&roll, 0, sizeof(roll));
+ roll.tm_sec = 59;
+ roll.tm_min = 59;
+ roll.tm_hour = 23;
+ roll.tm_mday = 31;
+ roll.tm_mon = 11;
+ roll.tm_year = 70;
+ roll.tm_wday = 0;
+ roll.tm_yday = 0;
+ roll.tm_isdst = 0;
+
+ bool eacces = true;
+ for (roll.tm_year = start; roll.tm_year < end; ++roll.tm_year) {
+ struct rtc_time tm = roll;
+ int __set_hwtime = set_hwtime(&tm);
+ // Allowed to be 100% denied for writing
+ if ((__set_hwtime == -EACCES) && (eacces == true)) {
+ continue;
+ }
+ eacces = false;
+ // below 2016, permitted to error out.
+ if ((__set_hwtime == -EINVAL) && (roll.tm_year < 116)) {
+ continue;
+ }
+ ASSERT_LE(0, __set_hwtime);
+ ASSERT_LE(0, rd_hwtime(&tm));
+ ASSERT_EQ(roll.tm_sec, tm.tm_sec);
+ ASSERT_EQ(roll.tm_min, tm.tm_min);
+ ASSERT_EQ(roll.tm_hour, tm.tm_hour);
+ ASSERT_EQ(roll.tm_mday, tm.tm_mday);
+ ASSERT_EQ(roll.tm_mon, tm.tm_mon);
+ ASSERT_EQ(roll.tm_year, tm.tm_year);
+ for (timeout = timeout_num; timeout && (roll.tm_year == tm.tm_year); --timeout) {
+ ASSERT_LE(0, rd_hwtime(&tm));
+ usleep(timeout_sleep);
+ }
+ ASSERT_EQ(roll.tm_year + 1, tm.tm_year);
+ EXPECT_LT(timeout_num * 5 / 100, timeout);
+ EXPECT_GT(timeout_num * 95 / 100, timeout);
+
+ // correct saved time to compensate for rollover check
+ if (++save.tm_sec >= 60) {
+ save.tm_sec = 0;
+ if (++save.tm_min >= 60) {
+ save.tm_min = 0;
+ if (++save.tm_hour >= 24) {
+ save.tm_hour = 0;
+ mday[1] = (save.tm_year % 4) ? 28 : 29;
+ if (++save.tm_mday >= mday[save.tm_mon]) {
+ save.tm_mday = 1;
+ if (++save.tm_mon >= 12) {
+ save.tm_mon = 0;
+ ++save.tm_year;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!eacces) {
+ ASSERT_LE(0, set_hwtime(&save));
+ }
+ ASSERT_LE(0, rd_hwtime(&roll));
+
+ if (!eacces) {
+ ASSERT_EQ(save.tm_sec, roll.tm_sec);
+ ASSERT_EQ(save.tm_min, roll.tm_min);
+ ASSERT_EQ(save.tm_hour, roll.tm_hour);
+ ASSERT_EQ(save.tm_mday, roll.tm_mday);
+ ASSERT_EQ(save.tm_mon, roll.tm_mon);
+ ASSERT_EQ(save.tm_year, roll.tm_year);
+ }
+}
+
+TEST(time, rtc_rollover_1970_1990) {
+ rtc_rollover(70, 90);
+}
+
+TEST(time, rtc_rollover_1990_2010) {
+ rtc_rollover(90, 110);
+}
+
+TEST(time, rtc_rollover_2010_2030) {
+ rtc_rollover(110, 130);
+}
+
+TEST(time, rtc_rollover_2030_2037) {
+ rtc_rollover(130, 137);
+}
diff --git a/tests/timetest/timetest.c b/tests/timetest/timetest.c
new file mode 100644
index 0000000..baba36e
--- /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) {