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) { + r.tv_sec++; + r.tv_nsec -= 1000 * 1000 * 1000; + } + return r; +} + +static struct timespec ts_min(struct timespec a, struct timespec b) +{ + if(a.tv_sec < b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_nsec < b.tv_nsec)) + return a; + else + return b; +} + +static struct timespec ts_max(struct timespec a, struct timespec b) +{ + if(a.tv_sec < b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_nsec < b.tv_nsec)) + return b; + else + return a; +} + +int main(int argc, char **argv) +{ + long long tnow, tlast; + struct timespec t1, dtmin, dtminp, dtmax; + int print_interval = 50000; + int print_countdown = 1; + int clock_id = CLOCK_MONOTONIC; + dtmin.tv_sec = INT_MAX; + dtmin.tv_nsec = 0; + dtminp.tv_sec = INT_MAX; + dtminp.tv_nsec = 0; + dtmax.tv_sec = 0; + dtmax.tv_nsec = 0; + tlast = 0; + + if(argc == 2) { + clock_id = atoi(argv[1]); + printf("using clock %d\n", clock_id); + } + clock_gettime(clock_id, &t1); + + for(;;) { + struct timespec t, dt; + clock_gettime(clock_id, &t); + dt = ts_sub(t, t1); + t1 = t; + dtmin = ts_min(dtmin, dt); + if(dt.tv_sec > 0 || dt.tv_nsec > 0) + dtminp = ts_min(dtminp, dt); + if(print_countdown != print_interval) + dtmax = ts_max(dtmax, dt); + if(--print_countdown == 0) { + fprintf(stderr,"%09ld.%09ld, dt %ld.%09ld, min %ld.%09ld, minp %ld.%09ld, max %ld.%09ld\n", + t.tv_sec, t.tv_nsec, dt.tv_sec, dt.tv_nsec, + dtmin.tv_sec, dtmin.tv_nsec, dtminp.tv_sec, dtminp.tv_nsec, + dtmax.tv_sec, dtmax.tv_nsec); + print_countdown = print_interval; + } + } + for(;;) { + tnow = nanotime(); + if(tnow < tlast) { +#if 0 + fprintf(stderr,"time went backwards: %lld -> %lld\n", + tlast, tnow); + exit(1); +#endif + fprintf(stderr,"%lld ROLLBACK\n", tnow); + } else { + fprintf(stderr,"%lld\n", tnow); + } + tlast = tnow; + } + + return 0; +}
diff --git a/tests/uevents/Android.mk b/tests/uevents/Android.mk new file mode 100644 index 0000000..fb8a851 --- /dev/null +++ b/tests/uevents/Android.mk
@@ -0,0 +1,11 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := uevents.c + +LOCAL_SHARED_LIBRARIES += libcutils +LOCAL_MODULE:= uevents + +LOCAL_CFLAGS := -Wno-unused-parameter + +include $(BUILD_EXECUTABLE)
diff --git a/tests/uevents/uevents.c b/tests/uevents/uevents.c new file mode 100644 index 0000000..1ca4cfe --- /dev/null +++ b/tests/uevents/uevents.c
@@ -0,0 +1,45 @@ +/* + * 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 <cutils/uevent.h> +#include <stdio.h> + +#define UEVENT_MSG_LEN 1024 + +int main(int argc, char *argv[]) +{ + int device_fd; + char msg[UEVENT_MSG_LEN+2]; + int n; + int i; + + device_fd = uevent_open_socket(64*1024, true); + if(device_fd < 0) + return -1; + + while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) { + msg[n] = '\0'; + msg[n+1] = '\0'; + + for (i = 0; i < n; i++) + if (msg[i] == '\0') + msg[i] = ' '; + + printf("%s\n", msg); + } + + return 0; +}
diff --git a/tests/wifi/Android.mk b/tests/wifi/Android.mk new file mode 100644 index 0000000..4343259 --- /dev/null +++ b/tests/wifi/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/wifi/stress/Android.mk b/tests/wifi/stress/Android.mk new file mode 100644 index 0000000..2361483 --- /dev/null +++ b/tests/wifi/stress/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. +# Copyright The Android Open Source Project + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := tests +LOCAL_MODULE := wifiLoadScanAssoc +LOCAL_SRC_FILES := wifiLoadScanAssoc.c +LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libhardware_legacy +LOCAL_STATIC_LIBRARIES += libtestUtil +LOCAL_C_INCLUDES += system/extras/tests/include \ + hardware/libhardware_legacy/include + +include $(BUILD_NATIVE_TEST)
diff --git a/tests/wifi/stress/wifiLoadScanAssoc.c b/tests/wifi/stress/wifiLoadScanAssoc.c new file mode 100644 index 0000000..5dc2692 --- /dev/null +++ b/tests/wifi/stress/wifiLoadScanAssoc.c
@@ -0,0 +1,517 @@ +/* + * 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. + * + */ + +/* + * WiFi load, scan, associate, unload stress test + * + * Repeatedly executes the following sequence: + * + * 1. Load WiFi driver + * 2. Start supplicant + * 3. Random delay + * 4. Obtain supplicant status (optional) + * 5. Stop supplicant + * 6. Unload WiFi driver + * + * The "Obtain supplicant status" step is optional and is pseudo + * randomly performed 50% of the time. The default range of + * delay after start supplicant is intentionally selected such + * that the obtain supplicant status and stop supplicant steps + * may be performed while the WiFi driver is still performing a scan + * or associate. The default values are given by DEFAULT_DELAY_MIN + * and DEFAULT_DELAY_MAX. Other values can be specified through the + * use of the -d and -D command-line options. + * + * Each sequence is refered to as a pass and by default an unlimited + * number of passes are performed. An override of the range of passes + * to be executed is available through the use of the -s (start) and + * -e (end) command-line options. Can also specify a single specific + * pass via the -p option. There is also a default time in which the + * test executes, which is given by DEFAULT_DURATION and can be overriden + * through the use of the -t command-line option. + */ + +#define _GNU_SOURCE + +#include <assert.h> +#include <errno.h> +#include <libgen.h> +#include <math.h> +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +#include <sys/syscall.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <hardware_legacy/wifi.h> + +#define LOG_TAG "wifiLoadScanAssocTest" +#include <utils/Log.h> +#include <testUtil.h> + +#define DEFAULT_START_PASS 0 +#define DEFAULT_END_PASS 999 +#define DEFAULT_DURATION FLT_MAX // A fairly long time, so that + // range of passes will have + // precedence +#define DEFAULT_DELAY_MIN 0.0 // Min delay after start supplicant +#define DEFAULT_DELAY_MAX 20.0 // Max delay after start supplicant +#define DELAY_EXP 150.0 // Exponent which determines the + // amount by which values closer + // to DELAY_MIN are favored. + +#define CMD_STATUS "wpa_cli status 2>&1" +#define CMD_STOP_FRAMEWORK "stop 2>&1" +#define CMD_START_FRAMEWORK "start 2>&1" + +#define MAXSTR 100 +#define MAXCMD 500 + +typedef unsigned int bool_t; +#define true (0 == 0) +#define false (!true) + +// File scope variables +cpu_set_t availCPU; +unsigned int numAvailCPU; +float delayMin = DEFAULT_DELAY_MIN; +float delayMax = DEFAULT_DELAY_MAX; +bool_t driverLoadedAtStart; + +// Command-line mutual exclusion detection flags. +// Corresponding flag set true once an option is used. +bool_t eFlag, sFlag, pFlag; + +// File scope prototypes +static void init(void); +static void randDelay(void); +static void randBind(const cpu_set_t *availSet, int *chosenCPU); + +/* + * Main + * + * Performs the following high-level sequence of operations: + * + * 1. Command-line parsing + * + * 2. Initialization + * + * 3. Execute passes that repeatedly perform the WiFi load, scan, + * associate, unload sequence. + * + * 4. Restore state of WiFi driver to state it was at the + * start of the test. + * + * 5. Restart framework + */ +int +main(int argc, char *argv[]) +{ + FILE *fp; + int rv, opt; + int cpu; + char *chptr; + unsigned int pass; + char cmd[MAXCMD]; + float duration = DEFAULT_DURATION; + unsigned int startPass = DEFAULT_START_PASS, endPass = DEFAULT_END_PASS; + struct timeval startTime, currentTime, delta; + + testSetLogCatTag(LOG_TAG); + + // Parse command line arguments + while ((opt = getopt(argc, argv, "d:D:s:e:p:t:?")) != -1) { + switch (opt) { + case 'd': // Minimum Delay + delayMin = strtod(optarg, &chptr); + if ((*chptr != '\0') || (delayMin < 0.0)) { + testPrintE("Invalid command-line specified minimum delay " + "of: %s", optarg); + exit(1); + } + break; + + case 'D': // Maximum Delay + delayMax = strtod(optarg, &chptr); + if ((*chptr != '\0') || (delayMax < 0.0)) { + testPrintE("Invalid command-line specified maximum delay " + "of: %s", optarg); + exit(2); + } + break; + + case 't': // Duration + duration = strtod(optarg, &chptr); + if ((*chptr != '\0') || (duration < 0.0)) { + testPrintE("Invalid command-line specified duration of: %s", + optarg); + exit(3); + } + break; + + case 's': // Starting Pass + if (sFlag || pFlag) { + testPrintE("Invalid combination of command-line options,"); + if (sFlag) { + testPrintE(" -s flag specified multiple times."); + } else { + testPrintE(" -s and -p flags are mutually exclusive."); + } + exit(10); + } + sFlag = true; + startPass = strtoul(optarg, &chptr, 10); + if (*chptr != '\0') { + testPrintE("Invalid command-line specified starting pass " + "of: %s", optarg); + exit(4); + } + break; + + case 'e': // Ending Pass + if (eFlag || pFlag) { + testPrintE("Invalid combination of command-line options,"); + if (sFlag) { + testPrintE(" -e flag specified multiple times."); + } else { + testPrintE(" -e and -p flags are mutually exclusive."); + } + exit(11); + } + eFlag = true; + endPass = strtoul(optarg, &chptr, 10); + if (*chptr != '\0') { + testPrintE("Invalid command-line specified ending pass " + "of: %s", optarg); + exit(5); + } + break; + + case 'p': // Single Specific Pass + if (pFlag || sFlag || eFlag) { + testPrintE("Invalid combination of command-line options,"); + if (pFlag) { + testPrintE(" -p flag specified multiple times."); + } else { + testPrintE(" -p and -%c flags are mutually exclusive.", + (sFlag) ? 's' : 'e'); + } + exit(12); + } + pFlag = true; + endPass = startPass = strtoul(optarg, &chptr, 10); + if (*chptr != '\0') { + testPrintE("Invalid command-line specified pass " + "of: %s", optarg); + exit(13); + } + break; + + case '?': + default: + testPrintE(" %s [options]", basename(argv[0])); + testPrintE(" options:"); + testPrintE(" -s Starting pass"); + testPrintE(" -e Ending pass"); + testPrintE(" -p Specific single pass"); + testPrintE(" -t Duration"); + testPrintE(" -d Delay min"); + testPrintE(" -D Delay max"); + exit(((optopt == 0) || (optopt == '?')) ? 0 : 6); + } + } + if (delayMax < delayMin) { + testPrintE("Unexpected maximum delay less than minimum delay"); + testPrintE(" delayMin: %f delayMax: %f", delayMin, delayMax); + exit(7); + } + if (endPass < startPass) { + testPrintE("Unexpected ending pass before starting pass"); + testPrintE(" startPass: %u endPass: %u", startPass, endPass); + exit(8); + } + if (argc != optind) { + testPrintE("Unexpected command-line postional argument"); + testPrintE(" %s [-s start_pass] [-e end_pass] [-d duration]", + basename(argv[0])); + exit(9); + } + testPrintI("duration: %g", duration); + testPrintI("startPass: %u", startPass); + testPrintI("endPass: %u", endPass); + testPrintI("delayMin: %f", delayMin); + testPrintI("delayMax: %f", delayMax); + + init(); + + // For each pass + gettimeofday(&startTime, NULL); + for (pass = startPass; pass <= endPass; pass++) { + // Stop if duration of work has already been performed + gettimeofday(¤tTime, NULL); + delta = tvDelta(&startTime, ¤tTime); + if (tv2double(&delta) > duration) { break; } + + testPrintI("==== Starting pass: %u", pass); + + // Use a pass dependent sequence of random numbers + srand48(pass); + + // Load WiFi Driver + randBind(&availCPU, &cpu); + if ((rv = wifi_load_driver()) != 0) { + testPrintE("CPU: %i wifi_load_driver() failed, rv: %i\n", + cpu, rv); + exit(20); + } + testPrintI("CPU: %i wifi_load_driver succeeded", cpu); + + // Start Supplicant + randBind(&availCPU, &cpu); + if ((rv = wifi_start_supplicant(false)) != 0) { + testPrintE("CPU: %i wifi_start_supplicant() failed, rv: %i\n", + cpu, rv); + exit(21); + } + testPrintI("CPU: %i wifi_start_supplicant succeeded", cpu); + + // Sleep a random amount of time + randDelay(); + + /* + * Obtain WiFi Status + * Half the time skip this step, which helps increase the + * level of randomization. + */ + if (testRandBool()) { + rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STATUS); + if (rv >= (signed) sizeof(cmd) - 1) { + testPrintE("Command too long for: %s\n", CMD_STATUS); + exit(22); + } + testExecCmd(cmd); + } + + // Stop Supplicant + randBind(&availCPU, &cpu); + if ((rv = wifi_stop_supplicant(false)) != 0) { + testPrintE("CPU: %i wifi_stop_supplicant() failed, rv: %i\n", + cpu, rv); + exit(23); + } + testPrintI("CPU: %i wifi_stop_supplicant succeeded", cpu); + + // Unload WiFi Module + randBind(&availCPU, &cpu); + if ((rv = wifi_unload_driver()) != 0) { + testPrintE("CPU: %i wifi_unload_driver() failed, rv: %i\n", + cpu, rv); + exit(24); + } + testPrintI("CPU: %i wifi_unload_driver succeeded", cpu); + + testPrintI("==== Completed pass: %u", pass); + } + + // If needed restore WiFi driver to state it was in at the + // start of the test. It is assumed that it the driver + // was loaded, then the wpa_supplicant was also running. + if (driverLoadedAtStart) { + // Load driver + if ((rv = wifi_load_driver()) != 0) { + testPrintE("main load driver failed, rv: %i", rv); + exit(25); + } + + // Start supplicant + if ((rv = wifi_start_supplicant(false)) != 0) { + testPrintE("main start supplicant failed, rv: %i", rv); + exit(26); + } + + // Obtain WiFi Status + rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STATUS); + if (rv >= (signed) sizeof(cmd) - 1) { + testPrintE("Command too long for: %s\n", CMD_STATUS); + exit(22); + } + testExecCmd(cmd); + } + + // Start framework + rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK); + if (rv >= (signed) sizeof(cmd) - 1) { + testPrintE("Command too long for: %s\n", CMD_START_FRAMEWORK); + exit(27); + } + testExecCmd(cmd); + + testPrintI("Successfully completed %u passes", pass - startPass); + + return 0; +} + +/* + * Initialize + * + * Perform testcase initialization, which includes: + * + * 1. Determine which CPUs are available for use + * + * 2. Determine total number of available CPUs + * + * 3. Stop framework + * + * 4. Determine whether WiFi driver is loaded and if so + * stop wpa_supplicant and unload WiFi driver. + */ +void +init(void) +{ + int rv; + unsigned int n1; + char cmd[MAXCMD]; + + // Use whichever CPUs are available at start of test + rv = sched_getaffinity(0, sizeof(availCPU), &availCPU); + if (rv != 0) { + testPrintE("init sched_getaffinity failed, rv: %i errno: %i", + rv, errno); + exit(40); + } + + // How many CPUs are available + numAvailCPU = 0; + for (n1 = 0; n1 < CPU_SETSIZE; n1++) { + if (CPU_ISSET(n1, &availCPU)) { numAvailCPU++; } + } + testPrintI("numAvailCPU: %u", numAvailCPU); + + // Stop framework + rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK); + if (rv >= (signed) sizeof(cmd) - 1) { + testPrintE("Command too long for: %s\n", CMD_STOP_FRAMEWORK); + exit(41); + } + testExecCmd(cmd); + + // Is WiFi driver loaded? + // If so stop the wpa_supplicant and unload the driver. + driverLoadedAtStart = is_wifi_driver_loaded(); + testPrintI("driverLoadedAtStart: %u", driverLoadedAtStart); + if (driverLoadedAtStart) { + // Stop wpa_supplicant + // Might already be stopped, in which case request should + // return immediately with success. + if ((rv = wifi_stop_supplicant(false)) != 0) { + testPrintE("init stop supplicant failed, rv: %i", rv); + exit(42); + } + testPrintI("Stopped wpa_supplicant"); + + if ((rv = wifi_unload_driver()) != 0) { + testPrintE("init unload driver failed, rv: %i", rv); + exit(43); + } + testPrintI("WiFi driver unloaded"); + } + +} + +/* + * Random Delay + * + * Delays for a random amount of time within the range given + * by the file scope variables delayMin and delayMax. The + * selected amount of delay can come from any part of the + * range, with a bias towards values closer to delayMin. + * The amount of bias is determined by the setting of DELAY_EXP. + * The setting of DELAY_EXP should always be > 1.0, with higher + * values causing a more significant bias toward the value + * of delayMin. + */ +void randDelay(void) +{ + const unsigned long nanosecspersec = 1000000000; + float fract, biasedFract, amt; + struct timeval startTime, endTime; + + // Obtain start time + gettimeofday(&startTime, NULL); + + // Determine random amount to sleep. + // Values closer to delayMin are prefered by an amount + // determined by the value of DELAY_EXP. + fract = testRandFract(); + biasedFract = pow(DELAY_EXP, fract) / pow(DELAY_EXP, 1.0); + amt = delayMin + ((delayMax - delayMin) * biasedFract); + + // Delay + testDelay(amt); + + // Obtain end time and display delta + gettimeofday(&endTime, NULL); + testPrintI("delay: %.2f", + (float) (tv2double(&endTime) - tv2double(&startTime))); +} + +static void +randBind(const cpu_set_t *availSet, int *chosenCPU) +{ + int rv; + cpu_set_t cpuset; + int chosenAvail, avail, cpu, currentCPU; + + // Randomly bind to a CPU + // Lower 16 bits from random number generator thrown away, + // because the low-order bits tend to have the same sequence for + // different seed values. + chosenAvail = testRandMod(numAvailCPU); + CPU_ZERO(&cpuset); + avail = 0; + for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { + if (CPU_ISSET(cpu, availSet)) { + if (chosenAvail == avail) { + CPU_SET(cpu, &cpuset); + break; + } + avail++; + } + } + assert(cpu < CPU_SETSIZE); + sched_setaffinity(0, sizeof(cpuset), &cpuset); + + // Confirm executing on requested CPU + if ((currentCPU = sched_getcpu()) < 0) { + testPrintE("randBind sched_getcpu() failed, rv: %i errno: %i", + currentCPU, errno); + exit(80); + + } + if (currentCPU != cpu) { + testPrintE("randBind executing on unexpected CPU %i, expected %i", + currentCPU, cpu); + exit(81); + } + + // Let the caller know which CPU was chosen + *chosenCPU = cpu; +}
diff --git a/tests/workloads/atrace-uncompress.py b/tests/workloads/atrace-uncompress.py new file mode 100644 index 0000000..5efb698 --- /dev/null +++ b/tests/workloads/atrace-uncompress.py
@@ -0,0 +1,35 @@ +# +# Uncompress a file generated via atrace -z +# +# Usage: python atrace-uncompress.py infile > outfile +# +import sys, zlib + +def main(): + + if len(sys.argv) != 2: + print >> sys.stderr, ('Usage: %s inputfile' % sys.argv[0]) + sys.exit(1) + + infile = open(sys.argv[1], "rb") + out = infile.read() + parts = out.split('\nTRACE:', 1) + + data = ''.join(parts[1]) + + # Remove CR characters + if data.startswith('\r\n'): + data = data.replace('\r\n', '\n') + + # Skip the initial newline. + data = data[1:] + + if not data: + print >> sys.stderr, ('No trace data found') + sys.exit(1) + + out = zlib.decompress(data) + print(out) + +if __name__ == '__main__': + main()
diff --git a/tests/workloads/capture.sh b/tests/workloads/capture.sh new file mode 100755 index 0000000..3b2f446 --- /dev/null +++ b/tests/workloads/capture.sh Binary files differ
diff --git a/tests/workloads/defs.sh b/tests/workloads/defs.sh new file mode 100755 index 0000000..a2b7138 --- /dev/null +++ b/tests/workloads/defs.sh Binary files differ
diff --git a/tests/workloads/feedly-chrome.sh b/tests/workloads/feedly-chrome.sh new file mode 100755 index 0000000..4c7002f --- /dev/null +++ b/tests/workloads/feedly-chrome.sh
@@ -0,0 +1,111 @@ +# Script to automate the following sequence: +# - Open Feedly +# - Open an article +# - Scroll to bottome +# - Open the same article in Chrome +# - Scroll the article +# - Back to Feely (should still be in memory) +# - Home screen +# ---- repeat ---- +# +# Currently works on volantis only (verticle orientation) +# + +CMDDIR=$(dirname $0 2>/dev/null) +CMDDIR=${CMDDIR:=.} +. $CMDDIR/defs.sh + +case "$DEVICE" in +(volantis) + echo volantis... + feedlyArticle="500 700" + feedlyOptions="1480 100" + feedlyBrowserSelect="1350 650" + feedlyArticleSwipeUp="700 700 700 50 50" + feedlyArticleSwipeDown="700 200 700 700 50" + chromeSwipe="700 700 700 50 50" + ;; +(shamu|*) + echo shamu... + feedlyArticle="676 500" + feedlyOptions="1327 207" + feedlyBrowserSelect="1278 1191" + feedlyArticleSwipeUp="700 1847 700 400 50" + feedlyArticleSwipeDown="700 400 700 1847 50" + chromeSwipe="700 1847 700 400 50" + ;; +(hammerhead|*) + echo "Error: No feedly screen geometry information available for $DEVICE" + exit 1;; +esac + +feedlySwitchToTime=600 + +# start feedly, if not installed, error out +t=$(forceStartActivity feedly) +checkIsRunning feedly "initial start of feedly" +echo Feedly start time = ${t}ms + +# start chrome, if not installed, error out +t=$(forceStartActivity chrome) +checkIsRunning chrome "initial start of chrome" +echo Chrome start time = ${t}ms +sleep 1 + +feedlyStartTimes=0 + +cur=1 +while [ $cur -le $iterations ] +do + echo ======================================= + echo Iteration $cur of $iterations + echo ======================================= + startInstramentation + t=$(startActivity feedly) + if [ $(checkStartTime "$t" $feedlySwitchToTime) != true ]; then + handleError Feedly took too long to start: $t v $feedlySwitchToTime: $? + # for now, not fatal + # exit 1 + fi + sleep 2 + ((feedlyStartTimes=feedlyStartTimes+t)) + echo feedly started in ${t}ms + checkIsRunning chrome "switch back to feedly" + checkIsRunning googlequicksearchbox "switch back to feedly" + + # click on first article + doTap $feedlyArticle + sleep 2 + + # scroll through article + doSwipe $feedlyArticleSwipeUp + sleep 5 + checkIsRunning chrome "feedly swipe" + checkIsRunning googlequicksearchbox "feedly swipe" + + # scroll back to top + doSwipe $feedlyArticleSwipeDown + sleep 2 + + # switch to chrome + # 1. click on menu bar + doTap $feedlyOptions + sleep 1 + # 2. click on browser + doTap $feedlyBrowserSelect + sleep 10 + + checkIsRunning feedly "switch to chrome" + checkIsRunning googlequicksearchbox "switch to chrome" + + # Now we're back in chrome, swipe to bottom of article + doSwipe $chromeSwipe + sleep 2 + checkIsRunning feedly "swiped chrome" + stopInstramentation + ((cur=cur+1)) +done +((feedlyAve=feedlyStartTimes/iterations)) +echo Avg start times: feedly: ${feedlyAve}ms + +doKeyevent HOME
diff --git a/tests/workloads/recentfling.sh b/tests/workloads/recentfling.sh new file mode 100755 index 0000000..092c8d9 --- /dev/null +++ b/tests/workloads/recentfling.sh
@@ -0,0 +1,150 @@ +# +# Script to start a set of apps, switch to recents and fling it back and forth. +# For each iteration, Total frames and janky frames are reported. +# +# Options are described below. +# +# Works for volantis, shamu, and hammerhead. Can be pushed and executed on +# the device. +# +iterations=10 +startapps=1 +capturesystrace=0 + +function processLocalOption { + ret=0 + case "$1" in + (-N) startapps=0;; + (-A) unset appList;; + (-L) appList=$2; shift; ret=1;; + (-T) capturesystrace=1;; + (*) + echo "$0: unrecognized option: $1" + echo; echo "Usage: $0 [options]" + echo "-A : use all known applications" + echo "-L applist : list of applications" + echo " default: $appList" + echo "-N : no app startups, just fling" + echo "-g : generate activity strings" + echo "-i iterations" + echo "-T : capture systrace on each iteration" + exit 1;; + esac + return $ret +} + +CMDDIR=$(dirname $0 2>/dev/null) +CMDDIR=${CMDDIR:=.} +. $CMDDIR/defs.sh + +case $DEVICE in +(shamu|hammerhead) + flingtime=300 + downCount=2 + upCount=6 + UP="70 400 70 100 $flingtime" + DOWN="70 100 70 400 $flingtime";; +(bullhead) + flingtime=200 + downCount=5 + upCount=5 + UP="500 1200 500 550 $flingtime" + DOWN="500 550 500 1200 $flingtime";; +(volantis) + flingtime=400 + downCount=5 + upCount=6 + UP="70 400 70 70 $flingtime" + DOWN="70 70 70 400 $flingtime";; +(*) + echo "Error: No display information available for $DEVICE" + exit 1;; +esac + +doKeyevent HOME +if [ $startapps -gt 0 ]; then + + # start a bunch of apps + for app in $appList + do + echo Starting $app ... + t=$(startActivity $app) + done +fi + +function swipe { + count=0 + while [ $count -lt $2 ] + do + doSwipe $1 + ((count=count+1)) + done +} + +cur=1 +frameSum=0 +jankSum=0 +latency90Sum=0 +latency95Sum=0 +latency99Sum=0 + +echo Fling recents... +doKeyevent HOME +sleep 0.5 +resetJankyFrames + +while [ $cur -le $iterations ] +do + if [ $capturesystrace -gt 0 ]; then + ${ADB}atrace --async_start -z -c -b 16000 freq gfx view idle sched + fi + doKeyevent APP_SWITCH + sleep 0.5 + swipe "$DOWN" $downCount + sleep 1 + swipe "$UP" $upCount + sleep 1 + swipe "$DOWN" $downCount + sleep 1 + swipe "$UP" $upCount + sleep 1 + if [ $capturesystrace -gt 0 ]; then + ${ADB}atrace --async_dump -z -c -b 16000 freq gfx view idle sched > trace.${cur}.out + fi + doKeyevent HOME + sleep 0.5 + + set -- $(getJankyFrames) + totalDiff=$1 + jankyDiff=$2 + latency90=$3 + latency95=$4 + latency99=$5 + if [ ${totalDiff:=0} -eq 0 ]; then + echo Error: could not read frame info with \"dumpsys gfxinfo\" + exit 1 + fi + + ((frameSum=frameSum+totalDiff)) + ((jankSum=jankSum+jankyDiff)) + ((latency90Sum=latency90Sum+latency90)) + ((latency95Sum=latency95Sum+latency95)) + ((latency99Sum=latency99Sum+latency99)) + if [ "$totalDiff" -eq 0 ]; then + echo Error: no frames detected. Is the display off? + exit 1 + fi + ((jankPct=jankyDiff*100/totalDiff)) + resetJankyFrames + + echo Frames: $totalDiff latency: $latency90/$latency95/$latency99 Janks: $jankyDiff\(${jankPct}%\) + ((cur=cur+1)) +done +doKeyevent HOME +((aveJankPct=jankSum*100/frameSum)) +((aveJanks=jankSum/iterations)) +((aveFrames=frameSum/iterations)) +((aveLatency90=latency90Sum/iterations)) +((aveLatency95=latency95Sum/iterations)) +((aveLatency99=latency99Sum/iterations)) +echo AVE: Frames: $aveFrames latency: $aveLatency90/$aveLatency95/$aveLatency99 Janks: $aveJanks\(${aveJankPct}%\)
diff --git a/tests/workloads/systemapps.sh b/tests/workloads/systemapps.sh new file mode 100755 index 0000000..a263e7d --- /dev/null +++ b/tests/workloads/systemapps.sh
@@ -0,0 +1,264 @@ +# Script to start a set of apps in order and then in each iteration +# switch the focus to each one. For each iteration, the time to start +# the app is reported as measured using atrace events and via am ThisTime. +# The output also reports if applications are restarted (eg, killed by +# LMK since previous iteration) or if there were any direct reclaim +# events. +# +# Variation: the "-T" option skips all of the atrace instramentation and +# attempts to start the apps as quickly as possible. +# +# Example 1: start all default apps. 2 iterations +# +# ./systemapps.sh -i 2 +# +# Example 2: just start chrome, feedly, and the home screen in a loop +# +# ./systemapps.sh -L "chrome feedly home" -i 5 +# +# Example 3: just start the default apps as quickly as possible +# +# ./systemapps.sh -T +# +# Other options are described below. +# +iterations=1 +tracecategories="gfx view am input memreclaim" +totaltimetest=0 +forcecoldstart=0 +waitTime=3.0 + +appList="gmail hangouts chrome youtube play home" + +function processLocalOption { + ret=0 + case "$1" in + (-A) unset appList;; + (-F) forcecoldstart=1;; + (-L) appList=$2; shift; ret=1;; + (-T) totaltimetest=1;; + (-W) waitTime=$2; shift; ret=1;; + (*) + echo "$0: unrecognized option: $1" + echo; echo "Usage: $0 [options]" + echo "-A : use all known applications" + echo "-F : force cold-start for all apps" + echo "-L applist : list of applications" + echo " default: $appList" + echo "-T : total time to start all apps" + echo "-W : time to wait between apps" + echo "-g : generate activity strings" + echo "-i iterations" + echo "-n : keep trace files" + echo "-o output file" + echo "-s : stop on error" + echo "-t trace categories" + exit 1;; + esac + return $ret +} + +CMDDIR=$(dirname $0 2>/dev/null) +CMDDIR=${CMDDIR:=.} +. $CMDDIR/defs.sh + +tmpTraceOutBase=./tmptrace + +if [ $user != "root" -a $totaltimetest -eq 0 ]; then + handleError Must be root on device + exit 1 +fi +doKeyevent HOME + +function computeStats { + label=$1 + t=$2 + restart=$3 + reclaim=$4 + frames=$5 + janks=$6 + l90=$7 + l95=$8 + l99=$9 + curMax=$(eval "echo \$${label}max") + curMax=${curMax:=0} + curMin=$(eval "echo \$${label}min") + curMin=${curMin:=100000} + curSum=$(eval "echo \$${label}sum") + curSum=${curSum:=0} + curRestart=$(eval "echo \$${label}restart") + curRestart=${curRestart:=0} + curReclaim=$(eval "echo \$${label}reclaim") + curReclaim=${curReclaim:=0} + curFrames=$(eval "echo \$${label}frames") + curFrames=${curFrames:=0} + curJanks=$(eval "echo \$${label}janks") + curJanks=${curJanks:=0} + cur90=$(eval "echo \$${label}90") + cur90=${cur90:=0} + cur95=$(eval "echo \$${label}95") + cur95=${cur95:=0} + cur99=$(eval "echo \$${label}99") + cur99=${cur99:=0} + if [ $curMax -lt $t ]; then + eval "${label}max=$t" + fi + if [ $curMin -gt $t ]; then + eval "${label}min=$t" + fi + ((curSum=curSum+t)) + eval "${label}sum=$curSum" + + ((curRestart=curRestart+${restart:=0})) + eval "${label}restart=$curRestart" + ((curReclaim=curReclaim+${reclaim:=0})) + eval "${label}reclaim=$curReclaim" + ((curFrames=curFrames+${frames:=0})) + eval "${label}frames=$curFrames" + ((curJanks=curJanks+${janks:=0})) + eval "${label}janks=$curJanks" + ((cur90=cur90+${l90:=0})) + eval "${label}90=$cur90" + ((cur95=cur95+${l95:=0})) + eval "${label}95=$cur95" + ((cur99=cur99+${l99:=0})) + eval "${label}99=$cur99" +} +function getStats { + label=$1 + echo $(eval "echo \$${label}max") $(eval "echo \$${label}min") $(eval "echo \$${label}sum") \ + $(eval "echo \$${label}restart") $(eval "echo \$${label}reclaim") \ + $(eval "echo \$${label}frames") $(eval "echo \$${label}janks") \ + $(eval "echo \$${label}90") $(eval "echo \$${label}95") $(eval "echo \$${label}99") +} + +cur=1 +totaltime=0 +startTimestamp=$(date +"%s %N") + +while [ $cur -le $iterations ] +do + if [ $iterations -gt 1 ]; then + echo ========================================= + echo Iteration $cur of $iterations + echo ========================================= + fi + if [ $iterations -gt 1 -o $cur -eq 1 ]; then + if [ $totaltimetest -eq 0 ]; then + printf "%-6s %7s(ms) %6s(ms) %s %s %s %s\n" App Time AmTime Restart DirReclaim Jank Latency + fi + fi + + appnum=-1 + for app in $appList + do + vout Starting $app... + ((appnum=appnum+1)) + loopTimestamp=$(date +"%s %N") + resetJankyFrames + resetJankyFrames $(getPackageName $app) + if [ $totaltimetest -eq 0 ]; then + tmpTraceOut="$tmpTraceOutBase-$app.out" + >$tmpTraceOut + startInstramentation + else + if [ $appnum -eq 0 ]; then + printf "%-8s %5s(ms) %3s(ms) %s %s\n" App Start Iter Jank Latency + fi + fi + if [ $forcecoldstart -eq 0 ]; then + t=$(startActivity $app) + else + t=$(forceStartActivity $app) + fi + + # let app finish drawing before checking janks + sleep $waitTime + set -- $(getJankyFrames $(getPackageName $app)) + frames=$1 + janks=$2 + l90=$3 + l95=$4 + l99=$5 + set -- $(getJankyFrames) + systemFrames=$1 + systemJanks=$2 + s90=$3 + s95=$4 + s99=$5 + ((frames=frames+systemFrames)) + ((janks=janks+systemJanks)) + ((l90=l90+s90)) + ((l95=l95+s95)) + ((l99=l99+s99)) + + loopEndTimestamp=$(date +"%s %N") + diffTime=$(computeTimeDiff $loopTimestamp $loopEndTimestamp) + + if [ $frames -eq 0 ]; then + janks=0 + jankPct=0 + else + ((jankPct=100*janks/frames)) + fi + if [ $totaltimetest -gt 0 ]; then + # Note: using %f since %d doesn't work correctly + # when running on lollipop + printf "%-10s %5.0f %5.0f %4.0f(%2.0f%%) %2.0f/%2.0f/%2.0f\n" $app $t $diffTime $janks $jankPct $l90 $l95 $l99 + ((totaltime=totaltime+t)) + continue + else + stopAndDumpInstramentation $tmpTraceOut + actName=$(getActivityName $app) + pkgName=$(getPackageName $app) + stime=$(getStartTime $actName $tmpTraceOut) + relaunch=$? + etime=$(getEndTime $pkgName $tmpTraceOut) + ((tdiff=$etime-$stime)) + if [ $etime -eq 0 -o $stime -eq 0 ]; then + handleError $app : could not compute start time stime=$stime etime=$etime + # use AmTime so statistics make sense + tdiff=$t + fi + checkForDirectReclaim $actName $tmpTraceOut + directReclaim=$? + + printf "%-12s %5d %5d %5d %5d %5d(%d%%) %d/%d/%d\n" "$app" "$tdiff" "$t" "$relaunch" "$directReclaim" "$janks" "$jankPct" $l90 $l95 $l99 + computeStats "$app" "$tdiff" "$relaunch" "$directReclaim" "$frames" "$janks" $l90 $l95 $l99 + + if [ $savetmpfiles -eq 0 ]; then + rm -f $tmpTraceOut + fi + fi + done + ((cur=cur+1)) +done +endTimestamp=$(date +"%s %N") +diffTime=$(computeTimeDiff $startTimestamp $endTimestamp) +if [ $totaltimetest -gt 0 ]; then + printf "%-10s %5.0f %5.0f\n" TOTAL $totaltime $diffTime +fi + +if [ $iterations -gt 1 -a $totaltimetest -eq 0 ]; then + echo + echo ========================================= + printf "Stats after $iterations iterations:\n" + echo ========================================= + printf "%-6s %7s(ms) %6s(ms) %6s(ms) %s %s %s %s\n" App Max Ave Min Restart DirReclaim Jank Latency + for app in $appList + do + set -- $(getStats $app) + sum=$3 + ((ave=sum/iterations)) + frames=$6 + janks=$7 + l90=$8 + l95=$9 + l99=${10} + ((ave90=l90/iterations)) + ((ave95=l95/iterations)) + ((ave99=l99/iterations)) + ((jankPct=100*janks/frames)) + printf "%-12s %5d %5d %5d %5d %5d %5d(%d%%) %d/%d/%d\n" $app $1 $ave $2 $4 $5 $janks $jankPct $ave90 $ave95 $ave99 + done +fi