summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit7341494707810f709855ea85ce03a8ec3ac8dbaf (patch)
tree3bfd77f6c3acddfd222b1b0f4cf1a3452bcc1863
downloadextras-release-1.0.tar.gz
-rw-r--r--Android.mk19
-rw-r--r--latencytop/Android.mk26
-rw-r--r--latencytop/MODULE_LICENSE_APACHE20
-rw-r--r--latencytop/NOTICE190
-rw-r--r--latencytop/latencytop.c442
-rw-r--r--libpagemap/Android.mk30
-rw-r--r--libpagemap/MODULE_LICENSE_APACHE20
-rw-r--r--libpagemap/NOTICE190
-rw-r--r--libpagemap/include/pagemap/pagemap.h171
-rw-r--r--libpagemap/pm_kernel.c158
-rw-r--r--libpagemap/pm_map.c125
-rw-r--r--libpagemap/pm_map.h24
-rw-r--r--libpagemap/pm_memusage.c28
-rw-r--r--libpagemap/pm_process.c290
-rw-r--r--librank/Android.mk30
-rw-r--r--librank/MODULE_LICENSE_APACHE20
-rw-r--r--librank/NOTICE190
-rw-r--r--librank/librank.c349
-rw-r--r--procmem/Android.mk30
-rw-r--r--procmem/MODULE_LICENSE_APACHE20
-rw-r--r--procmem/NOTICE190
-rw-r--r--procmem/procmem.c322
-rw-r--r--procrank/Android.mk30
-rw-r--r--procrank/MODULE_LICENSE_APACHE20
-rw-r--r--procrank/NOTICE190
-rw-r--r--procrank/procrank.c206
-rw-r--r--showmap/Android.mk13
-rw-r--r--showmap/MODULE_LICENSE_APACHE20
-rw-r--r--showmap/NOTICE190
-rw-r--r--showmap/showmap.c232
-rw-r--r--showslab/Android.mk15
-rw-r--r--showslab/MODULE_LICENSE_APACHE20
-rw-r--r--showslab/NOTICE190
-rw-r--r--showslab/showslab.c351
-rw-r--r--sound/Android.mk8
-rw-r--r--sound/playwav.c376
-rw-r--r--su/Android.mk15
-rw-r--r--su/MODULE_LICENSE_APACHE20
-rw-r--r--su/NOTICE190
-rw-r--r--su/su.c86
-rw-r--r--tests/Android.mk3
-rw-r--r--tests/cpueater/Android.mk24
-rw-r--r--tests/cpueater/cpueater.c82
-rw-r--r--tests/fstest/Android.mk43
-rw-r--r--tests/fstest/README68
-rw-r--r--tests/fstest/perm_checker.c399
-rw-r--r--tests/fstest/perm_checker.conf150
-rw-r--r--tests/icachetest/Android.mk14
-rw-r--r--tests/icachetest/icache.S180
-rw-r--r--tests/icachetest/icache2.S170
-rw-r--r--tests/icachetest/icache_main.c34
-rw-r--r--tests/memtest/Android.mk20
-rw-r--r--tests/memtest/memtest.cpp763
-rw-r--r--tests/memtest/thumb.cpp27
-rw-r--r--timeinfo/Android.mk24
-rw-r--r--timeinfo/timeinfo.cpp49
56 files changed, 6946 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 00000000..63185fac
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+ifneq ($(TARGET_SIMULATOR),true)
+ include $(all-subdir-makefiles)
+endif
diff --git a/latencytop/Android.mk b/latencytop/Android.mk
new file mode 100644
index 00000000..84bef410
--- /dev/null
+++ b/latencytop/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_SRC_FILES := latencytop.c
+
+LOCAL_MODULE := latencytop
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+
+LOCAL_MODULE_TAGS := debug tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/latencytop/MODULE_LICENSE_APACHE2 b/latencytop/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/latencytop/MODULE_LICENSE_APACHE2
diff --git a/latencytop/NOTICE b/latencytop/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/latencytop/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/latencytop/latencytop.c b/latencytop/latencytop.c
new file mode 100644
index 00000000..78d7c71d
--- /dev/null
+++ b/latencytop/latencytop.c
@@ -0,0 +1,442 @@
+/*
+ * 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 <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define MAX_LINE 512
+#define MAX_FILENAME 64
+
+const char *EXPECTED_VERSION = "Latency Top version : v0.1\n";
+const char *SYSCTL_FILE = "/proc/sys/kernel/latencytop";
+const char *GLOBAL_STATS_FILE = "/proc/latency_stats";
+const char *THREAD_STATS_FILE_FORMAT = "/proc/%d/task/%d/latency";
+
+struct latency_entry {
+ struct latency_entry *next;
+ unsigned long count;
+ unsigned long max;
+ unsigned long total;
+ char reason[MAX_LINE];
+};
+
+static inline void check_latencytop() { }
+
+static struct latency_entry *read_global_stats(struct latency_entry *list, int erase);
+static struct latency_entry *read_process_stats(struct latency_entry *list, int erase, int pid);
+static struct latency_entry *read_thread_stats(struct latency_entry *list, int erase, int pid, int tid, int fatal);
+
+static struct latency_entry *alloc_latency_entry(void);
+static void free_latency_entry(struct latency_entry *e);
+
+static void set_latencytop(int on);
+static struct latency_entry *read_latency_file(FILE *f, struct latency_entry *list);
+static void erase_latency_file(FILE *f);
+
+static struct latency_entry *find_latency_entry(struct latency_entry *e, char *reason);
+static void print_latency_entries(struct latency_entry *head);
+
+static void signal_handler(int sig);
+static void disable_latencytop(void);
+
+static int numcmp(const long long a, const long long b);
+static int lat_cmp(const void *a, const void *b);
+
+static void clear_screen(void);
+static void usage(const char *cmd);
+
+struct latency_entry *free_entries;
+
+int main(int argc, char *argv[]) {
+ struct latency_entry *e;
+ int delay, iterations;
+ int pid, tid;
+ int count, erase;
+ int i;
+
+ delay = 1;
+ iterations = 0;
+ pid = tid = 0;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-d")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -d expects an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ delay = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-n")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -n expects an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ iterations = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-h")) {
+ usage(argv[0]);
+ exit(EXIT_SUCCESS);
+ }
+ if (!strcmp(argv[i], "-p")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -p expects an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ pid = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-t")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -t expects an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ tid = atoi(argv[++i]);
+ continue;
+ }
+ fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (tid && !pid) {
+ fprintf(stderr, "If you provide a thread ID with -t, you must provide a process ID with -p.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ check_latencytop();
+
+ free_entries = NULL;
+
+ signal(SIGINT, &signal_handler);
+ signal(SIGTERM, &signal_handler);
+
+ atexit(&disable_latencytop);
+
+ set_latencytop(1);
+
+ count = 0;
+ erase = 1;
+
+ while ((iterations == 0) || (count++ < iterations)) {
+
+ sleep(delay);
+
+ e = NULL;
+ if (pid) {
+ if (tid) {
+ e = read_thread_stats(e, erase, pid, tid, 1);
+ } else {
+ e = read_process_stats(e, erase, pid);
+ }
+ } else {
+ e = read_global_stats(e, erase);
+ }
+ erase = 0;
+
+ clear_screen();
+ if (pid) {
+ if (tid) {
+ printf("Latencies for thread %d in process %d:\n", tid, pid);
+ } else {
+ printf("Latencies for process %d:\n", pid);
+ }
+ } else {
+ printf("Latencies across all processes:\n");
+ }
+ print_latency_entries(e);
+ }
+
+ set_latencytop(0);
+
+ return 0;
+}
+
+static struct latency_entry *read_global_stats(struct latency_entry *list, int erase) {
+ FILE *f;
+ struct latency_entry *e;
+
+ if (erase) {
+ f = fopen(GLOBAL_STATS_FILE, "w");
+ if (!f) {
+ fprintf(stderr, "Could not open global latency stats file: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ fprintf(f, "erase\n");
+ fclose(f);
+ }
+
+ f = fopen(GLOBAL_STATS_FILE, "r");
+ if (!f) {
+ fprintf(stderr, "Could not open global latency stats file: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ e = read_latency_file(f, list);
+
+ fclose(f);
+
+ return e;
+}
+
+static struct latency_entry *read_process_stats(struct latency_entry *list, int erase, int pid) {
+ char dirname[MAX_FILENAME];
+ DIR *dir;
+ struct dirent *ent;
+ struct latency_entry *e;
+ int tid;
+
+ sprintf(dirname, "/proc/%d/task", pid);
+ dir = opendir(dirname);
+ if (!dir) {
+ fprintf(stderr, "Could not open task dir for process %d.\n", pid);
+ fprintf(stderr, "Perhaps the process has terminated?\n");
+ exit(EXIT_FAILURE);
+ }
+
+ e = list;
+ while ((ent = readdir(dir))) {
+ if (!isdigit(ent->d_name[0]))
+ continue;
+
+ tid = atoi(ent->d_name);
+
+ e = read_thread_stats(e, erase, pid, tid, 0);
+ }
+
+ closedir(dir);
+
+ return e;
+}
+
+static struct latency_entry *read_thread_stats(struct latency_entry *list, int erase, int pid, int tid, int fatal) {
+ char filename[MAX_FILENAME];
+ FILE *f;
+ struct latency_entry *e;
+
+ sprintf(filename, THREAD_STATS_FILE_FORMAT, pid, tid);
+
+ if (erase) {
+ f = fopen(filename, "w");
+ if (!f) {
+ if (fatal) {
+ fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
+ fprintf(stderr, "Perhaps the process or thread has terminated?\n");
+ exit(EXIT_FAILURE);
+ } else {
+ return list;
+ }
+ }
+ fprintf(f, "erase\n");
+ fclose(f);
+ }
+
+ f = fopen(GLOBAL_STATS_FILE, "r");
+ if (!f) {
+ if (fatal) {
+ fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
+ fprintf(stderr, "Perhaps the process or thread has terminated?\n");
+ exit(EXIT_FAILURE);
+ } else {
+ return list;
+ }
+ }
+
+ e = read_latency_file(f, list);
+
+ fclose(f);
+
+ return e;
+}
+
+static struct latency_entry *alloc_latency_entry(void) {
+ struct latency_entry *e;
+
+ if (free_entries) {
+ e = free_entries;
+ free_entries = free_entries->next;
+ } else {
+ e = calloc(1, sizeof(struct latency_entry));
+ if (!e) {
+ fprintf(stderr, "Could not allocate latency entry: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ return e;
+}
+
+static void free_latency_entry(struct latency_entry *e) {
+ e->next = free_entries;
+ free_entries = e;
+}
+
+static struct latency_entry *find_latency_entry(struct latency_entry *head, char *reason) {
+ struct latency_entry *e;
+
+ e = head;
+
+ while (e) {
+ if (!strcmp(e->reason, reason))
+ return e;
+ e = e->next;
+ }
+
+ return NULL;
+}
+
+static void set_latencytop(int on) {
+ FILE *f;
+
+ f = fopen(SYSCTL_FILE, "w");
+ if (!f) {
+ fprintf(stderr, "Could not open %s: %s\n", SYSCTL_FILE, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ fprintf(f, "%d\n", on);
+
+ fclose(f);
+}
+
+static void erase_latency_file(FILE *f) {
+ fprintf(f, "erase\n");
+}
+
+static struct latency_entry *read_latency_file(FILE *f, struct latency_entry *list) {
+ struct latency_entry *e, *head;
+ char line[MAX_LINE];
+ unsigned long count, max, total;
+ char reason[MAX_LINE];
+
+ head = list;
+
+ if (!fgets(line, MAX_LINE, f)) {
+ fprintf(stderr, "Could not read latency file version: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (strcmp(line, EXPECTED_VERSION) != 0) {
+ fprintf(stderr, "Expected version: %s\n", EXPECTED_VERSION);
+ fprintf(stderr, "But got version: %s", line);
+ exit(EXIT_FAILURE);
+ }
+
+ while (fgets(line, MAX_LINE, f)) {
+ sscanf(line, "%ld %ld %ld %s", &count, &total, &max, reason);
+ if (max > 0 || total > 0) {
+ e = find_latency_entry(head, reason);
+ if (e) {
+ e->count += count;
+ if (max > e->max)
+ e->max = max;
+ e->total += total;
+ } else {
+ e = alloc_latency_entry();
+ e->count = count;
+ e->max = max;
+ e->total = total;
+ strcpy(e->reason, reason);
+ e->next = head;
+ head = e;
+ }
+ }
+ }
+
+ return head;
+}
+
+static void print_latency_entries(struct latency_entry *head) {
+ struct latency_entry *e, **array;
+ unsigned long average;
+ int i, count;
+
+ e = head;
+ count = 0;
+ while (e) {
+ count++;
+ e = e->next;
+ }
+
+ e = head;
+ array = calloc(count, sizeof(struct latency_entry *));
+ if (!array) {
+ fprintf(stderr, "Error allocating array: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ for (i = 0; i < count; i++) {
+ array[i] = e;
+ e = e->next;
+ }
+
+ qsort(array, count, sizeof(struct latency_entry *), &lat_cmp);
+
+ printf("%10s %10s %7s %s\n", "Maximum", "Average", "Count", "Reason");
+ for (i = 0; i < count; i++) {
+ e = array[i];
+ average = e->total / e->count;
+ printf("%4lu.%02lu ms %4lu.%02lu ms %7ld %s\n",
+ e->max / 1000, (e->max % 1000) / 10,
+ average / 1000, (average % 1000) / 10,
+ e->count,
+ e->reason);
+ }
+
+ free(array);
+}
+
+static void signal_handler(int sig) {
+ exit(EXIT_SUCCESS);
+}
+
+static void disable_latencytop(void) {
+ set_latencytop(0);
+}
+
+static void clear_screen(void) {
+ printf("\n\n");
+}
+
+static void usage(const char *cmd) {
+ fprintf(stderr, "Usage: %s [ -d delay ] [ -n iterations ] [ -p pid [ -t tid ] ] [ -h ]\n"
+ " -d delay Time to sleep between updates.\n"
+ " -n iterations Number of updates to show (0 = infinite).\n"
+ " -p pid Process to monitor (default is all).\n"
+ " -t tid Thread (within specified process) to monitor (default is all).\n"
+ " -h Display this help screen.\n",
+ cmd);
+}
+
+static int numcmp(const long long a, const long long b) {
+ if (a < b) return -1;
+ if (a > b) return 1;
+ return 0;
+}
+
+static int lat_cmp(const void *a, const void *b) {
+ const struct latency_entry *pa, *pb;
+
+ pa = (*((struct latency_entry **)a));
+ pb = (*((struct latency_entry **)b));
+
+ return numcmp(pb->max, pa->max);
+}
diff --git a/libpagemap/Android.mk b/libpagemap/Android.mk
new file mode 100644
index 00000000..b38363c8
--- /dev/null
+++ b/libpagemap/Android.mk
@@ -0,0 +1,30 @@
+# 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 := libpagemap
+LOCAL_MODULE_TAGS := debug
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_SRC_FILES := \
+ pm_kernel.c \
+ pm_process.c \
+ pm_map.c \
+ pm_memusage.c
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libpagemap/MODULE_LICENSE_APACHE2 b/libpagemap/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/libpagemap/MODULE_LICENSE_APACHE2
diff --git a/libpagemap/NOTICE b/libpagemap/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/libpagemap/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/libpagemap/include/pagemap/pagemap.h b/libpagemap/include/pagemap/pagemap.h
new file mode 100644
index 00000000..09ff29d8
--- /dev/null
+++ b/libpagemap/include/pagemap/pagemap.h
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+#ifndef _PAGEMAP_PAGEMAP_H
+#define _PAGEMAP_PAGEMAP_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+typedef struct pm_memusage pm_memusage_t;
+
+/* Holds the various metrics for memory usage of a process or a mapping. */
+struct pm_memusage {
+ size_t vss;
+ size_t rss;
+ size_t pss;
+ size_t uss;
+};
+
+/* Clears a memusage. */
+void pm_memusage_zero(pm_memusage_t *mu);
+/* Adds one memusage (a) to another (b). */
+void pm_memusage_add(pm_memusage_t *a, pm_memusage_t *b);
+
+typedef struct pm_kernel pm_kernel_t;
+typedef struct pm_process pm_process_t;
+typedef struct pm_map pm_map_t;
+
+/* pm_kernel_t holds the state necessary to interface to the kernel's pagemap
+ * system on a global level. */
+struct pm_kernel {
+ int kpagecount_fd;
+ int kpageflags_fd;
+
+ int pagesize;
+};
+
+/* pm_process_t holds the state necessary to interface to a particular process'
+ * pagemap. */
+struct pm_process {
+ pm_kernel_t *ker;
+
+ pid_t pid;
+
+ pm_map_t **maps;
+ int num_maps;
+
+ int pagemap_fd;
+};
+
+/* pm_map_t holds the state necessary to access information about a particular
+ * mapping in a particular process. */
+struct pm_map {
+ pm_process_t *proc;
+
+ unsigned long start;
+ unsigned long end;
+ unsigned long offset;
+ int flags;
+
+ char *name;
+};
+
+/* Create a pm_kernel_t. */
+int pm_kernel_create(pm_kernel_t **ker_out);
+
+#define pm_kernel_pagesize(ker) ((ker)->pagesize)
+
+/* Get a list of probably-existing PIDs (returned through *pids_out).
+ * Length of the array (in sizeof(pid_t) units) is returned through *len.
+ * The array should be freed by the caller. */
+int pm_kernel_pids(pm_kernel_t *ker, pid_t **pids_out, size_t *len);
+
+/* Get the map count (from /proc/kpagecount) of a physical frame.
+ * The count is returned through *count_out. */
+int pm_kernel_count(pm_kernel_t *ker, unsigned long pfn, uint64_t *count_out);
+
+/* Get the page flags (from /proc/kpageflags) of a physical frame.
+ * The count is returned through *flags_out. */
+int pm_kernel_flags(pm_kernel_t *ker, unsigned long pfn, uint64_t *flags_out);
+
+#define PM_PAGE_LOCKED (1 << 0)
+#define PM_PAGE_ERROR (1 << 1)
+#define PM_PAGE_REFERENCED (1 << 2)
+#define PM_PAGE_UPTODATE (1 << 3)
+#define PM_PAGE_DIRTY (1 << 4)
+#define PM_PAGE_LRU (1 << 5)
+#define PM_PAGE_ACTIVE (1 << 6)
+#define PM_PAGE_SLAB (1 << 7)
+#define PM_PAGE_WRITEBACK (1 << 8)
+#define PM_PAGE_RECLAIM (1 << 9)
+#define PM_PAGE_BUDDY (1 << 10)
+
+/* Destroy a pm_kernel_t. */
+int pm_kernel_destroy(pm_kernel_t *ker);
+
+/* Get the PID of a pm_process_t. */
+#define pm_process_pid(proc) ((proc)->pid)
+
+/* Create a pm_process_t and returns it through *proc_out.
+ * Takes a pm_kernel_t, and the PID of the process. */
+int pm_process_create(pm_kernel_t *ker, pid_t pid, pm_process_t **proc_out);
+
+/* Get the total memory usage of a process and store in *usage_out. */
+int pm_process_usage(pm_process_t *proc, pm_memusage_t *usage_out);
+
+/* Get the working set of a process (if ws_out != NULL), and reset it
+ * (if reset != 0). */
+int pm_process_workingset(pm_process_t *proc, pm_memusage_t *ws_out, int reset);
+
+/* Get the PFNs corresponding to a range of virtual addresses.
+ * The array of PFNs is returned through *range_out, and the caller has the
+ * responsibility to free it. */
+int pm_process_pagemap_range(pm_process_t *proc,
+ unsigned long low, unsigned long hi,
+ uint64_t **range_out, size_t *len);
+
+#define _BITS(x, offset, bits) (((x) >> offset) & ((1LL << ((bits) + 1)) - 1))
+
+#define PM_PAGEMAP_PRESENT(x) (_BITS(x, 63, 1))
+#define PM_PAGEMAP_SWAPPED(x) (!_BITS(x, 62, 1))
+#define PM_PAGEMAP_SHIFT(x) (_BITS(x, 55, 6))
+#define PM_PAGEMAP_PFN(x) (_BITS(x, 0, 55))
+#define PM_PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50))
+#define PM_PAGEMAP_SWAP_TYPE(x) (_BITS(x, 0, 5))
+
+/* Get the maps in the virtual address space of this process.
+ * Returns an array of pointers to pm_map_t through *maps.
+ * The array should be freed by the caller, but the maps should not be
+ * modified or destroyed. */
+int pm_process_maps(pm_process_t *proc, pm_map_t ***maps_out, size_t *len);
+
+/* Destroy a pm_process_t. */
+int pm_process_destroy(pm_process_t *proc);
+
+/* Get the name, flags, start/end address, or offset of a map. */
+#define pm_map_name(map) ((map)->name)
+#define pm_map_flags(map) ((map)->flags)
+#define PM_MAP_READ 1
+#define PM_MAP_WRITE 2
+#define PM_MAP_EXEC 4
+#define pm_map_start(map) ((map)->start)
+#define pm_map_end(map) ((map)->end)
+#define pm_map_offset(map) ((map)->offset)
+
+/* Get the PFNs of the pages in the virtual address space of this map.
+ * Array of PFNs is returned through *pagemap_out, and should be freed by the
+ * caller. */
+int pm_map_pagemap(pm_map_t *map, uint64_t **pagemap_out, size_t *len);
+
+/* Get the memory usage of this map alone. */
+int pm_map_usage(pm_map_t *map, pm_memusage_t *usage_out);
+
+/* Get the working set of this map alone. */
+int pm_map_workingset(pm_map_t *map, pm_memusage_t *ws_out);
+
+#endif
diff --git a/libpagemap/pm_kernel.c b/libpagemap/pm_kernel.c
new file mode 100644
index 00000000..3615f1ac
--- /dev/null
+++ b/libpagemap/pm_kernel.c
@@ -0,0 +1,158 @@
+/*
+ * 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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <pagemap/pagemap.h>
+
+int pm_kernel_create(pm_kernel_t **ker_out) {
+ pm_kernel_t *ker;
+ int error;
+
+ if (!ker_out)
+ return 1;
+
+ ker = calloc(1, sizeof(*ker));
+ if (!ker)
+ return errno;
+
+ ker->kpagecount_fd = open("/proc/kpagecount", O_RDONLY);
+ if (ker->kpagecount_fd < 0) {
+ error = errno;
+ free(ker);
+ return error;
+ }
+
+ ker->kpageflags_fd = open("/proc/kpageflags", O_RDONLY);
+ if (ker->kpageflags_fd < 0) {
+ error = errno;
+ close(ker->kpagecount_fd);
+ free(ker);
+ return error;
+ }
+
+ ker->pagesize = getpagesize();
+
+ *ker_out = ker;
+
+ return 0;
+}
+
+#define INIT_PIDS 20
+int pm_kernel_pids(pm_kernel_t *ker, pid_t **pids_out, size_t *len) {
+ DIR *proc;
+ struct dirent *dir;
+ pid_t pid, *pids, *new_pids;
+ size_t pids_count, pids_size;
+ int error;
+
+ proc = opendir("/proc");
+ if (!proc)
+ return errno;
+
+ pids = malloc(INIT_PIDS * sizeof(pid_t));
+ if (!pids) {
+ closedir(proc);
+ return errno;
+ }
+ pids_count = 0; pids_size = INIT_PIDS;
+
+ while ((dir = readdir(proc))) {
+ if (sscanf(dir->d_name, "%d", &pid) < 1)
+ continue;
+
+ if (pids_count >= pids_size) {
+ new_pids = realloc(pids, 2 * pids_size * sizeof(pid_t));
+ if (!new_pids) {
+ error = errno;
+ free(pids);
+ closedir(proc);
+ return error;
+ }
+ pids = new_pids;
+ pids_size = 2 * pids_size;
+ }
+
+ pids[pids_count] = pid;
+
+ pids_count++;
+ }
+
+ closedir(proc);
+
+ new_pids = realloc(pids, pids_count * sizeof(pid_t));
+ if (!new_pids) {
+ error = errno;
+ free(pids);
+ return error;
+ }
+
+ *pids_out = new_pids;
+ *len = pids_count;
+
+ return 0;
+}
+
+int pm_kernel_count(pm_kernel_t *ker, unsigned long pfn, uint64_t *count_out) {
+ off_t off;
+
+ if (!ker || !count_out)
+ return -1;
+
+ off = lseek(ker->kpagecount_fd, pfn * sizeof(uint64_t), SEEK_SET);
+ if (off == (off_t)-1)
+ return errno;
+ if (read(ker->kpagecount_fd, count_out, sizeof(uint64_t)) <
+ (ssize_t)sizeof(uint64_t))
+ return errno;
+
+ return 0;
+}
+
+int pm_kernel_flags(pm_kernel_t *ker, unsigned long pfn, uint64_t *flags_out) {
+ off_t off;
+
+ if (!ker || !flags_out)
+ return -1;
+
+ off = lseek(ker->kpageflags_fd, pfn * sizeof(uint64_t), SEEK_SET);
+ if (off == (off_t)-1)
+ return errno;
+ if (read(ker->kpageflags_fd, flags_out, sizeof(uint64_t)) <
+ (ssize_t)sizeof(uint64_t))
+ return errno;
+
+ return 0;
+}
+
+int pm_kernel_destroy(pm_kernel_t *ker) {
+ if (!ker)
+ return -1;
+
+ close(ker->kpagecount_fd);
+ close(ker->kpageflags_fd);
+
+ free(ker);
+
+ return 0;
+}
diff --git a/libpagemap/pm_map.c b/libpagemap/pm_map.c
new file mode 100644
index 00000000..f683ba6c
--- /dev/null
+++ b/libpagemap/pm_map.c
@@ -0,0 +1,125 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <pagemap/pagemap.h>
+
+int pm_map_pagemap(pm_map_t *map, uint64_t **pagemap_out, size_t *len) {
+ if (!map)
+ return -1;
+
+ return pm_process_pagemap_range(map->proc, map->start, map->end,
+ pagemap_out, len);
+}
+
+int pm_map_usage(pm_map_t *map, pm_memusage_t *usage_out) {
+ uint64_t *pagemap;
+ size_t len, i;
+ uint64_t count;
+ pm_memusage_t usage;
+ int error;
+
+ if (!map || !usage_out)
+ return -1;
+
+ error = pm_map_pagemap(map, &pagemap, &len);
+ if (error) return error;
+
+ pm_memusage_zero(&usage);
+
+ for (i = 0; i < len; i++) {
+ if (!PM_PAGEMAP_PRESENT(pagemap[i]) ||
+ PM_PAGEMAP_SWAPPED(pagemap[i]))
+ continue;
+
+ error = pm_kernel_count(map->proc->ker, PM_PAGEMAP_PFN(pagemap[i]),
+ &count);
+ if (error) goto out;
+
+ usage.vss += map->proc->ker->pagesize;
+ usage.rss += (count >= 1) ? (map->proc->ker->pagesize) : (0);
+ usage.pss += (count >= 1) ? (map->proc->ker->pagesize / count) : (0);
+ usage.uss += (count == 1) ? (map->proc->ker->pagesize) : (0);
+ }
+
+ memcpy(usage_out, &usage, sizeof(usage));
+
+ error = 0;
+
+out:
+ free(pagemap);
+
+ return error;
+}
+
+int pm_map_workingset(pm_map_t *map, pm_memusage_t *ws_out) {
+ uint64_t *pagemap;
+ size_t len, i;
+ uint64_t count, flags;
+ pm_memusage_t ws;
+ int error;
+
+ if (!map || !ws_out)
+ return -1;
+
+ error = pm_map_pagemap(map, &pagemap, &len);
+ if (error) return error;
+
+ pm_memusage_zero(&ws);
+
+ for (i = 0; i < len; i++) {
+ if (!PM_PAGEMAP_PRESENT(pagemap[i]) ||
+ PM_PAGEMAP_SWAPPED(pagemap[i]))
+ continue;
+
+ error = pm_kernel_flags(map->proc->ker, PM_PAGEMAP_PFN(pagemap[i]),
+ &flags);
+ if (error) goto out;
+
+ if (!(flags & PM_PAGE_REFERENCED))
+ continue;
+
+ error = pm_kernel_count(map->proc->ker, PM_PAGEMAP_PFN(pagemap[i]),
+ &count);
+ if (error) goto out;
+
+ ws.vss += map->proc->ker->pagesize;
+ ws.rss += (count >= 1) ? (map->proc->ker->pagesize) : (0);
+ ws.pss += (count >= 1) ? (map->proc->ker->pagesize / count) : (0);
+ ws.uss += (count == 1) ? (map->proc->ker->pagesize) : (0);
+ }
+
+ memcpy(ws_out, &ws, sizeof(ws));
+
+ error = 0;
+
+out:
+ free(pagemap);
+
+ return 0;
+}
+
+int pm_map_destroy(pm_map_t *map) {
+ if (!map)
+ return -1;
+
+ free(map->name);
+ free(map);
+
+ return 0;
+}
diff --git a/libpagemap/pm_map.h b/libpagemap/pm_map.h
new file mode 100644
index 00000000..08dc4485
--- /dev/null
+++ b/libpagemap/pm_map.h
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBS_PAGEMAP_PM_MAP_H
+#define _LIBS_PAGEMAP_PM_MAP_H
+
+#include <pagemap/pagemap.h>
+
+int pm_map_destroy(pm_map_t *map);
+
+#endif
diff --git a/libpagemap/pm_memusage.c b/libpagemap/pm_memusage.c
new file mode 100644
index 00000000..9c5db92e
--- /dev/null
+++ b/libpagemap/pm_memusage.c
@@ -0,0 +1,28 @@
+/*
+ * 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 <pagemap/pagemap.h>
+
+void pm_memusage_zero(pm_memusage_t *mu) {
+ mu->vss = mu->rss = mu->pss = mu->uss = 0;
+}
+
+void pm_memusage_add(pm_memusage_t *a, pm_memusage_t *b) {
+ a->vss += b->vss;
+ a->rss += b->rss;
+ a->pss += b->pss;
+ a->uss += b->uss;
+}
diff --git a/libpagemap/pm_process.c b/libpagemap/pm_process.c
new file mode 100644
index 00000000..1ab367d8
--- /dev/null
+++ b/libpagemap/pm_process.c
@@ -0,0 +1,290 @@
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <pagemap/pagemap.h>
+
+#include "pm_map.h"
+
+static int read_maps(pm_process_t *proc);
+
+#define MAX_FILENAME 64
+
+int pm_process_create(pm_kernel_t *ker, pid_t pid, pm_process_t **proc_out) {
+ pm_process_t *proc;
+ char filename[MAX_FILENAME];
+ int error;
+
+ if (!ker || !proc_out)
+ return -1;
+
+ proc = calloc(1, sizeof(*proc));
+ if (!proc)
+ return errno;
+
+ proc->ker = ker;
+ proc->pid = pid;
+
+ error = snprintf(filename, MAX_FILENAME, "/proc/%d/pagemap", pid);
+ if (error < 0 || error >= MAX_FILENAME) {
+ error = (error < 0) ? (errno) : (-1);
+ free(proc);
+ return error;
+ }
+
+ proc->pagemap_fd = open(filename, O_RDONLY);
+ if (proc->pagemap_fd < 0) {
+ error = errno;
+ free(proc);
+ return error;
+ }
+
+ error = read_maps(proc);
+ if (error) {
+ free(proc);
+ return error;
+ }
+
+ *proc_out = proc;
+
+ return 0;
+}
+
+int pm_process_usage(pm_process_t *proc, pm_memusage_t *usage_out) {
+ pm_memusage_t usage, map_usage;
+ int error;
+ int i;
+
+ if (!proc || !usage_out)
+ return -1;
+
+ pm_memusage_zero(&usage);
+
+ for (i = 0; i < proc->num_maps; i++) {
+ error = pm_map_usage(proc->maps[i], &map_usage);
+ if (error) return error;
+
+ pm_memusage_add(&usage, &map_usage);
+ }
+
+ memcpy(usage_out, &usage, sizeof(pm_memusage_t));
+
+ return 0;
+}
+
+int pm_process_pagemap_range(pm_process_t *proc,
+ unsigned long low, unsigned long high,
+ uint64_t **range_out, size_t *len) {
+ int firstpage, numpages;
+ uint64_t *range;
+ off_t off;
+ int error;
+
+ if (!proc || (low >= high) || !range_out || !len)
+ return -1;
+
+ firstpage = low / proc->ker->pagesize;
+ numpages = (high - low) / proc->ker->pagesize;
+
+ range = malloc(numpages * sizeof(uint64_t));
+ if (!range)
+ return errno;
+
+ off = lseek(proc->pagemap_fd, firstpage * sizeof(uint64_t), SEEK_SET);
+ if (off == (off_t)-1) {
+ error = errno;
+ free(range);
+ return error;
+ }
+ error = read(proc->pagemap_fd, (char*)range, numpages * sizeof(uint64_t));
+ if (error < numpages * sizeof(uint64_t)) {
+ error = (error < 0) ? errno : -1;
+ free(range);
+ return error;
+ }
+
+ *range_out = range;
+ *len = numpages;
+
+ return 0;
+}
+
+int pm_process_maps(pm_process_t *proc, pm_map_t ***maps_out, size_t *len) {
+ pm_map_t **maps;
+
+ if (!proc || !maps_out || !len)
+ return -1;
+
+ if (proc->num_maps) {
+ maps = malloc(proc->num_maps * sizeof(pm_map_t*));
+ if (!maps)
+ return errno;
+
+ memcpy(maps, proc->maps, proc->num_maps * sizeof(pm_map_t*));
+
+ *maps_out = maps;
+ } else {
+ *maps_out = NULL;
+ }
+ *len = proc->num_maps;
+
+ return 0;
+}
+
+int pm_process_workingset(pm_process_t *proc,
+ pm_memusage_t *ws_out, int reset) {
+ pm_memusage_t ws, map_ws;
+ char filename[MAX_FILENAME];
+ int fd;
+ int i, j;
+ int error;
+
+ if (!proc)
+ return -1;
+
+ if (ws_out) {
+ pm_memusage_zero(&ws);
+ for (i = 0; i < proc->num_maps; i++) {
+ error = pm_map_workingset(proc->maps[i], &map_ws);
+ if (error) return error;
+
+ pm_memusage_add(&ws, &map_ws);
+ }
+
+ memcpy(ws_out, &ws, sizeof(ws));
+ }
+
+ if (reset) {
+ error = snprintf(filename, MAX_FILENAME, "/proc/%d/clear_refs",
+ proc->pid);
+ if (error < 0 || error >= MAX_FILENAME) {
+ return (error < 0) ? (errno) : (-1);
+ }
+
+ fd = open(filename, O_WRONLY);
+ if (fd < 0)
+ return errno;
+
+ write(fd, "1\n", strlen("1\n"));
+
+ close(fd);
+ }
+
+ return 0;
+}
+
+int pm_process_destroy(pm_process_t *proc) {
+ if (!proc)
+ return -1;
+
+ free(proc->maps);
+ close(proc->pagemap_fd);
+ free(proc);
+
+ return 0;
+}
+
+#define INITIAL_MAPS 10
+#define MAX_LINE 256
+#define MAX_PERMS 5
+
+/*
+ * #define FOO 123
+ * S(FOO) => "123"
+ */
+#define _S(n) #n
+#define S(n) _S(n)
+
+static int read_maps(pm_process_t *proc) {
+ char filename[MAX_FILENAME];
+ char line[MAX_LINE], name[MAX_LINE], perms[MAX_PERMS];
+ FILE *maps_f;
+ pm_map_t *map, **maps, **new_maps;
+ int maps_count, maps_size;
+ int error;
+
+ if (!proc)
+ return -1;
+
+ maps = calloc(INITIAL_MAPS, sizeof(pm_map_t*));
+ if (!maps)
+ return errno;
+ maps_count = 0; maps_size = INITIAL_MAPS;
+
+ error = snprintf(filename, MAX_FILENAME, "/proc/%d/maps", proc->pid);
+ if (error < 0 || error >= MAX_FILENAME)
+ return (error < 0) ? (errno) : (-1);
+
+ maps_f = fopen(filename, "r");
+ if (!maps_f)
+ return errno;
+
+ while (fgets(line, MAX_LINE, maps_f)) {
+ if (maps_count >= maps_size) {
+ new_maps = realloc(maps, 2 * maps_size * sizeof(pm_map_t*));
+ if (!new_maps) {
+ error = errno;
+ free(maps);
+ fclose(maps_f);
+ return error;
+ }
+ maps = new_maps;
+ maps_size *= 2;
+ }
+
+ maps[maps_count] = map = calloc(1, sizeof(*map));
+
+ map->proc = proc;
+
+ sscanf(line, "%lx-%lx %s %lx %*s %*d %" S(MAX_LINE) "s",
+ &map->start, &map->end, perms, &map->offset, name);
+
+ map->name = malloc(strlen(name) + 1);
+ if (!map->name) {
+ error = errno;
+ for (; maps_count > 0; maps_count--)
+ pm_map_destroy(maps[maps_count]);
+ free(maps);
+ return error;
+ }
+ strcpy(map->name, name);
+ if (perms[0] == 'r') map->flags |= PM_MAP_READ;
+ if (perms[1] == 'w') map->flags |= PM_MAP_WRITE;
+ if (perms[2] == 'x') map->flags |= PM_MAP_EXEC;
+
+ maps_count++;
+ }
+
+ fclose(maps_f);
+
+ new_maps = realloc(maps, maps_count * sizeof(pm_map_t*));
+ if (maps_count && !new_maps) {
+ error = errno;
+ free(maps);
+ return error;
+ }
+
+ proc->maps = new_maps;
+ proc->num_maps = maps_count;
+
+ return 0;
+}
diff --git a/librank/Android.mk b/librank/Android.mk
new file mode 100644
index 00000000..300b3f59
--- /dev/null
+++ b/librank/Android.mk
@@ -0,0 +1,30 @@
+# 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_SRC_FILES := librank.c
+
+LOCAL_C_INCLUDES := $(call include-path-for, libpagemap)
+
+LOCAL_SHARED_LIBRARIES := libpagemap
+
+LOCAL_MODULE := librank
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+
+LOCAL_MODULE_TAGS := debug
+
+include $(BUILD_EXECUTABLE)
diff --git a/librank/MODULE_LICENSE_APACHE2 b/librank/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/librank/MODULE_LICENSE_APACHE2
diff --git a/librank/NOTICE b/librank/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/librank/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/librank/librank.c b/librank/librank.c
new file mode 100644
index 00000000..13b20974
--- /dev/null
+++ b/librank/librank.c
@@ -0,0 +1,349 @@
+/*
+ * 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 <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <pagemap/pagemap.h>
+
+#define MAX_CMDLINE 256
+
+struct process_info {
+ pid_t pid;
+ char cmdline[MAX_CMDLINE];
+};
+
+struct mapping_info {
+ struct process_info *proc;
+ pm_memusage_t usage;
+};
+
+struct library_info {
+ struct library_info *next;
+ char *name;
+ struct mapping_info **mappings;
+ int mappings_count;
+ int mappings_size;
+ pm_memusage_t total_usage;
+};
+
+static void usage(char *myname);
+static int getprocname(pid_t pid, char *buf, size_t len);
+static int numcmp(long long a, long long b);
+static int licmp(const void *a, const void *b);
+
+char *library_name_blacklist[] = { "[heap]", "[stack]", "", NULL };
+
+#define declare_sort(field) \
+ static int sort_by_ ## field (const void *a, const void *b)
+
+declare_sort(vss);
+declare_sort(rss);
+declare_sort(pss);
+declare_sort(uss);
+
+#define INIT_LIBRARIES 16
+#define INIT_MAPPINGS 4
+
+static int order;
+
+struct library_info **libraries;
+int libraries_count;
+int libraries_size;
+
+struct library_info *get_library(char *name) {
+ int i;
+ struct library_info *library;
+
+ for (i = 0; library_name_blacklist[i]; i++)
+ if (!strcmp(name, library_name_blacklist[i]))
+ return NULL;
+
+ for (i = 0; i < libraries_count; i++) {
+ if (!strcmp(libraries[i]->name, name))
+ return libraries[i];
+ }
+
+ if (libraries_count >= libraries_size) {
+ libraries = realloc(libraries, 2 * libraries_size * sizeof(struct library_info *));
+ if (!libraries) {
+ fprintf(stderr, "Couldn't resize libraries array: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ libraries_size = 2 * libraries_size;
+ }
+
+ library = calloc(1, sizeof(*library));
+ if (!library) {
+ fprintf(stderr, "Couldn't allocate space for library struct: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ library->name = malloc(strlen(name) + 1);
+ if (!library->name) {
+ fprintf(stderr, "Couldn't allocate space for library name: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ strcpy(library->name, name);
+ library->mappings = malloc(INIT_MAPPINGS * sizeof(struct mapping_info *));
+ if (!library->mappings) {
+ fprintf(stderr, "Couldn't allocate space for library mappings array: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ library->mappings_count = 0; library->mappings_size = INIT_MAPPINGS;
+ pm_memusage_zero(&library->total_usage);
+
+ libraries[libraries_count++] = library;
+
+ return library;
+}
+
+struct mapping_info *get_mapping(struct library_info *library, struct process_info *proc) {
+ struct mapping_info *mapping;
+ int i;
+
+ for (i = 0; i < library->mappings_count; i++) {
+ if (library->mappings[i]->proc == proc)
+ return library->mappings[i];
+ }
+
+ if (library->mappings_count >= library->mappings_size) {
+ library->mappings = realloc(library->mappings,
+ 2 * library->mappings_size * sizeof(struct mapping*));
+ if (!library->mappings) {
+ fprintf(stderr, "Couldn't resize mappings array: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ library->mappings_size = 2 * library->mappings_size;
+ }
+
+ mapping = calloc(1, sizeof(*mapping));
+ if (!mapping) {
+ fprintf(stderr, "Couldn't allocate space for mapping struct: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ mapping->proc = proc;
+ pm_memusage_zero(&mapping->usage);
+
+ library->mappings[library->mappings_count++] = mapping;
+
+ return mapping;
+}
+
+struct process_info *get_process(pid_t pid) {
+ struct process_info *process;
+
+ process = calloc(1, sizeof(*process));
+ if (!process) {
+ fprintf(stderr, "Couldn't allocate space for process struct: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ process->pid = pid;
+ getprocname(pid, process->cmdline, sizeof(process->cmdline));
+
+ return process;
+}
+
+int main(int argc, char *argv[]) {
+ char cmdline[256];
+ char *prefix;
+ size_t prefix_len;
+ int (*compfn)(const void *a, const void *b);
+
+ pm_kernel_t *ker;
+ pm_process_t *proc;
+
+ pid_t *pids;
+ size_t num_procs;
+
+ pm_map_t **maps;
+ size_t num_maps;
+ pm_memusage_t map_usage;
+
+ struct library_info *li, **lis;
+ struct mapping_info *mi, **mis;
+ struct process_info *pi;
+
+ int i, j, error;
+
+ compfn = &sort_by_pss;
+ order = -1;
+ prefix = NULL;
+ prefix_len = 0;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-P")) {
+ if (i + 1 >= argc) {
+ fprintf(stderr, "Option -P requires an argument.\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ prefix = argv[++i];
+ prefix_len = strlen(prefix);
+ continue;
+ }
+ if (!strcmp(argv[i], "-v")) { compfn = &sort_by_vss; continue; }
+ if (!strcmp(argv[i], "-r")) { compfn = &sort_by_rss; continue; }
+ if (!strcmp(argv[i], "-p")) { compfn = &sort_by_pss; continue; }
+ if (!strcmp(argv[i], "-u")) { compfn = &sort_by_uss; continue; }
+ if (!strcmp(argv[i], "-R")) { order *= -1; continue; }
+ if (!strcmp(argv[i], "-h")) { usage(argv[0]); exit(0); }
+ fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ libraries = malloc(INIT_LIBRARIES * sizeof(struct library_info *));
+ libraries_count = 0; libraries_size = INIT_LIBRARIES;
+
+ error = pm_kernel_create(&ker);
+ if (error) {
+ fprintf(stderr, "Error initializing kernel interface -- "
+ "does this kernel have pagemap?\n");
+ exit(EXIT_FAILURE);
+ }
+
+ error = pm_kernel_pids(ker, &pids, &num_procs);
+ if (error) {
+ fprintf(stderr, "Error listing processes.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < num_procs; i++) {
+ error = pm_process_create(ker, pids[i], &proc);
+ if (error) {
+ fprintf(stderr, "warning: could not create process interface for %d\n", pids[i]);
+ continue;
+ }
+
+ pi = get_process(pids[i]);
+
+ error = pm_process_maps(proc, &maps, &num_maps);
+ if (error) {
+ fprintf(stderr, "Error listing maps for process %d.\n", proc->pid);
+ exit(EXIT_FAILURE);
+ }
+
+ for (j = 0; j < num_maps; j++) {
+ if (prefix && (strncmp(pm_map_name(maps[j]), prefix, prefix_len)))
+ continue;
+
+ li = get_library(pm_map_name(maps[j]));
+ if (!li)
+ continue;
+
+ mi = get_mapping(li, pi);
+
+ error = pm_map_usage(maps[j], &map_usage);
+ if (error) {
+ fprintf(stderr, "Error getting map memory usage of "
+ "map %s in process %d.\n",
+ pm_map_name(maps[j]), proc->pid);
+ exit(EXIT_FAILURE);
+ }
+ pm_memusage_add(&mi->usage, &map_usage);
+ pm_memusage_add(&li->total_usage, &map_usage);
+ }
+ }
+
+ printf( " %6s %6s %6s %6s %6s %s\n", "RSStot", "VSS", "RSS", "PSS", "USS", "Name/PID");
+ fflush(stdout);
+
+ qsort(libraries, libraries_count, sizeof(libraries[0]), &licmp);
+
+ for (i = 0; i < libraries_count; i++) {
+ li = libraries[i];
+
+ printf("%6dK %6s %6s %6s %6s %s\n", li->total_usage.pss / 1024, "", "", "", "", li->name);
+ fflush(stdout);
+
+ qsort(li->mappings, li->mappings_count, sizeof(li->mappings[0]), compfn);
+
+ for (j = 0; j < li->mappings_count; j++) {
+ mi = li->mappings[j];
+ pi = mi->proc;
+ printf( " %6s %6dK %6dK %6dK %6dK %s [%d]\n", "",
+ mi->usage.vss / 1024,
+ mi->usage.rss / 1024,
+ mi->usage.pss / 1024,
+ mi->usage.uss / 1024,
+ pi->cmdline,
+ pi->pid);
+ }
+ printf("\n");
+ fflush(stdout);
+ }
+
+ return 0;
+}
+
+static void usage(char *myname) {
+ fprintf(stderr, "Usage: %s [ -P | -L ] [ -v | -r | -p | -u | -h ]\n"
+ "\n"
+ "Sort options:\n"
+ " -v Sort processes by VSS.\n"
+ " -r Sort processes by RSS.\n"
+ " -p Sort processes by PSS.\n"
+ " -u Sort processes by USS.\n"
+ " (Default sort order is PSS.)\n"
+ " -P /path Limit libraries displayed to those in path.\n"
+ " -R Reverse sort order (default is descending).\n"
+ " -h Display this help screen.\n",
+ myname);
+}
+
+static int getprocname(pid_t pid, char *buf, size_t len) {
+ char filename[20];
+ FILE *f;
+
+ sprintf(filename, "/proc/%d/cmdline", pid);
+ f = fopen(filename, "r");
+ if (!f) { *buf = '\0'; return 1; }
+ if (!fgets(buf, len, f)) { *buf = '\0'; return 2; }
+ fclose(f);
+ return 0;
+}
+
+static int numcmp(long long a, long long b) {
+ if (a < b) return -1;
+ if (a > b) return 1;
+ return 0;
+}
+
+static int licmp(const void *a, const void *b) {
+ return order * numcmp(
+ (*((struct library_info**)a))->total_usage.pss,
+ (*((struct library_info**)b))->total_usage.pss
+ );
+}
+
+#define create_sort(field, compfn) \
+ static int sort_by_ ## field (const void *a, const void *b) { \
+ return order * compfn( \
+ (*((struct mapping_info**)a))->usage.field, \
+ (*((struct mapping_info**)b))->usage.field \
+ ); \
+ }
+
+create_sort(vss, numcmp)
+create_sort(rss, numcmp)
+create_sort(pss, numcmp)
+create_sort(uss, numcmp)
diff --git a/procmem/Android.mk b/procmem/Android.mk
new file mode 100644
index 00000000..ffd56604
--- /dev/null
+++ b/procmem/Android.mk
@@ -0,0 +1,30 @@
+# 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_SRC_FILES := procmem.c
+
+LOCAL_C_INCLUDES := $(call include-path-for, libpagemap)
+
+LOCAL_SHARED_LIBRARIES := libpagemap
+
+LOCAL_MODULE := procmem
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+
+LOCAL_MODULE_TAGS := debug
+
+include $(BUILD_EXECUTABLE)
diff --git a/procmem/MODULE_LICENSE_APACHE2 b/procmem/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/procmem/MODULE_LICENSE_APACHE2
diff --git a/procmem/NOTICE b/procmem/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/procmem/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/procmem/procmem.c b/procmem/procmem.c
new file mode 100644
index 00000000..03c9f51f
--- /dev/null
+++ b/procmem/procmem.c
@@ -0,0 +1,322 @@
+/*
+ * 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 <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <pagemap/pagemap.h>
+
+/* Information about a single mapping */
+struct map_info {
+ pm_map_t *map;
+ pm_memusage_t usage;
+ /* page counts */
+ unsigned long shared_clean;
+ unsigned long shared_dirty;
+ unsigned long private_clean;
+ unsigned long private_dirty;
+};
+
+/* display the help screen */
+static void usage(const char *cmd);
+
+/* qsort compare function to compare maps by PSS */
+int comp_pss(const void *a, const void *b);
+
+int main(int argc, char *argv[]) {
+ pid_t pid;
+
+ /* libpagemap context */
+ pm_kernel_t *ker;
+ int pagesize; /* cached for speed */
+ pm_process_t *proc;
+
+ /* maps and such */
+ pm_map_t **maps; int num_maps;
+
+ struct map_info **mis;
+ struct map_info *mi;
+
+ /* pagemap information */
+ uint64_t *pagemap; int num_pages;
+ unsigned long address; uint64_t mapentry;
+ uint64_t count, flags;
+
+ /* totals */
+ unsigned long total_shared_clean, total_shared_dirty, total_private_clean, total_private_dirty;
+ pm_memusage_t total_usage;
+
+ /* command-line options */
+ int ws;
+#define WS_OFF (0)
+#define WS_ONLY (1)
+#define WS_RESET (2)
+ int (*compfn)(const void *a, const void *b);
+ int hide_zeros;
+
+ /* temporary variables */
+ int i, j;
+ char *endptr;
+ int error;
+
+ if (argc < 2) {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ ws = WS_OFF;
+ compfn = NULL;
+ hide_zeros = 0;
+ for (i = 1; i < argc - 1; i++) {
+ if (!strcmp(argv[i], "-w")) { ws = WS_ONLY; continue; }
+ if (!strcmp(argv[i], "-W")) { ws = WS_RESET; continue; }
+ if (!strcmp(argv[i], "-m")) { compfn = NULL; continue; }
+ if (!strcmp(argv[i], "-p")) { compfn = &comp_pss; continue; }
+ if (!strcmp(argv[i], "-h")) { hide_zeros = 1; continue; }
+ fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ pid = (pid_t)strtol(argv[argc - 1], &endptr, 10);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Invalid PID \"%s\".\n", argv[argc - 1]);
+ exit(EXIT_FAILURE);
+ }
+
+ error = pm_kernel_create(&ker);
+ if (error) {
+ fprintf(stderr, "error creating kernel interface -- "
+ "does this kernel have pagemap?\n");
+ exit(EXIT_FAILURE);
+ }
+
+ pagesize = pm_kernel_pagesize(ker);
+
+ error = pm_process_create(ker, pid, &proc);
+ if (error) {
+ fprintf(stderr, "error creating process interface -- "
+ "does process %d really exist?\n", pid);
+ exit(EXIT_FAILURE);
+ }
+
+ if (ws == WS_RESET) {
+ error = pm_process_workingset(proc, NULL, 1);
+ if (error) {
+ fprintf(stderr, "error resetting working set for process.\n");
+ exit(EXIT_FAILURE);
+ }
+ exit(EXIT_SUCCESS);
+ }
+
+ /* get maps, and allocate our map_info array */
+ error = pm_process_maps(proc, &maps, &num_maps);
+ if (error) {
+ fprintf(stderr, "error listing maps.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ mis = (struct map_info **)calloc(num_maps, sizeof(struct map_info *));
+ if (!mis) {
+ fprintf(stderr, "error allocating map_info array: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /* print header */
+ if (ws == WS_ONLY) {
+ printf("%7s %7s %7s %7s %7s %7s %7s %s\n",
+ "WRss", "WPss", "WUss", "WShCl", "WShDi", "WPrCl", "WPrDi", "Name");
+ printf("%7s %7s %7s %7s %7s %7s %7s %s\n",
+ "-------", "-------", "-------", "-------", "-------", "-------", "-------", "");
+ } else {
+ printf("%7s %7s %7s %7s %7s %7s %7s %7s %s\n",
+ "Vss", "Rss", "Pss", "Uss", "ShCl", "ShDi", "PrCl", "PrDi", "Name");
+ printf("%7s %7s %7s %7s %7s %7s %7s %7s %s\n",
+ "-------", "-------", "-------", "-------", "-------", "-------", "-------", "-------", "");
+ }
+
+ /* zero things */
+ pm_memusage_zero(&total_usage);
+ total_shared_clean = total_shared_dirty = total_private_clean = total_private_dirty = 0;
+
+ for (i = 0; i < num_maps; i++) {
+ mi = (struct map_info *)calloc(1, sizeof(struct map_info));
+ if (!mi) {
+ fprintf(stderr, "error allocating map_info: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ mi->map = maps[i];
+
+ /* get, and sum, memory usage */
+
+ if (ws == WS_ONLY)
+ error = pm_map_workingset(mi->map, &mi->usage);
+ else
+ error = pm_map_usage(mi->map, &mi->usage);
+ if (error) {
+ fflush(stdout);
+ fprintf(stderr, "error getting usage for map.\n");
+ continue;
+ }
+
+ pm_memusage_add(&total_usage, &mi->usage);
+
+ /* get, and sum, individual page counts */
+
+ error = pm_map_pagemap(mi->map, &pagemap, &num_pages);
+ if (error) {
+ fflush(stdout);
+ fprintf(stderr, "error getting pagemap for map.\n");
+ continue;
+ }
+
+ mi->shared_clean = mi->shared_dirty = mi->private_clean = mi->private_dirty = 0;
+
+ for (j = 0; j < num_pages; j++) {
+ address = pm_map_start(mi->map) + j * ker->pagesize;
+ mapentry = pagemap[j];
+
+ if (PM_PAGEMAP_PRESENT(mapentry) && !PM_PAGEMAP_SWAPPED(mapentry)) {
+
+ error = pm_kernel_count(ker, PM_PAGEMAP_PFN(mapentry), &count);
+ if (error) {
+ fflush(stdout);
+ fprintf(stderr, "error getting count for frame.\n");
+ }
+
+ error = pm_kernel_flags(ker, PM_PAGEMAP_PFN(mapentry), &flags);
+ if (error) {
+ fflush(stdout);
+ fprintf(stderr, "error getting flags for frame.\n");
+ }
+
+ if ((ws != WS_ONLY) || (flags & PM_PAGE_REFERENCED)) {
+ if (count > 1) {
+ if (flags & PM_PAGE_DIRTY)
+ mi->shared_dirty++;
+ else
+ mi->shared_clean++;
+ } else {
+ if (flags & PM_PAGE_DIRTY)
+ mi->private_dirty++;
+ else
+ mi->private_clean++;
+ }
+ }
+ }
+ }
+
+ total_shared_clean += mi->shared_clean;
+ total_shared_dirty += mi->shared_dirty;
+ total_private_clean += mi->private_clean;
+ total_private_dirty += mi->private_dirty;
+
+ /* add to array */
+ mis[i] = mi;
+ }
+
+ /* sort the array, if requested (compfn == NULL for original order) */
+ if (compfn)
+ qsort(mis, num_maps, sizeof(mis[0]), compfn);
+
+ for (i = 0; i < num_maps; i++) {
+ mi = mis[i];
+
+ if (hide_zeros && !mi->usage.rss)
+ continue;
+
+ if (ws == WS_ONLY) {
+ printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n",
+ (long)mi->usage.rss / 1024,
+ (long)mi->usage.pss / 1024,
+ (long)mi->usage.uss / 1024,
+ mi->shared_clean * pagesize / 1024,
+ mi->shared_dirty * pagesize / 1024,
+ mi->private_clean * pagesize / 1024,
+ mi->private_dirty * pagesize / 1024,
+ pm_map_name(mi->map)
+ );
+ } else {
+ printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n",
+ (long)mi->usage.vss / 1024,
+ (long)mi->usage.rss / 1024,
+ (long)mi->usage.pss / 1024,
+ (long)mi->usage.uss / 1024,
+ mi->shared_clean * pagesize / 1024,
+ mi->shared_dirty * pagesize / 1024,
+ mi->private_clean * pagesize / 1024,
+ mi->private_dirty * pagesize / 1024,
+ pm_map_name(mi->map)
+ );
+ }
+ }
+
+ /* print totals */
+ if (ws == WS_ONLY) {
+ printf("%7s %7s %7s %7s %7s %7s %7s %s\n",
+ "-------", "-------", "-------", "-------", "-------", "-------", "-------", "");
+ printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n",
+ (long)total_usage.rss / 1024,
+ (long)total_usage.pss / 1024,
+ (long)total_usage.uss / 1024,
+ total_shared_clean * pagesize / 1024,
+ total_shared_dirty * pagesize / 1024,
+ total_private_clean * pagesize / 1024,
+ total_private_dirty * pagesize / 1024,
+ "TOTAL"
+ );
+ } else {
+ printf("%7s %7s %7s %7s %7s %7s %7s %7s %s\n",
+ "-------", "-------", "-------", "-------", "-------", "-------", "-------", "-------", "");
+ printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n",
+ (long)total_usage.vss / 1024,
+ (long)total_usage.rss / 1024,
+ (long)total_usage.pss / 1024,
+ (long)total_usage.uss / 1024,
+ total_shared_clean * pagesize / 1024,
+ total_shared_dirty * pagesize / 1024,
+ total_private_clean * pagesize / 1024,
+ total_private_dirty * pagesize / 1024,
+ "TOTAL"
+ );
+ }
+
+ return 0;
+}
+
+static void usage(const char *cmd) {
+ fprintf(stderr, "Usage: %s [ -w | -W ] [ -p | -m ] [ -h ] pid\n"
+ " -w Displays statistics for the working set only.\n"
+ " -W Resets the working set of the process.\n"
+ " -p Sort by PSS.\n"
+ " -m Sort by mapping order (as read from /proc).\n"
+ " -h Hide maps with no RSS.\n",
+ cmd);
+}
+
+int comp_pss(const void *a, const void *b) {
+ struct map_info *ma, *mb;
+
+ ma = *((struct map_info **)a);
+ mb = *((struct map_info **)b);
+
+ if (mb->usage.pss < ma->usage.pss) return -1;
+ if (mb->usage.pss > ma->usage.pss) return 1;
+ return 0;
+}
diff --git a/procrank/Android.mk b/procrank/Android.mk
new file mode 100644
index 00000000..eb487105
--- /dev/null
+++ b/procrank/Android.mk
@@ -0,0 +1,30 @@
+# 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_SRC_FILES := procrank.c
+
+LOCAL_C_INCLUDES := $(call include-path-for, libpagemap)
+
+LOCAL_SHARED_LIBRARIES := libpagemap
+
+LOCAL_MODULE := procrank
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+
+LOCAL_MODULE_TAGS := debug
+
+include $(BUILD_EXECUTABLE)
diff --git a/procrank/MODULE_LICENSE_APACHE2 b/procrank/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/procrank/MODULE_LICENSE_APACHE2
diff --git a/procrank/NOTICE b/procrank/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/procrank/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/procrank/procrank.c b/procrank/procrank.c
new file mode 100644
index 00000000..585fddcd
--- /dev/null
+++ b/procrank/procrank.c
@@ -0,0 +1,206 @@
+/*
+ * 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 <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <pagemap/pagemap.h>
+
+struct proc_info {
+ pid_t pid;
+ pm_memusage_t usage;
+ unsigned long wss;
+};
+
+static void usage(char *myname);
+static int getprocname(pid_t pid, char *buf, size_t len);
+static int numcmp(long long a, long long b);
+
+#define declare_sort(field) \
+ static int sort_by_ ## field (const void *a, const void *b)
+
+declare_sort(vss);
+declare_sort(rss);
+declare_sort(pss);
+declare_sort(uss);
+
+int (*compfn)(const void *a, const void *b);
+static int order;
+
+#define MAX_PROCS 256
+
+int main(int argc, char *argv[]) {
+ pm_kernel_t *ker;
+ pm_process_t *proc;
+ pid_t *pids;
+ struct proc_info *procs[MAX_PROCS];
+ size_t num_procs;
+ char cmdline[256];
+ int error;
+
+ #define WS_OFF 0
+ #define WS_ONLY 1
+ #define WS_RESET 2
+ int ws;
+
+ int i, j;
+
+ compfn = &sort_by_pss;
+ order = -1;
+ ws = WS_OFF;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-v")) { compfn = &sort_by_vss; continue; }
+ if (!strcmp(argv[i], "-r")) { compfn = &sort_by_rss; continue; }
+ if (!strcmp(argv[i], "-p")) { compfn = &sort_by_pss; continue; }
+ if (!strcmp(argv[i], "-u")) { compfn = &sort_by_uss; continue; }
+ if (!strcmp(argv[i], "-w")) { ws = WS_ONLY; continue; }
+ if (!strcmp(argv[i], "-W")) { ws = WS_RESET; continue; }
+ if (!strcmp(argv[i], "-R")) { order *= -1; continue; }
+ if (!strcmp(argv[i], "-h")) { usage(argv[0]); exit(0); }
+ fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ error = pm_kernel_create(&ker);
+ if (error) {
+ fprintf(stderr, "Error creating kernel interface -- "
+ "does this kernel have pagemap?\n");
+ exit(EXIT_FAILURE);
+ }
+
+ error = pm_kernel_pids(ker, &pids, &num_procs);
+ if (error) {
+ fprintf(stderr, "Error listing processes.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < num_procs; i++) {
+ procs[i] = malloc(sizeof(struct proc_info));
+ if (!procs[i]) {
+ fprintf(stderr, "malloc: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ procs[i]->pid = pids[i];
+ error = pm_process_create(ker, pids[i], &proc);
+ if (!error) {
+ switch (ws) {
+ case WS_OFF:
+ pm_process_usage(proc, &procs[i]->usage);
+ break;
+ case WS_ONLY:
+ pm_process_workingset(proc, &procs[i]->usage, 0);
+ break;
+ case WS_RESET:
+ pm_process_workingset(proc, NULL, 1);
+ break;
+ }
+ pm_process_destroy(proc);
+ } else {
+ fprintf(stderr, "warning: could not create process interface for %d\n", pids[i]);
+ pm_memusage_zero(&procs[i]->usage);
+ }
+ }
+
+ free(pids);
+
+ if (ws == WS_RESET) exit(0);
+
+ j = 0;
+ for (i = 0; i < num_procs; i++) {
+ if (procs[i]->usage.vss)
+ procs[j++] = procs[i];
+ }
+ num_procs = j;
+
+ qsort(procs, num_procs, sizeof(procs[0]), compfn);
+
+ if (ws)
+ printf("%5s %7s %7s %7s %s\n", "PID", "WRss", "WPss", "WUss", "cmdline");
+ else
+ printf("%5s %7s %7s %7s %7s %s\n", "PID", "Vss", "Rss", "Pss", "Uss", "cmdline");
+ for (i = 0; i < num_procs; i++) {
+ getprocname(procs[i]->pid, cmdline, sizeof(cmdline));
+ if (ws)
+ printf("%5d %6dK %6dK %6dK %s\n",
+ procs[i]->pid,
+ procs[i]->usage.rss / 1024,
+ procs[i]->usage.pss / 1024,
+ procs[i]->usage.uss / 1024,
+ cmdline
+ );
+ else
+ printf("%5d %6dK %6dK %6dK %6dK %s\n",
+ procs[i]->pid,
+ procs[i]->usage.vss / 1024,
+ procs[i]->usage.rss / 1024,
+ procs[i]->usage.pss / 1024,
+ procs[i]->usage.uss / 1024,
+ cmdline
+ );
+ }
+
+ return 0;
+}
+
+static void usage(char *myname) {
+ fprintf(stderr, "Usage: %s [ -W ] [ -v | -r | -p | -u | -h ]\n"
+ " -v Sort by VSS.\n"
+ " -r Sort by RSS.\n"
+ " -p Sort by PSS.\n"
+ " -u Sort by USS.\n"
+ " (Default sort order is PSS.)\n"
+ " -R Reverse sort order (default is descending).\n"
+ " -w Display statistics for working set only.\n"
+ " -W Reset working set of all processes.\n"
+ " -h Display this help screen.\n",
+ myname);
+}
+
+static int getprocname(pid_t pid, char *buf, size_t len) {
+ char filename[20];
+ FILE *f;
+
+ sprintf(filename, "/proc/%d/cmdline", pid);
+ f = fopen(filename, "r");
+ if (!f) { *buf = '\0'; return 1; }
+ if (!fgets(buf, len, f)) { *buf = '\0'; return 2; }
+ fclose(f);
+ return 0;
+}
+
+static int numcmp(long long a, long long b) {
+ if (a < b) return -1;
+ if (a > b) return 1;
+ return 0;
+}
+
+#define create_sort(field, compfn) \
+ static int sort_by_ ## field (const void *a, const void *b) { \
+ return order * compfn( \
+ (*((struct proc_info**)a))->usage.field, \
+ (*((struct proc_info**)b))->usage.field \
+ ); \
+ }
+
+create_sort(vss, numcmp)
+create_sort(rss, numcmp)
+create_sort(pss, numcmp)
+create_sort(uss, numcmp)
diff --git a/showmap/Android.mk b/showmap/Android.mk
new file mode 100644
index 00000000..5c90f12f
--- /dev/null
+++ b/showmap/Android.mk
@@ -0,0 +1,13 @@
+# Copyright 2006 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= showmap.c
+LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE:= showmap
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/showmap/MODULE_LICENSE_APACHE2 b/showmap/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/showmap/MODULE_LICENSE_APACHE2
diff --git a/showmap/NOTICE b/showmap/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/showmap/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/showmap/showmap.c b/showmap/showmap.c
new file mode 100644
index 00000000..e8c7dd50
--- /dev/null
+++ b/showmap/showmap.c
@@ -0,0 +1,232 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <ctype.h>
+#include <stddef.h>
+
+typedef struct mapinfo mapinfo;
+
+struct mapinfo {
+ mapinfo *next;
+ unsigned start;
+ unsigned end;
+ unsigned size;
+ unsigned rss;
+ unsigned pss;
+ unsigned shared_clean;
+ unsigned shared_dirty;
+ unsigned private_clean;
+ unsigned private_dirty;
+ char name[1];
+};
+
+// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /android/lib/libcomposer.so
+// 012345678901234567890123456789012345678901234567890123456789
+// 0 1 2 3 4 5
+
+mapinfo *read_mapinfo(FILE *fp)
+{
+ char line[1024];
+ mapinfo *mi;
+ int len;
+ int skip;
+
+again:
+ skip = 0;
+
+ if(fgets(line, 1024, fp) == 0) return 0;
+
+ len = strlen(line);
+ if(len < 1) return 0;
+ line[--len] = 0;
+
+ mi = calloc(1, sizeof(mapinfo) + len + 16);
+ if(mi == 0) return 0;
+
+ mi->start = strtoul(line, 0, 16);
+ mi->end = strtoul(line + 9, 0, 16);
+
+ if(len < 50) {
+ if((mi->start >= 0x10000000) && (mi->start < 0x40000000)) {
+ strcpy(mi->name, "[stack]");
+ } else if(mi->start > 0x50000000) {
+ strcpy(mi->name, "[lib_bss]");
+ } else {
+ strcpy(mi->name, "[anon]");
+ }
+ } else {
+ strcpy(mi->name, line + 49);
+ }
+
+ if(fgets(line, 1024, fp) == 0) goto oops;
+ if(sscanf(line, "Size: %d kB", &mi->size) != 1) goto oops;
+ if(fgets(line, 1024, fp) == 0) goto oops;
+ if(sscanf(line, "Rss: %d kB", &mi->rss) != 1) goto oops;
+ if(fgets(line, 1024, fp) == 0) goto oops;
+ if(sscanf(line, "Pss: %d kB", &mi->pss) == 1)
+ if(fgets(line, 1024, fp) == 0) goto oops;
+ if(sscanf(line, "Shared_Clean: %d kB", &mi->shared_clean) != 1) goto oops;
+ if(fgets(line, 1024, fp) == 0) goto oops;
+ if(sscanf(line, "Shared_Dirty: %d kB", &mi->shared_dirty) != 1) goto oops;
+ if(fgets(line, 1024, fp) == 0) goto oops;
+ if(sscanf(line, "Private_Clean: %d kB", &mi->private_clean) != 1) goto oops;
+ if(fgets(line, 1024, fp) == 0) goto oops;
+ if(sscanf(line, "Private_Dirty: %d kB", &mi->private_dirty) != 1) goto oops;
+ if(fgets(line, 1024, fp) == 0) goto oops;
+
+ if(skip) {
+ free(mi);
+ goto again;
+ }
+
+ return mi;
+oops:
+ free(mi);
+ return 0;
+}
+
+
+mapinfo *load_maps(int pid, int verbose)
+{
+ char tmp[128];
+ FILE *fp;
+ mapinfo *milist = 0;
+ mapinfo *mi;
+
+ sprintf(tmp, "/proc/%d/smaps", pid);
+ fp = fopen(tmp, "r");
+ if(fp == 0) return 0;
+
+ while((mi = read_mapinfo(fp)) != 0) {
+ /* if not verbose, coalesce mappings from the same entity */
+ if(!verbose && milist) {
+ if((!strcmp(mi->name, milist->name) && (mi->name[0] != '['))
+ || !strcmp(mi->name,"[lib_bss]")) {
+ milist->size += mi->size;
+ milist->rss += mi->rss;
+ milist->pss += mi->pss;
+ milist->shared_clean += mi->shared_clean;
+ milist->shared_dirty += mi->shared_dirty;
+ milist->private_clean += mi->private_clean;
+ milist->private_dirty += mi->private_dirty;
+ milist->end = mi->end;
+ free(mi);
+ continue;
+ }
+ }
+
+ mi->next = milist;
+ milist = mi;
+ }
+ fclose(fp);
+
+ return milist;
+}
+
+static int verbose = 0;
+static int terse = 0;
+static int addresses = 0;
+
+int show_map(int pid)
+{
+ mapinfo *milist;
+ mapinfo *mi;
+ unsigned shared_dirty = 0;
+ unsigned shared_clean = 0;
+ unsigned private_dirty = 0;
+ unsigned private_clean = 0;
+ unsigned rss = 0;
+ unsigned pss = 0;
+ unsigned size = 0;
+
+ milist = load_maps(pid, verbose);
+ if(milist == 0) {
+ fprintf(stderr,"cannot get /proc/smaps for pid %d\n", pid);
+ return 1;
+ }
+
+ if(addresses) {
+ printf("start end shared private object\n");
+ printf("-------- -------- -------- -------- ------------------------------\n");
+ } else {
+ printf("virtual shared shared private private\n");
+ printf("size RSS PSS clean dirty clean dirty object\n");
+ printf("-------- -------- -------- -------- -------- -------- -------- ------------------------------\n");
+ }
+ for(mi = milist; mi; mi = mi->next){
+ shared_clean += mi->shared_clean;
+ shared_dirty += mi->shared_dirty;
+ private_clean += mi->private_clean;
+ private_dirty += mi->private_dirty;
+ rss += mi->rss;
+ pss += mi->pss;
+ size += mi->size;
+
+ if(terse && !mi->private_dirty) continue;
+
+ if(addresses) {
+ printf("%08x %08x %8d %8d %s\n", mi->start, mi->end,
+ mi->shared_clean + mi->shared_dirty,
+ mi->private_clean + mi->private_dirty,
+ mi->name);
+ } else {
+ printf("%8d %8d %8d %8d %8d %8d %8d %s\n", mi->size,
+ mi->rss,
+ mi->pss,
+ mi->shared_clean, mi->shared_dirty,
+ mi->private_clean, mi->private_dirty,
+ mi->name);
+ }
+ }
+ if(addresses) {
+ printf("-------- -------- -------- -------- ------------------------------\n");
+ printf(" %8d %8d TOTAL\n",
+ shared_dirty + shared_clean,
+ private_dirty + private_clean);
+ } else {
+ printf("-------- -------- -------- -------- -------- -------- -------- ------------------------------\n");
+ printf("%8d %8d %8d %8d %8d %8d %8d TOTAL\n", size,
+ rss, pss,
+ shared_clean, shared_dirty,
+ private_clean, private_dirty);
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int usage = 1;
+
+ for(argc--, argv++; argc > 0; argc--, argv++) {
+ if(!strcmp(argv[0],"-v")) {
+ verbose = 1;
+ continue;
+ }
+ if(!strcmp(argv[0],"-t")) {
+ terse = 1;
+ continue;
+ }
+ if(!strcmp(argv[0],"-a")) {
+ addresses = 1;
+ continue;
+ }
+ show_map(atoi(argv[0]));
+ usage = 0;
+ }
+
+ if(usage) {
+ fprintf(stderr,
+ "showmap [-t] [-v] [-c] <pid>\n"
+ " -t = terse (show only items with private pages)\n"
+ " -v = verbose (don't coalesce adjacant maps)\n"
+ " -a = addresses (show virtual memory map)\n"
+ );
+ }
+
+ return 0;
+}
diff --git a/showslab/Android.mk b/showslab/Android.mk
new file mode 100644
index 00000000..c914a8b6
--- /dev/null
+++ b/showslab/Android.mk
@@ -0,0 +1,15 @@
+# Copyright 2007 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= showslab.c
+LOCAL_SHARED_LIBRARIES :=
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE:= showslab
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/showslab/MODULE_LICENSE_APACHE2 b/showslab/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/showslab/MODULE_LICENSE_APACHE2
diff --git a/showslab/NOTICE b/showslab/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/showslab/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/showslab/showslab.c b/showslab/showslab.c
new file mode 100644
index 00000000..9c9e60eb
--- /dev/null
+++ b/showslab/showslab.c
@@ -0,0 +1,351 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+
+#define STRINGIFY_ARG(a) #a
+#define STRINGIFY(a) STRINGIFY_ARG(a)
+
+#define DEF_SORT_FUNC sort_nr_objs
+#define SLABINFO_LINE_LEN 512 /* size of longest line */
+#define SLABINFO_NAME_LEN 32 /* cache name size (will truncate) */
+#define SLABINFO_FILE "/proc/slabinfo"
+#define DEF_NR_ROWS 15 /* default nr of caches to show */
+
+/* object representing a slab cache (each line of slabinfo) */
+struct slab_info {
+ char name[SLABINFO_NAME_LEN]; /* name of this cache */
+ struct slab_info *next;
+ unsigned long nr_pages; /* size of cache in pages */
+ unsigned long nr_objs; /* number of objects in this cache */
+ unsigned long nr_active_objs; /* number of active objects */
+ unsigned long obj_size; /* size of each object */
+ unsigned long objs_per_slab; /* number of objects per slab */
+ unsigned long nr_slabs; /* number of slabs in this cache */
+ unsigned long use; /* percent full: total / active */
+};
+
+/* object representing system-wide statistics */
+struct slab_stat {
+ unsigned long total_size; /* size of all objects */
+ unsigned long active_size; /* size of all active objects */
+ unsigned long nr_objs; /* total number of objects */
+ unsigned long nr_active_objs; /* total number of active objects */
+ unsigned long nr_slabs; /* total number of slabs */
+ unsigned long nr_active_slabs; /* total number of active slabs*/
+ unsigned long nr_caches; /* number of caches */
+ unsigned long nr_active_caches; /* number of active caches */
+ unsigned long avg_obj_size; /* average object size */
+ unsigned long min_obj_size; /* size of smallest object */
+ unsigned long max_obj_size; /* size of largest object */
+};
+
+typedef int (*sort_t)(const struct slab_info *, const struct slab_info *);
+static sort_t sort_func;
+
+/*
+ * get_slabinfo - open, read, and parse a slabinfo 2.x file, which has the
+ * following format:
+ *
+ * slabinfo - version: 2.1
+ * <name> <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab>
+ * : tunables <limit> <batchcount> <sharedfactor>
+ * : slabdata <active_slabs> <num_slabs> <sharedavail>
+ *
+ * Returns the head of the new list of slab_info structures, or NULL on error.
+ */
+static struct slab_info * get_slabinfo(struct slab_stat *stats)
+{
+ struct slab_info *head = NULL, *p = NULL, *prev = NULL;
+ FILE *slabfile;
+ char line[SLABINFO_LINE_LEN];
+ unsigned int major, minor;
+
+ slabfile = fopen(SLABINFO_FILE, "r");
+ if (!slabfile) {
+ perror("fopen");
+ return NULL;
+ }
+
+ if (!fgets(line, SLABINFO_LINE_LEN, slabfile)) {
+ fprintf(stderr, "cannot read from " SLABINFO_FILE "\n");
+ return NULL;
+ }
+
+ if (sscanf(line, "slabinfo - version: %u.%u", &major, &minor) != 2) {
+ fprintf(stderr, "unable to parse slabinfo version!\n");
+ return NULL;
+ }
+
+ if (major != 2 || minor > 1) {
+ fprintf(stderr, "we only support slabinfo 2.0 and 2.1!\n");
+ return NULL;
+ }
+
+ stats->min_obj_size = INT_MAX;
+
+ while (fgets(line, SLABINFO_LINE_LEN, slabfile)) {
+ unsigned long nr_active_slabs, pages_per_slab;
+ int ret;
+
+ if (line[0] == '#')
+ continue;
+
+ p = malloc(sizeof (struct slab_info));
+ if (!p) {
+ perror("malloc");
+ head = NULL;
+ break;
+ }
+ if (stats->nr_caches++ == 0)
+ head = prev = p;
+
+ ret = sscanf(line, "%" STRINGIFY(SLABINFO_NAME_LEN) "s"
+ " %lu %lu %lu %lu %lu : tunables %*d %*d %*d : \
+ slabdata %lu %lu %*d", p->name,
+ &p->nr_active_objs, &p->nr_objs,
+ &p->obj_size, &p->objs_per_slab,
+ &pages_per_slab,
+ &nr_active_slabs,
+ &p->nr_slabs);
+
+ if (ret != 8) {
+ fprintf(stderr, "unrecognizable data in slabinfo!\n");
+ head = NULL;
+ break;
+ }
+
+ if (p->obj_size < stats->min_obj_size)
+ stats->min_obj_size = p->obj_size;
+ if (p->obj_size > stats->max_obj_size)
+ stats->max_obj_size = p->obj_size;
+
+ p->nr_pages = p->nr_slabs * pages_per_slab;
+
+ if (p->nr_objs) {
+ p->use = 100 * p->nr_active_objs / p->nr_objs;
+ stats->nr_active_caches++;
+ } else
+ p->use = 0;
+
+ stats->nr_objs += p->nr_objs;
+ stats->nr_active_objs += p->nr_active_objs;
+ stats->total_size += p->nr_objs * p->obj_size;
+ stats->active_size += p->nr_active_objs * p->obj_size;
+ stats->nr_slabs += p->nr_slabs;
+ stats->nr_active_slabs += nr_active_slabs;
+
+ prev->next = p;
+ prev = p;
+ }
+
+ if (fclose(slabfile))
+ perror("fclose");
+
+ if (p)
+ p->next = NULL;
+ if (stats->nr_objs)
+ stats->avg_obj_size = stats->total_size / stats->nr_objs;
+
+ return head;
+}
+
+/*
+ * free_slablist - deallocate the memory associated with each node in the
+ * provided slab_info linked list
+ */
+static void free_slablist(struct slab_info *list)
+{
+ while (list) {
+ struct slab_info *temp = list->next;
+ free(list);
+ list = temp;
+ }
+}
+
+static struct slab_info *merge_objs(struct slab_info *a, struct slab_info *b)
+{
+ struct slab_info list;
+ struct slab_info *p = &list;
+
+ while (a && b) {
+ if (sort_func(a, b)) {
+ p->next = a;
+ p = a;
+ a = a->next;
+ } else {
+ p->next = b;
+ p = b;
+ b = b->next;
+ }
+ }
+
+ p->next = (a == NULL) ? b : a;
+ return list.next;
+}
+
+/*
+ * slabsort - merge sort the slab_info linked list based on sort_func
+ */
+static struct slab_info *slabsort(struct slab_info *list)
+{
+ struct slab_info *a, *b;
+
+ if (!list || !list->next)
+ return list;
+
+ a = list;
+ b = list->next;
+
+ while (b && b->next) {
+ list = list->next;
+ b = b->next->next;
+ }
+
+ b = list->next;
+ list->next = NULL;
+
+ return merge_objs(slabsort(a), slabsort(b));
+}
+
+/*
+ * Sort Routines. Each of these should be associated with a command-line
+ * search option. The functions should fit the prototype:
+ *
+ * int sort_foo(const struct slab_info *a, const struct slab_info *b)
+ *
+ * They return zero if the first parameter is smaller than the second.
+ * Otherwise, they return nonzero.
+ */
+
+static int sort_name(const struct slab_info *a, const struct slab_info *b)
+{
+ return (strcmp(a->name, b->name) < 0 ) ? 1: 0;
+}
+
+#define BUILD_SORT_FUNC(VAL) \
+ static int sort_ ## VAL \
+ (const struct slab_info *a, const struct slab_info *b) { \
+ return (a-> VAL > b-> VAL); }
+
+BUILD_SORT_FUNC(nr_objs)
+BUILD_SORT_FUNC(nr_active_objs)
+BUILD_SORT_FUNC(obj_size)
+BUILD_SORT_FUNC(objs_per_slab)
+BUILD_SORT_FUNC(nr_slabs)
+BUILD_SORT_FUNC(use)
+BUILD_SORT_FUNC(nr_pages)
+
+/*
+ * set_sort_func - return the slab_sort_func that matches the given key.
+ * On unrecognizable key, the call returns NULL.
+ */
+static void * set_sort_func(char key)
+{
+ switch (tolower(key)) {
+ case 'a':
+ return sort_nr_active_objs;
+ case 'c':
+ return sort_nr_pages;
+ case 'l':
+ return sort_nr_slabs;
+ case 'n':
+ return sort_name;
+ case 'o':
+ return sort_nr_objs;
+ case 'p':
+ return sort_objs_per_slab;
+ case 's':
+ return sort_obj_size;
+ case 'u':
+ return sort_use;
+ default:
+ return NULL;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ struct slab_info *list, *p;
+ struct slab_stat stats = { .nr_objs = 0 };
+ unsigned int page_size = getpagesize() / 1024, nr_rows = DEF_NR_ROWS, i;
+
+ sort_func = DEF_SORT_FUNC;
+
+ if (argc > 1) {
+ /* FIXME: Ugh. */
+ if (argc == 3 && !strcmp(argv[1], "-n")) {
+ errno = 0;
+ nr_rows = (unsigned int) strtoul(argv[2], NULL, 0);
+ if (errno) {
+ perror("strtoul");
+ exit(EXIT_FAILURE);
+ }
+ }
+ else if (argc == 3 && !strcmp(argv[1], "-s"))
+ sort_func = set_sort_func(argv[2][0]) ? : DEF_SORT_FUNC;
+ else {
+ fprintf(stderr, "usage: %s [options]\n\n", argv[0]);
+ fprintf(stderr, "options:\n");
+ fprintf(stderr, " -s S specify sort criteria S\n");
+ fprintf(stderr, " -h display this help\n\n");
+ fprintf(stderr, "Valid sort criteria:\n");
+ fprintf(stderr, " a: number of Active objects\n");
+ fprintf(stderr, " c: Cache size\n");
+ fprintf(stderr, " l: number of sLabs\n");
+ fprintf(stderr, " n: Name\n");
+ fprintf(stderr, " o: number of Objects\n");
+ fprintf(stderr, " p: objects Per slab\n");
+ fprintf(stderr, " s: object Size\n");
+ fprintf(stderr, " u: cache Utilization\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ list = get_slabinfo (&stats);
+ if (!list)
+ exit(EXIT_FAILURE);
+
+ printf(" Active / Total Objects (%% used) : %lu / %lu (%.1f%%)\n"
+ " Active / Total Slabs (%% used) : %lu / %lu (%.1f%%)\n"
+ " Active / Total Caches (%% used) : %lu / %lu (%.1f%%)\n"
+ " Active / Total Size (%% used) : %.2fK / %.2fK (%.1f%%)\n"
+ " Min / Avg / Max Object Size : %.2fK / %.2fK / %.2fK\n\n",
+ stats.nr_active_objs,
+ stats.nr_objs,
+ 100.0 * stats.nr_active_objs / stats.nr_objs,
+ stats.nr_active_slabs,
+ stats.nr_slabs,
+ 100.0 * stats.nr_active_slabs / stats.nr_slabs,
+ stats.nr_active_caches,
+ stats.nr_caches,
+ 100.0 * stats.nr_active_caches / stats.nr_caches,
+ stats.active_size / 1024.0,
+ stats.total_size / 1024.0,
+ 100.0 * stats.active_size / stats.total_size,
+ stats.min_obj_size / 1024.0,
+ stats.avg_obj_size / 1024.0,
+ stats.max_obj_size / 1024.0);
+
+ printf("%6s %6s %4s %8s %6s %8s %10s %-23s\n",
+ "OBJS", "ACTIVE", "USE", "OBJ SIZE", "SLABS",
+ "OBJ/SLAB", "CACHE SIZE", "NAME");
+
+ p = list = slabsort(list);
+ for (i = 0; i < nr_rows && p; i++) {
+ printf("%6lu %6lu %3lu%% %7.2fK %6lu %8lu %9luK %-23s\n",
+ p->nr_objs, p->nr_active_objs, p->use,
+ p->obj_size / 1024.0, p->nr_slabs,
+ p->objs_per_slab,
+ p->nr_pages * page_size,
+ p->name);
+ p = p->next;
+ }
+
+ free_slablist(list);
+
+ return 0;
+}
diff --git a/sound/Android.mk b/sound/Android.mk
new file mode 100644
index 00000000..7a58998b
--- /dev/null
+++ b/sound/Android.mk
@@ -0,0 +1,8 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := sound
+LOCAL_SRC_FILES := playwav.c
+LOCAL_MODULE_TAGS := tests
+include $(BUILD_EXECUTABLE)
+
diff --git a/sound/playwav.c b/sound/playwav.c
new file mode 100644
index 00000000..6d6bce75
--- /dev/null
+++ b/sound/playwav.c
@@ -0,0 +1,376 @@
+/* Copyright (C) 2008 The Android Open Source Project
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <linux/ioctl.h>
+
+#define AUDIO_IOCTL_MAGIC 'a'
+
+#define AUDIO_START _IOW(AUDIO_IOCTL_MAGIC, 0, unsigned)
+#define AUDIO_STOP _IOW(AUDIO_IOCTL_MAGIC, 1, unsigned)
+#define AUDIO_FLUSH _IOW(AUDIO_IOCTL_MAGIC, 2, unsigned)
+#define AUDIO_GET_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 3, unsigned)
+#define AUDIO_SET_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 4, unsigned)
+#define AUDIO_GET_STATS _IOR(AUDIO_IOCTL_MAGIC, 5, unsigned)
+
+struct msm_audio_config {
+ uint32_t buffer_size;
+ uint32_t buffer_count;
+ uint32_t channel_count;
+ uint32_t sample_rate;
+ uint32_t codec_type;
+ uint32_t unused[3];
+};
+
+struct msm_audio_stats {
+ uint32_t out_bytes;
+ uint32_t unused[3];
+};
+
+int pcm_play(unsigned rate, unsigned channels,
+ int (*fill)(void *buf, unsigned sz, void *cookie),
+ void *cookie)
+{
+ struct msm_audio_config config;
+ struct msm_audio_stats stats;
+ unsigned sz, n;
+ char buf[8192];
+ int afd;
+
+ afd = open("/dev/msm_pcm_out", O_RDWR);
+ if (afd < 0) {
+ perror("pcm_play: cannot open audio device");
+ return -1;
+ }
+
+ if(ioctl(afd, AUDIO_GET_CONFIG, &config)) {
+ perror("could not get config");
+ return -1;
+ }
+
+ config.channel_count = channels;
+ config.sample_rate = rate;
+ if (ioctl(afd, AUDIO_SET_CONFIG, &config)) {
+ perror("could not set config");
+ return -1;
+ }
+ sz = config.buffer_size;
+ if (sz > sizeof(buf)) {
+ fprintf(stderr,"too big\n");
+ return -1;
+ }
+
+ fprintf(stderr,"prefill\n");
+ for (n = 0; n < config.buffer_count; n++) {
+ if (fill(buf, sz, cookie))
+ break;
+ if (write(afd, buf, sz) != sz)
+ break;
+ }
+
+ fprintf(stderr,"start\n");
+ ioctl(afd, AUDIO_START, 0);
+
+ for (;;) {
+#if 0
+ if (ioctl(afd, AUDIO_GET_STATS, &stats) == 0)
+ fprintf(stderr,"%10d\n", stats.out_bytes);
+#endif
+ if (fill(buf, sz, cookie))
+ break;
+ if (write(afd, buf, sz) != sz)
+ break;
+ }
+
+done:
+ close(afd);
+ return 0;
+}
+
+/* http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+
+static char *next;
+static unsigned avail;
+
+int fill_buffer(void *buf, unsigned sz, void *cookie)
+{
+ if (sz > avail)
+ return -1;
+ memcpy(buf, next, sz);
+ next += sz;
+ avail -= sz;
+ return 0;
+}
+
+void play_file(unsigned rate, unsigned channels,
+ int fd, unsigned count)
+{
+ next = malloc(count);
+ if (!next) {
+ fprintf(stderr,"could not allocate %d bytes\n", count);
+ return;
+ }
+ if (read(fd, next, count) != count) {
+ fprintf(stderr,"could not read %d bytes\n", count);
+ return;
+ }
+ avail = count;
+ pcm_play(rate, channels, fill_buffer, 0);
+}
+
+int wav_play(const char *fn)
+{
+ struct wav_header hdr;
+ unsigned rate, channels;
+ int fd;
+ fd = open(fn, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "playwav: cannot open '%s'\n", fn);
+ return -1;
+ }
+ if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ fprintf(stderr, "playwav: cannot read header\n");
+ return -1;
+ }
+ fprintf(stderr,"playwav: %d ch, %d hz, %d bit, %s\n",
+ hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
+ hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");
+
+ if ((hdr.riff_id != ID_RIFF) ||
+ (hdr.riff_fmt != ID_WAVE) ||
+ (hdr.fmt_id != ID_FMT)) {
+ fprintf(stderr, "playwav: '%s' is not a riff/wave file\n", fn);
+ return -1;
+ }
+ if ((hdr.audio_format != FORMAT_PCM) ||
+ (hdr.fmt_sz != 16)) {
+ fprintf(stderr, "playwav: '%s' is not pcm format\n", fn);
+ return -1;
+ }
+ if (hdr.bits_per_sample != 16) {
+ fprintf(stderr, "playwav: '%s' is not 16bit per sample\n", fn);
+ return -1;
+ }
+
+ play_file(hdr.sample_rate, hdr.num_channels,
+ fd, hdr.data_sz);
+
+ return 0;
+}
+
+int wav_rec(const char *fn, unsigned channels, unsigned rate)
+{
+ struct wav_header hdr;
+ unsigned char buf[8192];
+ struct msm_audio_config cfg;
+ unsigned sz, n;
+ int fd, afd;
+ unsigned total = 0;
+ unsigned char tmp;
+
+ hdr.riff_id = ID_RIFF;
+ hdr.riff_sz = 0;
+ hdr.riff_fmt = ID_WAVE;
+ hdr.fmt_id = ID_FMT;
+ hdr.fmt_sz = 16;
+ hdr.audio_format = FORMAT_PCM;
+ hdr.num_channels = channels;
+ hdr.sample_rate = rate;
+ hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2;
+ hdr.block_align = hdr.num_channels * 2;
+ hdr.bits_per_sample = 16;
+ hdr.data_id = ID_DATA;
+ hdr.data_sz = 0;
+
+ fd = open(fn, O_CREAT | O_RDWR, 0666);
+ if (fd < 0) {
+ perror("cannot open output file");
+ return -1;
+ }
+ write(fd, &hdr, sizeof(hdr));
+
+ afd = open("/dev/msm_pcm_in", O_RDWR);
+ if (afd < 0) {
+ perror("cannot open msm_pcm_in");
+ close(fd);
+ return -1;
+ }
+
+ /* config change should be a read-modify-write operation */
+ if (ioctl(afd, AUDIO_GET_CONFIG, &cfg)) {
+ perror("cannot read audio config");
+ goto fail;
+ }
+
+ cfg.channel_count = hdr.num_channels;
+ cfg.sample_rate = hdr.sample_rate;
+ if (ioctl(afd, AUDIO_SET_CONFIG, &cfg)) {
+ perror("cannot write audio config");
+ goto fail;
+ }
+
+ if (ioctl(afd, AUDIO_GET_CONFIG, &cfg)) {
+ perror("cannot read audio config");
+ goto fail;
+ }
+
+ sz = cfg.buffer_size;
+ fprintf(stderr,"buffer size %d x %d\n", sz, cfg.buffer_count);
+ if (sz > sizeof(buf)) {
+ fprintf(stderr,"buffer size %d too large\n", sz);
+ goto fail;
+ }
+
+ if (ioctl(afd, AUDIO_START, 0)) {
+ perror("cannot start audio");
+ goto fail;
+ }
+
+ fcntl(0, F_SETFL, O_NONBLOCK);
+ fprintf(stderr,"\n*** RECORDING * HIT ENTER TO STOP ***\n");
+
+ for (;;) {
+ while (read(0, &tmp, 1) == 1) {
+ if ((tmp == 13) || (tmp == 10)) goto done;
+ }
+ if (read(afd, buf, sz) != sz) {
+ perror("cannot read buffer");
+ goto fail;
+ }
+ if (write(fd, buf, sz) != sz) {
+ perror("cannot write buffer");
+ goto fail;
+ }
+ total += sz;
+
+ }
+done:
+ close(afd);
+
+ /* update lengths in header */
+ hdr.data_sz = total;
+ hdr.riff_sz = total + 8 + 16 + 8;
+ lseek(fd, 0, SEEK_SET);
+ write(fd, &hdr, sizeof(hdr));
+ close(fd);
+ return 0;
+
+fail:
+ close(afd);
+ close(fd);
+ unlink(fn);
+ return -1;
+}
+
+int mp3_play(const char *fn)
+{
+ char buf[64*1024];
+ int r;
+ int fd, afd;
+
+ fd = open(fn, O_RDONLY);
+ if (fd < 0) {
+ perror("cannot open mp3 file");
+ return -1;
+ }
+
+ afd = open("/dev/msm_mp3", O_RDWR);
+ if (afd < 0) {
+ close(fd);
+ perror("cannot open mp3 output device");
+ return -1;
+ }
+
+ fprintf(stderr,"MP3 PLAY\n");
+ ioctl(afd, AUDIO_START, 0);
+
+ for (;;) {
+ r = read(fd, buf, 64*1024);
+ if (r <= 0) break;
+ r = write(afd, buf, r);
+ if (r < 0) break;
+ }
+
+ close(fd);
+ close(afd);
+}
+
+int main(int argc, char **argv)
+{
+ const char *fn = 0;
+ int play = 1;
+ unsigned channels = 1;
+ unsigned rate = 44100;
+
+ argc--;
+ argv++;
+ while (argc > 0) {
+ if (!strcmp(argv[0],"-rec")) {
+ play = 0;
+ } else if (!strcmp(argv[0],"-play")) {
+ play = 1;
+ } else if (!strcmp(argv[0],"-stereo")) {
+ channels = 2;
+ } else if (!strcmp(argv[0],"-mono")) {
+ channels = 1;
+ } else if (!strcmp(argv[0],"-rate")) {
+ argc--;
+ argv++;
+ if (argc == 0) {
+ fprintf(stderr,"playwav: -rate requires a parameter\n");
+ return -1;
+ }
+ rate = atoi(argv[0]);
+ } else {
+ fn = argv[0];
+ }
+ argc--;
+ argv++;
+ }
+
+ if (fn == 0) {
+ fn = play ? "/data/out.wav" : "/data/rec.wav";
+ }
+
+ if (play) {
+ const char *dot = strrchr(fn, '.');
+ if (dot && !strcmp(dot,".mp3")) {
+ return mp3_play(fn);
+ } else {
+ return wav_play(fn);
+ }
+ } else {
+ return wav_rec(fn, channels, rate);
+ }
+ return 0;
+}
diff --git a/su/Android.mk b/su/Android.mk
new file mode 100644
index 00000000..dd412d59
--- /dev/null
+++ b/su/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= su.c
+
+LOCAL_MODULE:= su
+
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+
+LOCAL_STATIC_LIBRARIES := libc
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/su/MODULE_LICENSE_APACHE2 b/su/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/su/MODULE_LICENSE_APACHE2
diff --git a/su/NOTICE b/su/NOTICE
new file mode 100644
index 00000000..c5b1efa7
--- /dev/null
+++ b/su/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/su/su.c b/su/su.c
new file mode 100644
index 00000000..aac981ea
--- /dev/null
+++ b/su/su.c
@@ -0,0 +1,86 @@
+/*
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include <unistd.h>
+#include <time.h>
+
+#include <pwd.h>
+
+/*
+ * SU can be given a specific command to exec. UID _must_ be
+ * specified for this (ie argc => 3). Full path of file must be specified.
+ *
+ * Usage:
+ * su 1000
+ * su 1000 /system/bin/ls -l
+ */
+int main(int argc, char **argv)
+{
+ struct passwd *pw;
+ int uid, gid;
+
+ if(argc < 2) {
+ uid = gid = 0;
+ } else {
+ pw = getpwnam(argv[1]);
+
+ if(pw == 0) {
+ uid = gid = atoi(argv[1]);
+ } else {
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+ }
+ }
+
+ if(setgid(gid) || setuid(uid)) {
+ fprintf(stderr,"su: permission denied\n");
+ return 1;
+ }
+
+ /* User specified command for exec. */
+ if (argc == 3 ) {
+ if (execlp(argv[2], argv[2], NULL) < 0) {
+ fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2],
+ strerror(errno));
+ return -errno;
+ }
+ } else if (argc > 3) {
+ /* Copy the rest of the args from main. */
+ char *exec_args[argc - 1];
+ memset(exec_args, 0, sizeof(exec_args));
+ memcpy(exec_args, &argv[2], sizeof(exec_args));
+ if (execv(argv[2], exec_args) < 0) {
+ fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2],
+ strerror(errno));
+ return -errno;
+ }
+ }
+
+ /* Default exec shell. */
+ execlp("/system/bin/sh", "sh", NULL);
+
+ fprintf(stderr, "su: exec failed\n");
+ return 1;
+}
+
diff --git a/tests/Android.mk b/tests/Android.mk
new file mode 100644
index 00000000..582ddc90
--- /dev/null
+++ b/tests/Android.mk
@@ -0,0 +1,3 @@
+ifeq ($(TARGET_ARCH),arm)
+include $(call all-subdir-makefiles)
+endif
diff --git a/tests/cpueater/Android.mk b/tests/cpueater/Android.mk
new file mode 100644
index 00000000..88e3cd83
--- /dev/null
+++ b/tests/cpueater/Android.mk
@@ -0,0 +1,24 @@
+# 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 := tests eng
+LOCAL_SRC_FILES := cpueater.c
+include $(BUILD_EXECUTABLE)
+
diff --git a/tests/cpueater/cpueater.c b/tests/cpueater/cpueater.c
new file mode 100644
index 00000000..b7d69ff9
--- /dev/null
+++ b/tests/cpueater/cpueater.c
@@ -0,0 +1,82 @@
+/*
+ * 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;
+ }
+}
+
+
+/* vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab */
+
diff --git a/tests/fstest/Android.mk b/tests/fstest/Android.mk
new file mode 100644
index 00000000..bf4f17c3
--- /dev/null
+++ b/tests/fstest/Android.mk
@@ -0,0 +1,43 @@
+# 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_SRC_FILES := perm_checker.c
+
+LOCAL_SHARED_LIBRARIES := libc
+
+LOCAL_MODULE := perm_checker
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
+
+####
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := perm_checker.conf
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_MODULE_CLASS := ETC
+
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
diff --git a/tests/fstest/README b/tests/fstest/README
new file mode 100644
index 00000000..e4f8194c
--- /dev/null
+++ b/tests/fstest/README
@@ -0,0 +1,68 @@
+All files and directories will be matched against entries taken from
+/etc/perm_checker.conf, and any file/directory which fails the ruleset
+will cause an error message along with a corresponding explicit (fully
+specified and minimal) rule for that file/directory to be printed on
+stdout. If only the message "Passed." is printed on stdout, all files are
+correctly matched by perm_checker.conf.
+
+A file or directory will always fail the ruleset unless there is AT LEAST
+one matching rule. If there is an explicit (fully specified) <spec>
+matching the file or directory name, it will fail if and only if that
+explicit <spec> rule fails (i.e., other matching <spec> rules will be
+ignored). Otherwise, it will fail if _any_ matching wildcard or recursive
+<spec> rule fails to hold.
+
+Entries in the perm_checker.conf file are of the following form:
+
+<spec> <min_mode> <max_mode> <min_uid> <max_uid> <min_gid> <max_gid>
+
+Where <spec> is one of the following:
+
+A fully specified path name, which must end in / ex: /dev/
+A fully specified filename, symlink, device node, etc. ex: /dev/tty0
+
+A recursive path specification, which ends in /... ex: /dev/...
+A wildcard file specification, which ends in * ex: /dev/tty*
+
+By convention /dev/* will include all files directly in /dev/, but not files
+that are in subdirectories of /dev/, such as /dev/input/, unlike a
+recursive path specification. The wildcard notation * will never result in
+a match to a directory name.
+
+NOTE: Symbolic links are treated specially to prevent infinite recursion
+and simplify the ruleset. Symbolic links are ignored unless an explicit
+rule with the same name as the symlink exists, in which case the permissions
+on the rule must match the permissions on the symlink itself, not the target.
+
+<min_mode> is a numeric mode mask, and a mode will match it if and only if
+(min_mode & mode) == min_mode.
+
+<max_mode> is a numeric mode mask, and a mode will match it if and only if
+(max_mode | mode) == max_mode.
+
+<min_uid> may be either a numeric user id, or a user name (which must not
+start with a number). If it is a user name, getpwnam() will be used to
+translate it to a numeric user id.
+
+<max_uid>, <min_gid>, and <max_gid> have similar syntax to <min_uid>.
+
+
+-- Tips --
+
+I recommend to use 19999 as the maximum uid/gid whenever any valid
+application uid/gid is acceptable.
+
+Once the test is installed, it can be executed via:
+
+adb shell perm_checker
+
+To get a list of all failing rules:
+
+adb shell perm_checker | grep "^# INFO #" | sort | uniq
+
+To get a fully specified set of rules for all failing files:
+
+adb shell perm_checker | grep -v "^#"
+
+NOTE: There may be failing files even if no rules have failed, since a
+file that does not match any rule is a failure.
diff --git a/tests/fstest/perm_checker.c b/tests/fstest/perm_checker.c
new file mode 100644
index 00000000..5cead10b
--- /dev/null
+++ b/tests/fstest/perm_checker.c
@@ -0,0 +1,399 @@
+/*
+ * 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.
+ */
+
+// A simple file permissions checker. See associated README.
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <pwd.h>
+#include <grp.h>
+
+#include <linux/kdev_t.h>
+
+#define PERMS(M) (M & ~S_IFMT)
+#define MAX_NAME_LEN 4096
+#define MAX_UID_LEN 256
+#define MAX_GID_LEN MAX_UID_LEN
+
+enum perm_rule_type {EXACT_FILE = 0, EXACT_DIR, WILDCARD, RECURSIVE,
+ NUM_PR_TYPES};
+
+struct perm_rule {
+ char *rule_text;
+ int rule_line;
+ char *spec;
+ mode_t min_mode;
+ mode_t max_mode;
+ uid_t min_uid;
+ uid_t max_uid;
+ gid_t min_gid;
+ gid_t max_gid;
+ enum perm_rule_type type;
+ struct perm_rule *next;
+};
+
+typedef struct perm_rule perm_rule_t;
+
+static perm_rule_t *rules[NUM_PR_TYPES];
+
+static uid_t str2uid(char *str, int line_num)
+{
+ struct passwd *pw;
+
+ if (isdigit(str[0]))
+ return (uid_t) atol(str);
+
+ if (!(pw = getpwnam(str))) {
+ printf("# ERROR # Invalid uid '%s' reading line %d\n", str, line_num);
+ exit(255);
+ }
+ return pw->pw_uid;
+}
+
+static gid_t str2gid(char *str, int line_num)
+{
+ struct group *gr;
+
+ if (isdigit(str[0]))
+ return (uid_t) atol(str);
+
+ if (!(gr = getgrnam(str))) {
+ printf("# ERROR # Invalid gid '%s' reading line %d\n", str, line_num);
+ exit(255);
+ }
+ return gr->gr_gid;
+}
+
+static int read_rules(FILE *fp)
+{
+ char spec[MAX_NAME_LEN + 5]; // Allows for "/..." suffix + terminator
+ char min_uid_buf[MAX_UID_LEN + 1], max_uid_buf[MAX_UID_LEN + 1];
+ char min_gid_buf[MAX_GID_LEN + 1], max_gid_buf[MAX_GID_LEN + 1];
+ char rule_text_buf[MAX_NAME_LEN + 2*MAX_UID_LEN + 2*MAX_GID_LEN + 9];
+ unsigned long min_mode, max_mode;
+ perm_rule_t *pr;
+ int res;
+ int num_rules = 0, num_lines = 0;
+
+ // Note: Use of an unsafe C function here is OK, since this is a test
+ while ((res = fscanf(fp, "%s %lo %lo %s %s %s %s\n", spec,
+ &min_mode, &max_mode, min_uid_buf, max_uid_buf,
+ min_gid_buf, max_gid_buf)) != EOF) {
+ num_lines++;
+ if (res < 7) {
+ printf("# WARNING # Invalid rule on line number %d\n", num_lines);
+ continue;
+ }
+ if (!(pr = malloc(sizeof(perm_rule_t)))) {
+ printf("Out of memory.\n");
+ exit(255);
+ }
+ if (snprintf(rule_text_buf, sizeof(rule_text_buf),
+ "%s %lo %lo %s %s %s %s", spec, min_mode, max_mode,
+ min_uid_buf, max_uid_buf, min_gid_buf, max_gid_buf)
+ >= (long int) sizeof(rule_text_buf)) {
+ // This should never happen, but just in case...
+ printf("# ERROR # Maximum length limits exceeded on line %d\n",
+ num_lines);
+ exit(255);
+ }
+ pr->rule_text = strndup(rule_text_buf, sizeof(rule_text_buf));
+ pr->rule_line = num_lines;
+ if (strstr(spec, "/...")) {
+ pr->spec = strndup(spec, strlen(spec) - 3);
+ pr->type = RECURSIVE;
+ } else if (spec[strlen(spec) - 1] == '*') {
+ pr->spec = strndup(spec, strlen(spec) - 1);
+ pr->type = WILDCARD;
+ } else if (spec[strlen(spec) - 1] == '/') {
+ pr->spec = strdup(spec);
+ pr->type = EXACT_DIR;
+ } else {
+ pr->spec = strdup(spec);
+ pr->type = EXACT_FILE;
+ }
+ if ((pr->spec == NULL) || (pr->rule_text == NULL)) {
+ printf("Out of memory.\n");
+ exit(255);
+ }
+ pr->min_mode = min_mode;
+ pr->max_mode = max_mode;
+ pr->min_uid = str2uid(min_uid_buf, num_lines);
+ pr->max_uid = str2uid(max_uid_buf, num_lines);
+ pr->min_gid = str2gid(min_gid_buf, num_lines);
+ pr->max_gid = str2gid(max_gid_buf, num_lines);
+
+ // Add the rule to the appropriate set
+ pr->next = rules[pr->type];
+ rules[pr->type] = pr;
+ num_rules++;
+#if 0 // Useful for debugging
+ printf("rule #%d: type = %d spec = %s min_mode = %o max_mode = %o "
+ "min_uid = %d max_uid = %d min_gid = %d max_gid = %d\n",
+ num_rules, pr->type, pr->spec, pr->min_mode, pr->max_mode,
+ pr->min_uid, pr->max_uid, pr->min_gid, pr->max_gid);
+#endif
+ }
+ return num_lines - num_rules;
+}
+
+static void print_failed_rule(const perm_rule_t *pr)
+{
+ printf("# INFO # Failed rule #%d: %s\n", pr->rule_line, pr->rule_text);
+}
+
+static void print_new_rule(const char *name, mode_t mode, uid_t uid, gid_t gid)
+{
+ struct passwd *pw;
+ struct group *gr;
+ gr = getgrgid(gid);
+ pw = getpwuid(uid);
+ printf("%s %4o %4o %s %d %s %d\n", name, mode, mode, pw->pw_name, uid,
+ gr->gr_name, gid);
+}
+
+// Returns 1 if the rule passes, prints the failure and returns 0 if not
+static int pass_rule(const perm_rule_t *pr, mode_t mode, uid_t uid, gid_t gid)
+{
+ if (((pr->min_mode & mode) == pr->min_mode) &&
+ ((pr->max_mode | mode) == pr->max_mode) &&
+ (pr->min_gid <= gid) && (pr->max_gid >= gid) &&
+ (pr->min_uid <= uid) && (pr->max_uid >= uid))
+ return 1;
+ print_failed_rule(pr);
+ return 0;
+}
+
+// Returns 0 on success
+static int validate_file(const char *name, mode_t mode, uid_t uid, gid_t gid)
+{
+ perm_rule_t *pr;
+ int rules_matched = 0;
+ int retval = 0;
+
+ pr = rules[EXACT_FILE];
+ while (pr != NULL) {
+ if (strcmp(name, pr->spec) == 0) {
+ if (!pass_rule(pr, mode, uid, gid))
+ retval++;
+ else
+ rules_matched++; // Exact match found
+ }
+ pr = pr->next;
+ }
+
+ if ((retval + rules_matched) > 1)
+ printf("# WARNING # Multiple exact rules for file: %s\n", name);
+
+ // If any exact rule matched or failed, we are done with this file
+ if (retval)
+ print_new_rule(name, mode, uid, gid);
+ if (rules_matched || retval)
+ return retval;
+
+ pr = rules[WILDCARD];
+ while (pr != NULL) {
+ // Check if the spec is a prefix of the filename, and that the file
+ // is actually in the same directory as the wildcard.
+ if ((strstr(name, pr->spec) == name) &&
+ (!strchr(name + strlen(pr->spec), '/'))) {
+ if (!pass_rule(pr, mode, uid, gid))
+ retval++;
+ else
+ rules_matched++;
+ }
+ pr = pr->next;
+ }
+
+ pr = rules[RECURSIVE];
+ while (pr != NULL) {
+ if (strstr(name, pr->spec) == name) {
+ if (!pass_rule(pr, mode, uid, gid))
+ retval++;
+ else
+ rules_matched++;
+ }
+ pr = pr->next;
+ }
+
+ if (!rules_matched)
+ retval++; // In case no rules either matched or failed, be sure to fail
+
+ if (retval)
+ print_new_rule(name, mode, uid, gid);
+
+ return retval;
+}
+
+// Returns 0 on success
+static int validate_link(const char *name, mode_t mode, uid_t uid, gid_t gid)
+{
+ perm_rule_t *pr;
+ int rules_matched = 0;
+ int retval = 0;
+
+ // For now, we match links against "exact" file rules only
+ pr = rules[EXACT_FILE];
+ while (pr != NULL) {
+ if (strcmp(name, pr->spec) == 0) {
+ if (!pass_rule(pr, mode, uid, gid))
+ retval++;
+ else
+ rules_matched++; // Exact match found
+ }
+ pr = pr->next;
+ }
+
+ if ((retval + rules_matched) > 1)
+ printf("# WARNING # Multiple exact rules for link: %s\n", name);
+ if (retval)
+ print_new_rule(name, mode, uid, gid);
+
+ // Note: Unlike files, if no rules matches for links, retval = 0 (success).
+ return retval;
+}
+
+// Returns 0 on success
+static int validate_dir(const char *name, mode_t mode, uid_t uid, gid_t gid)
+{
+ perm_rule_t *pr;
+ int rules_matched = 0;
+ int retval = 0;
+
+ pr = rules[EXACT_DIR];
+ while (pr != NULL) {
+ if (strcmp(name, pr->spec) == 0) {
+ if (!pass_rule(pr, mode, uid, gid))
+ retval++;
+ else
+ rules_matched++; // Exact match found
+ }
+ pr = pr->next;
+ }
+
+ if ((retval + rules_matched) > 1)
+ printf("# WARNING # Multiple exact rules for directory: %s\n", name);
+
+ // If any exact rule matched or failed, we are done with this directory
+ if (retval)
+ print_new_rule(name, mode, uid, gid);
+ if (rules_matched || retval)
+ return retval;
+
+ pr = rules[RECURSIVE];
+ while (pr != NULL) {
+ if (strstr(name, pr->spec) == name) {
+ if (!pass_rule(pr, mode, uid, gid))
+ retval++;
+ else
+ rules_matched++;
+ }
+ pr = pr->next;
+ }
+
+ if (!rules_matched)
+ retval++; // In case no rules either matched or failed, be sure to fail
+
+ if (retval)
+ print_new_rule(name, mode, uid, gid);
+
+ return retval;
+}
+
+// Returns 0 on success
+static int check_path(const char *name)
+{
+ char namebuf[MAX_NAME_LEN + 1];
+ char tmp[MAX_NAME_LEN + 1];
+ DIR *d;
+ struct dirent *de;
+ struct stat s;
+ int err;
+ int retval = 0;
+
+ err = lstat(name, &s);
+ if (err < 0) {
+ if (errno != ENOENT)
+ {
+ perror(name);
+ return 1;
+ }
+ return 0; // File doesn't exist anymore
+ }
+
+ if (S_ISDIR(s.st_mode)) {
+ if (name[strlen(name) - 1] != '/')
+ snprintf(namebuf, sizeof(namebuf), "%s/", name);
+ else
+ snprintf(namebuf, sizeof(namebuf), "%s", name);
+
+ retval |= validate_dir(namebuf, PERMS(s.st_mode), s.st_uid, s.st_gid);
+ d = opendir(namebuf);
+ if(d == 0) {
+ printf("%s : opendir failed: %s\n", namebuf, strerror(errno));
+ return 1;
+ }
+
+ while ((de = readdir(d)) != 0) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+ continue;
+ snprintf(tmp, sizeof(tmp), "%s%s", namebuf, de->d_name);
+ retval |= check_path(tmp);
+ }
+ closedir(d);
+ return retval;
+ } else if (S_ISLNK(s.st_mode)) {
+ validate_link(name, PERMS(s.st_mode), s.st_uid, s.st_gid);
+ } else {
+ return validate_file(name, PERMS(s.st_mode), s.st_uid, s.st_gid);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ FILE *fp;
+ int i;
+
+ // Initialize ruleset pointers
+ for (i = 0; i < NUM_PR_TYPES; i++)
+ rules[i] = NULL;
+
+ if (!(fp = fopen("/etc/perm_checker.conf", "r"))) {
+ printf("Error opening /etc/perm_checker.conf\n");
+ exit(255);
+ }
+ read_rules(fp);
+ fclose(fp);
+
+ if (check_path("/"))
+ return 255;
+
+ printf("Passed.\n");
+ return 0;
+}
diff --git a/tests/fstest/perm_checker.conf b/tests/fstest/perm_checker.conf
new file mode 100644
index 00000000..460f2e4a
--- /dev/null
+++ b/tests/fstest/perm_checker.conf
@@ -0,0 +1,150 @@
+/ 755 755 root root root root
+/* 400 755 root root root root
+/cache/ 770 770 system system cache cache
+/cache/... 770 770 system system cache cache
+/cache/lost+found/ 700 770 root root root root
+/d/ 755 755 root root root root
+/d/... 000 770 root root root root
+/data/ 771 771 system system system system
+/data/* 000 744 system system system system
+/data/anr/ 000 751 root system log log
+/data/anr/... 000 662 root system log log
+/data/app/ 771 771 system system system system
+/data/app/... 644 664 system system system system
+/data/dalvik-cache/ 750 751 root root root root
+/data/dalvik-cache/... 400 744 root 19999 root 19999
+/data/data 701 771 system system system system
+/data/data/... 000 775 system 19999 system 19999
+/data/testinfo/ 770 771 root system root system
+/data/testinfo/* 000 664 root system root system
+/data/tombstones/ 755 755 system system system system
+/data/tombstones/* 000 600 system 19999 system 19999
+/data/lost+found/ 700 770 root root root root
+/data/misc/ 1711 1771 root system root misc
+/data/misc/akmd_set.txt 600 640 root compass compass compass
+/data/misc/rild* 600 660 root radio root radio
+/data/misc/hcid/ 770 770 bluetooth bluetooth bluetooth bluetooth
+/data/misc/wifi/ 000 1771 system wifi system wifi
+/data/misc/wifi/... 000 770 root wifi root wifi
+/data/local/ 771 771 shell shell shell shell
+/data/local/tmp/ 771 1771 shell shell shell shell
+/data/app_private/ 700 771 system system system system
+/data/system/... 000 770 system system system system
+/dev/ 1777 1777 root root root root
+/dev/alarm 660 660 root system root system
+/dev/ashmem 666 666 root root root root
+/dev/android_adb 600 600 root root root root
+/dev/android_ums 640 640 mount mount mount mount
+/dev/binder 666 666 root root root root
+/dev/console 600 600 root root root root
+/dev/full 666 666 root root root root
+/dev/hw3d 660 660 system system graphics graphics
+/dev/htc-acoustic 600 640 radio radio radio radio
+/dev/network_throughput 600 660 root system root system
+/dev/network_latency 600 660 root system root system
+/dev/cpu_dma_latency 600 660 root system root system
+/dev/mem 600 600 root root root root
+/dev/msm_mp3 600 660 root system root audio
+/dev/msm_pcm_in 660 660 system system audio audio
+/dev/msm_pcm_out 660 660 system system audio audio
+/dev/msm_perf 600 600 root root root root
+/dev/null 666 666 root root root root
+/dev/pmem_adsp 660 660 system system audio audio
+/dev/pmem 660 660 system system graphics graphics
+/dev/ppp 600 600 root root root root
+/dev/psaux 600 600 root root root root
+/dev/ptmx 666 666 root root root root
+/dev/random 666 666 root root root root
+/dev/smd0 640 640 radio radio radio radio
+/dev/ttyMSM0 600 600 bluetooth bluetooth bluetooth bluetooth
+/dev/urandom 666 666 root root root root
+/dev/zero 666 666 root root root root
+/dev/akm* 640 640 compass compass system system
+/dev/km* 600 600 root root root root
+/dev/mt9* 600 660 system system system system
+/dev/pmem_gpu* 660 660 system system graphics graphics
+/dev/qmi* 600 640 radio radio radio radio
+/dev/rtc* 600 600 root root root root
+/dev/smd* 600 600 root root root root
+/dev/tty* 600 600 root root root root
+/dev/vc* 600 600 root root root root
+/dev/adsp/ 750 755 root root root root
+/dev/adsp/* 660 660 system system audio audio
+/dev/block/ 750 775 root root root root
+/dev/block/* 600 600 root root root root
+/dev/graphics/ 755 755 root root root root
+/dev/graphics/* 660 660 root root graphics graphics
+/dev/input/ 755 755 root root root root
+/dev/input/* 660 660 root root input input
+/dev/log/ 755 755 root root root root
+/dev/log/* 662 662 root root log log
+/dev/oncrpc/ 755 755 root root root root
+/dev/oncrpc/... 000 660 root camera root camera
+/dev/pts/ 755 755 root root root root
+/dev/pts/* 600 600 root system root system
+/dev/mtd/ 750 775 root root root root
+/dev/mtd/* 600 600 root root root root
+/dev/socket/ 750 755 root system root system
+/dev/socket/dbus 660 660 root bluetooth bluetooth bluetooth
+/dev/socket/installd 600 660 system system system system
+/dev/socket/mountd 660 660 root mount root mount
+/dev/socket/property_service 666 666 root system root system
+/dev/socket/rild 660 660 root radio radio radio
+/dev/socket/usbd 660 660 root mount mount mount
+/dev/socket/zygote 666 666 root root root root
+/etc 777 777 root root root root
+/proc/ 555 555 root root root root
+/proc/... 000 777 root 19999 root 19999
+/proc/sys/kernel/sched_nr_migrate 000 1664 root root root root
+/root/ 700 700 root root root root
+/sdcard/ 000 077 system system system system
+/sdcard/... 000 077 system system system system
+/sbin/ 700 770 root root root root
+/sbin/... 700 775 root root root root
+/sys/ 755 775 root system root system
+/sys/... 000 775 root system root system
+/sys/android_power/acquire_full_wake_lock 664 664 radio radio system system
+/sys/android_power/acquire_partial_wake_lock 664 664 radio radio system system
+/sys/android_power/release_wake_lock 664 664 radio radio system system
+/sys/android_power/request_state 664 664 radio radio system system
+/sys/android_power/state 664 664 radio radio system system
+/sys/module/board_trout/parameters/bluetooth_power_on 660 660 root bluetooth bluetooth bluetooth
+/sys/qemu_trace/process_name 000 777 root system root system
+/sys/qemu_trace/state 000 777 root system root system
+/sys/qemu_trace/symbol 000 777 root system root system
+/system/ 755 755 root root root root
+/system/* 000 664 root system root system
+/system/app/ 755 755 root root root root
+/system/app/... 600 644 root root root root
+/system/bin/... 000 755 root system root system
+/system/xbin/... 000 755 root system root system
+/system/etc/ 755 755 root root root root
+/system/etc/... 000 664 root system root audio
+/system/etc/firmware/ 700 755 root root root root
+/system/etc/init.goldfish.sh 500 550 root root root root
+/system/etc/init.gprs-pppd 500 550 root root root root
+/system/etc/init.testmenu 500 550 root root root root
+/system/etc/perm_checker.conf 000 777 root system root system
+/system/etc/ppp/ 755 775 root system root system
+/system/etc/ppp/chap-secrets 600 660 root system root system
+/system/etc/ppp/ip-down 500 550 root system root system
+/system/etc/ppp/ip-up 500 550 root system root system
+/system/etc/security/ 755 755 root root root root
+/system/etc/wifi/ 750 755 root system root system
+/system/lib/ 755 755 root root root root
+/system/lib/... 600 644 root root root root
+/system/lib/modules/ 755 755 root root root root
+/system/lost+found/ 700 770 root root root root
+/system/fonts/ 755 755 root root root root
+/system/fonts/... 644 644 root root root root
+/system/framework/ 755 755 root root root root
+/system/framework/... 600 644 root root root root
+/system/media/ 755 755 root root root root
+/system/media/... 644 644 root root root root
+/system/media/audio/ 755 755 root root root root
+/system/media/audio/notifications/ 755 755 root root root root
+/system/media/audio/ringtones/ 755 755 root root root root
+/system/sounds/ 755 755 root root root root
+/system/sounds/... 644 644 root root root root
+/system/usr/... 400 755 root root root root
+/sqlite_stmt_journals 1777 1777 root root root root
diff --git a/tests/icachetest/Android.mk b/tests/icachetest/Android.mk
new file mode 100644
index 00000000..fca07ee1
--- /dev/null
+++ b/tests/icachetest/Android.mk
@@ -0,0 +1,14 @@
+# 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 := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/icachetest/icache.S b/tests/icachetest/icache.S
new file mode 100644
index 00000000..e5a24277
--- /dev/null
+++ b/tests/icachetest/icache.S
@@ -0,0 +1,180 @@
+/*
+ * icache.s
+ *
+ *
+ * Copyright 2005 The Android Open Source Project
+ *
+ */
+
+ .text
+ .global icache_test
+ .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 00000000..5e06dba9
--- /dev/null
+++ b/tests/icachetest/icache2.S
@@ -0,0 +1,170 @@
+/*
+ * icache.s
+ *
+ *
+ * Copyright 2005 The Android Open Source Project
+ *
+ */
+
+ .text
+ .align
+
+ .global icache_test2
+
+#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 00000000..93f36d47
--- /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/memtest/Android.mk b/tests/memtest/Android.mk
new file mode 100644
index 00000000..d0500b23
--- /dev/null
+++ b/tests/memtest/Android.mk
@@ -0,0 +1,20 @@
+# Copyright 2006 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= memtest.cpp.arm \
+ thumb.cpp
+
+
+LOCAL_SHARED_LIBRARIES := libc
+#libutils libhardware
+
+LOCAL_MODULE:= memtest
+
+LOCAL_MODULE_TAGS := tests
+
+## LOCAL_CFLAGS += -fstack-protector-all
+LOCAL_CFLAGS += -fomit-frame-pointer
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/memtest/memtest.cpp b/tests/memtest/memtest.cpp
new file mode 100644
index 00000000..d6cc9b21
--- /dev/null
+++ b/tests/memtest/memtest.cpp
@@ -0,0 +1,763 @@
+/*
+ * 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>
+
+#if 0
+const int DCACHE_SIZE = 8*1024;
+const int CPU_FREQ_EST = 195;
+const int BRANCH_CYCLE = 3;
+#else
+const int DCACHE_SIZE = 32*1024;
+const int CPU_FREQ_EST = 384;
+const int BRANCH_CYCLE = 2;
+#endif
+
+typedef long long nsecs_t;
+
+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;
+}
+
+nsecs_t loop_overhead(size_t count) __attribute__((noinline));
+nsecs_t loop_overhead(size_t count)
+{
+ nsecs_t overhead = -system_time();
+ do {
+ asm volatile ("":::"memory");
+ } while (--count);
+ overhead += system_time();
+ return overhead;
+}
+
+static void preload(volatile char* addr, size_t s)
+{
+ for (size_t i=0 ; i<s ; i+=32) {
+ char c = addr[i];
+ (void)c;
+ }
+}
+
+static void usage(char* p) {
+ printf( "Usage: %s <test> <options>\n"
+ "<test> is one of the following:\n"
+ " cpufreq\n"
+ " memcpy [perf [fast] | test]\n"
+ " memset [perf | test]\n"
+ " memcmp [perf | test]\n"
+ " strlen [perf | test]\n"
+ " malloc [fill]\n"
+ " madvise\n"
+ " resampler\n"
+ " crash\n"
+ " stack (stack smasher)\n"
+ " crawl\n"
+ , p);
+}
+
+int cpufreq_test(int argc, char** argv);
+int memcpy_test(int argc, char** argv);
+int memset_test(int argc, char** argv);
+int memcmp_test(int argc, char** argv);
+int strlen_test(int argc, char** argv);
+int malloc_test(int argc, char** argv);
+int madvise_test(int argc, char** argv);
+int crash_test(int argc, char** argv);
+int stack_smasher_test(int argc, char** argv);
+int crawl_test(int argc, char** argv);
+
+#if 0
+#pragma mark -
+#pragma mark main
+#endif
+
+int main(int argc, char** argv)
+{
+ if (argc == 1) {
+ usage(argv[0]);
+ return 0;
+ }
+ int err = -1;
+ if (!strcmp(argv[1], "cpufreq")) err = cpufreq_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "memcpy")) err = memcpy_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "memset")) err = memset_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "memcmp")) err = memcmp_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "strlen")) err = strlen_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "malloc")) err = malloc_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "madvise")) err = madvise_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "crash")) err = crash_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "stack")) err = stack_smasher_test(argc-1, argv+1);
+ else if (!strcmp(argv[1], "crawl")) err = crawl_test(argc-1, argv+1);
+ if (err) {
+ usage(argv[0]);
+ }
+ return 0;
+}
+
+#if 0
+#pragma mark -
+#pragma mark memcpy
+#endif
+
+int validate_memcpy(char* s, char* d, size_t size);
+int validate_memset(char* s, char c, size_t size);
+
+int memcpy_test(int argc, char** argv)
+{
+ int option = 0;
+ if (argc >= 2) {
+ if (!strcmp(argv[1], "perf")) option = 0;
+ else if (!strcmp(argv[1], "test")) option = 1;
+ else return -1;
+ }
+
+ const int MAX_SIZE = 1024*1024; // 1MB
+ const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 150 MB/s
+ const int UNCACHED_SPEED_EST = (CPU_FREQ_EST/4)*1024*1024; // 60 MB/s
+ char* src = (char*)malloc(MAX_SIZE+4+8+32);
+ char* dst = (char*)malloc(MAX_SIZE+4+8+32);
+ memset(src, 0, MAX_SIZE+4+8+32);
+ memset(dst, 0, MAX_SIZE+4+8+32);
+
+ if (option == 0) {
+ bool fast = (argc>=3 && !strcmp(argv[2], "fast"));
+ printf("memcpy() performance test is running, please wait...\n");
+ fflush(stdout);
+ usleep(10000);
+ setpriority(PRIO_PROCESS, 0, -20);
+ static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE };
+
+ struct result_t { int size; float res; };
+ result_t* results = (result_t*)src;
+ int nbr = 0;
+ int size = 0;
+ for (int i=0 ; ; i++) {
+ if (!fast) {
+ if (size<128) size += 8;
+ else if (size<1024) size += 128;
+ else if (size<16384) size += 1024;
+ else size <<= 1;
+ } else {
+ if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]))
+ break;
+ size = FAST_SIZES[i];
+ }
+ if (size > MAX_SIZE) {
+ break;
+ }
+
+ const int REPEAT = (((size < DCACHE_SIZE) ?
+ (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size) / 2;
+ // ~0.5 second per test
+
+ const nsecs_t overhead = loop_overhead(REPEAT);
+
+ // tweak to make it a bad case
+ char* ddd = (char*)((long(dst+31)&~31) + 4);
+ char* sss = (char*)((long(src+31)&~31) + 28);
+
+ for (int offset=0 ; offset<=2 ; offset +=2 ) {
+ memcpy(dst, src, size); // just make sure to load the caches I/D
+ nsecs_t t = -system_time();
+ register int count = REPEAT;
+ do {
+ memcpy(ddd, sss+offset, size);
+ } while (--count);
+ t += system_time() - overhead;
+ const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t);
+ results[nbr].size = size;
+ results[nbr].res = throughput;
+ nbr++;
+ }
+ }
+
+ printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (nc)");
+ for (int i=0 ; i<nbr ; i+=2) {
+ printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res);
+ }
+ } else if (option == 1) {
+ printf("memcpy() validation test is running, please wait...\n");
+ fflush(stdout);
+ char* curr = (char*)src;
+ for (int i=0 ; i<MAX_SIZE ; i++) {
+ char c = rand();
+ *curr++ = c != 0x55 ? c : 0xAA;
+ }
+ char* s = src + 1024;
+ char* d = dst + 1024;
+ int nb = 0;
+ for (int size=0 ; size<4096 && !nb ; size++) {
+ nb += validate_memcpy(s, d, size);
+ for (int o=1 ; o<32 && !nb ; o++) {
+ nb += validate_memcpy(s+o, d, size);
+ nb += validate_memcpy(s, d+o, size);
+ nb += validate_memcpy(s+o, d+o, size);
+ }
+ }
+ if (nb) printf("%d error(s) found\n", nb);
+ else printf("success!\n");
+ }
+ fflush(stdout);
+ free(dst);
+ free(src);
+ return 0;
+}
+
+int validate_memcpy(char* s, char* d, size_t size)
+{
+ int nberr = 0;
+ memset(d-4, 0x55, size+8);
+ memcpy(s, d, size);
+ if (memcmp(s,d,size)) {
+ printf("*** memcpy(%p,%p,%lu) destination != source\n",s,d,size);
+ nberr++;
+ }
+ bool r = (d[size]==0x55)&&(d[size+1]==0x55)&&(d[size+2]==0x55)&&(d[size+3]==0x55);
+ if (!r) {
+ printf("*** memcpy(%p,%p,%lu) clobbered past end of destination!\n",s,d,size);
+ nberr++;
+ }
+ r = (d[-1]==0x55)&&(d[-2]==0x55)&&(d[-3]==0x55)&&(d[-4]==0x55);
+ if (!r) {
+ printf("*** memcpy(%p,%p,%lu) clobbered before start of destination!\n",s,d,size);
+ nberr++;
+ }
+ return nberr;
+}
+
+
+#if 0
+#pragma mark -
+#pragma mark memset
+#endif
+
+int memset_test(int argc, char** argv)
+{
+ int option = 0;
+ if (argc >= 2) {
+ if (!strcmp(argv[1], "perf")) option = 0;
+ else if (!strcmp(argv[1], "test")) option = 1;
+ else return -1;
+ }
+
+ const int MAX_SIZE = 1024*1024; // 1MB
+ const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s
+ const int UNCACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s
+ char* dst = (char*)malloc(MAX_SIZE+4+8);
+
+ if (option == 0) {
+ printf("memset() performance test is running, please wait...\n");
+ fflush(stdout);
+ usleep(10000);
+ setpriority(PRIO_PROCESS, 0, -20);
+
+ static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE };
+ const size_t FAST_SIZES_COUNT = sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]);
+ struct result_t { int size; float res; };
+ result_t results[FAST_SIZES_COUNT*2];
+ int nbr = 0;
+ int size = 0;
+ for (int i=0 ; ; i++) {
+ if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]))
+ break;
+ size = FAST_SIZES[i];
+ if (size > MAX_SIZE) {
+ break;
+ }
+ const int REPEAT = (((size < DCACHE_SIZE) ?
+ (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size);
+ // ~0.5 second per test
+
+ const nsecs_t overhead = loop_overhead(REPEAT);
+
+ for (int j=0 ; j<2 ; j++) {
+ if (j==0) preload(dst, DCACHE_SIZE*4); // flush D
+ else preload(dst, size); // load D
+ nsecs_t t = -system_time();
+ size_t count = REPEAT;
+ do {
+ memset(dst, 0, size);
+ } while (--count);
+ t += system_time() - overhead;
+
+ const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t);
+ results[nbr].size = size;
+ results[nbr].res = throughput;
+ nbr++;
+ }
+ }
+
+ printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (cached)");
+ for (int i=0 ; i<nbr ; i+=2) {
+ printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res);
+ }
+ } else if (option == 1) {
+ printf("memset() validation test is running, please wait...\n");
+ fflush(stdout);
+ char* d = dst + 1024;
+ int nb = 0;
+ for (int o=1 ; o<32 ; o++) {
+ for (int size=0 ; size<4096 && !nb ; size++) {
+ nb += validate_memset(d, char(o), size);
+ nb += validate_memset(d+o, char(o), size);
+ }
+ }
+ if (nb) printf("%d error(s) found\n", nb);
+ else printf("success!\n");
+ }
+ fflush(stdout);
+ free(dst);
+ return 0;
+}
+
+int validate_memset(char* d, char c, size_t size)
+{
+ int nberr = 0;
+ for (size_t i=0; i<size ; d[i++]=0xaa) ;
+ d[-1] = 0x55;
+ d[size+1] = 0x55;
+ memset(d, c, size);
+ if (d[size+1]!=0x55) {
+ printf("*** memset(%p,%02x,%lu) clobbered past end of destination!\n",d,(int)c,size);
+ nberr++;
+ }
+ if (d[-1]!=0x55) {
+ printf("*** memset(%p,%02x,%lu) clobbered before start of destination!\n",d,(int)c,size);
+ nberr++;
+ }
+ for (size_t i=0 ; i<size ; i++) {
+ if (d[i] != c) {
+ printf("*** memset(%p,%02x,%lu) failed at offset %lu\n",d,(int)c,size, i);
+ nberr++;
+ break;
+ }
+ }
+ return nberr;
+}
+
+#if 0
+#pragma mark -
+#pragma mark memcmp
+#endif
+
+static int ref_memcmp(const void *s1, const void *s2, size_t n)
+{
+ const unsigned char *c1 = (const unsigned char *)s1, *c2 = (const unsigned char *)s2;
+ int d = 0;
+
+ while ( n-- ) {
+ d = (int)*c1++ - (int)*c2++;
+ if ( d )
+ break;
+ }
+
+ return d;
+}
+
+int validate_memcmp(const char* s, const char* d, size_t size)
+{
+
+ int a = ref_memcmp(s, d, size);
+ int b = memcmp(s, d, size);
+ //printf("%d, %d\n", a, b);
+ if (a != b) {
+ printf("*** memcmp(%p,%p,%lu) failed %d should be %d\n",s,d,size,b,a);
+ return 1;
+ }
+ return 0;
+}
+
+int memcmp_test(int argc, char** argv)
+{
+ int option = 0;
+ if (argc >= 2) {
+ if (!strcmp(argv[1], "perf")) option = 0;
+ else if (!strcmp(argv[1], "test")) option = 1;
+ else return -1;
+ }
+
+ const int MAX_SIZE = 1024*1024; // 1MB
+ const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 150 MB/s
+ const int UNCACHED_SPEED_EST = (CPU_FREQ_EST/4)*1024*1024; // 60 MB/s
+ char* src = (char*)malloc(MAX_SIZE+4+8+32);
+ char* dst = (char*)malloc(MAX_SIZE+4+8+32);
+
+ if (option == 0) {
+ printf("memcmp() performance test is running, please wait...\n");
+ fflush(stdout);
+ usleep(10000);
+ setpriority(PRIO_PROCESS, 0, -20);
+
+ static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE };
+
+ struct result_t { int size; float res; };
+ result_t* results = (result_t*)src;
+ int nbr = 0;
+ int size = 0;
+ for (int i=0 ; ; i++) {
+ if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]))
+ break;
+ size = FAST_SIZES[i];
+ if (size > MAX_SIZE) {
+ break;
+ }
+
+ const int REPEAT = (((size < DCACHE_SIZE) ?
+ (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size) / 2;
+ // ~0.5 second per test
+
+ const nsecs_t overhead = loop_overhead(REPEAT);
+
+ // tweak to make it a bad case
+ char* ddd = (char*)((long(dst+31)&~31) + 4);
+ char* sss = (char*)((long(src+31)&~31) + 28);
+
+ for (int offset=0 ; offset<=2 ; offset +=2 ) {
+ memcpy(ddd, sss+offset, size); // just make sure to load the caches I/D
+ nsecs_t t = -system_time();
+ register int count = REPEAT;
+ char c;
+ c = memcmp(ddd, sss+offset, size);
+ //printf("size %d, memcmp -> %d\n", size, (int)c);
+ do {
+ c = memcmp(ddd, sss+offset, size);
+ asm volatile (""::"r"(c):"memory");
+ } while (--count);
+ t += system_time() - overhead;
+ const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t);
+ results[nbr].size = size;
+ results[nbr].res = throughput;
+ nbr++;
+ }
+ }
+
+ printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (nc)");
+ for (int i=0 ; i<nbr ; i+=2) {
+ printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res);
+ }
+ } else {
+ printf("memcmp() validation test is running, please wait...\n");
+ fflush(stdout);
+
+ const char* const s = (const char*)src + 1024;
+ const char* const d = (const char*)dst + 1024;
+ int nb = 0;
+ for (int j=0 ; j<32 ; j++) {
+
+ char *curr0 = (char*)src;
+ char *curr1 = (char*)dst;
+ for (int i=0 ; i<MAX_SIZE ; i++) {
+ char c = rand();
+ *curr0++ = c;
+ *curr1++ = c;
+ }
+ if (j) {
+ src[1024 + j] ^= 0xFF;
+ }
+
+
+ for (int size=0 ; size<32 && !nb ; size++) {
+ for (int o=0 ; o<4 ; o++) {
+ nb += validate_memcmp(s+o, d+o, size);
+ }
+ // memmove((char*)d+1, d, size);
+ for (int o=0 ; o<4 ; o++) {
+ nb += validate_memcmp(s, d+o, size);
+ }
+ }
+ }
+ if (nb) printf("%d error(s) found\n", nb);
+ else printf("success!\n");
+ }
+ fflush(stdout);
+ free(dst);
+ free(src);
+ return 0;
+}
+
+#if 0
+#pragma mark -
+#pragma mark strlen
+#endif
+
+int strlen_test(int argc, char** argv)
+{
+ int option = 0;
+ if (argc >= 2) {
+ if (!strcmp(argv[1], "perf")) option = 0;
+ else if (!strcmp(argv[1], "test")) option = 1;
+ else return -1;
+ }
+
+ const int MAX_SIZE = 1024*1024; // 1MB
+ const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s
+ const int UNCACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s
+ char* str = (char*)calloc(MAX_SIZE+4+8, 1);
+
+ if (option == 0) {
+ printf("strlen() performance test is running, please wait...\n");
+ fflush(stdout);
+ usleep(10000);
+ setpriority(PRIO_PROCESS, 0, -20);
+
+ static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE };
+ const size_t FAST_SIZES_COUNT = sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]);
+ struct result_t { int size; float res; };
+ result_t results[FAST_SIZES_COUNT*2];
+ int nbr = 0;
+ int size = 0;
+ for (int i=0 ; ; i++) {
+ if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]))
+ break;
+ size = FAST_SIZES[i];
+ if (size > MAX_SIZE) {
+ break;
+ }
+ const int REPEAT = (((size < DCACHE_SIZE) ?
+ (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size);
+ // ~0.5 second per test
+
+ const nsecs_t overhead = loop_overhead(REPEAT);
+
+ for (int j=0 ; j<2 ; j++) {
+ memset(str, 'A', size-1);
+ if (j==0) preload(str, DCACHE_SIZE*4); // flush D
+ else preload(str, size); // load D
+
+ nsecs_t t = -system_time();
+ size_t count = REPEAT;
+ int c=0;
+ do {
+ c = strlen(str);
+ asm volatile (""::"r"(c):"memory");
+ } while (--count);
+ t += system_time() - overhead;
+
+ const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t);
+ results[nbr].size = size;
+ results[nbr].res = throughput;
+ nbr++;
+ }
+ }
+
+ printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (cached)");
+ for (int i=0 ; i<nbr ; i+=2) {
+ printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res);
+ }
+ }
+
+ fflush(stdout);
+ free(str);
+ return 0;
+}
+
+
+#if 0
+#pragma mark -
+#pragma mark malloc
+#endif
+
+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 = %9lu failed\n", size);
+ size >>= 1;
+ } else {
+ total += size;
+ printf("size = %9lu, addr = %p (total = %9lu (%lu 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 %lu MB\n", total / (1024*1024));
+ return 0;
+}
+
+#if 0
+#pragma mark -
+#pragma mark madvise
+#endif
+
+int madvise_test(int argc, char** argv)
+{
+ for (int i=0 ; i<2 ; i++) {
+ size_t size = i==0 ? 4096 : 48*1024*1024; // 48 MB
+ printf("Allocating %lu 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 %lu 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;
+}
+
+#if 0
+#pragma mark -
+#pragma mark cpufreq
+#endif
+
+int cpufreq_test(int argc, char** argv)
+{
+ struct timespec res;
+ clock_getres(CLOCK_REALTIME, &res);
+ printf("CLOCK_REALTIME resolution: %lu ns\n", res.tv_nsec);
+ clock_getres(CLOCK_MONOTONIC, &res);
+ printf("CLOCK_MONOTONIC resolution: %lu ns\n", res.tv_nsec);
+ clock_getres(CLOCK_PROCESS_CPUTIME_ID, &res);
+ printf("CLOCK_PROCESS_CPUTIME_ID resolution: %lu ns\n", res.tv_nsec);
+ clock_getres(CLOCK_THREAD_CPUTIME_ID, &res);
+ printf("CLOCK_THREAD_CPUTIME_ID resolution: %lu ns\n", res.tv_nsec);
+
+ if (clock_getres(CLOCK_REALTIME_HR, &res) != 0)
+ printf("CLOCK_REALTIME_HR resolution: %lu ns\n", res.tv_nsec);
+ else
+ printf("CLOCK_REALTIME_HR not supported\n");
+
+ if (clock_getres(CLOCK_MONOTONIC_HR, &res) != 0)
+ printf("CLOCK_MONOTONIC_HR resolution: %lu ns\n", res.tv_nsec);
+ else
+ printf("CLOCK_MONOTONIC_HR not supported\n");
+
+ printf("\nEstimating the CPU frequency, please wait...\n");
+ fflush(stdout);
+ usleep(10000);
+ setpriority(PRIO_PROCESS, 0, -20);
+
+ const int LOOP_CYCLES = 1+BRANCH_CYCLE; // 1 cycle + 3 cycles for the branch
+ const size_t REPEAT = CPU_FREQ_EST*1000000; // ~4 seconds (4cycles/loop)
+ register size_t count = REPEAT;
+ nsecs_t t = system_time();
+ do { // this loop generates 1+3 cycles
+ asm volatile ("":::"memory");
+ } while (--count);
+ t = system_time() - t;
+ const float freq = t ? (1000.0f*float(REPEAT)*LOOP_CYCLES) / t : 0;
+ printf("this CPU frequency: %ld MHz\n", long(freq+0.5f));
+ return 0;
+}
+
+#if 0
+#pragma mark -
+#pragma mark crash_test
+#endif
+
+int crash_test(int argc, char** argv)
+{
+ printf("about to crash...\n");
+ asm volatile(
+ "mov r0, #0 \n"
+ "mov r1, #1 \n"
+ "mov r2, #2 \n"
+ "mov r3, #3 \n"
+ "ldr r12, [r0] \n"
+ );
+
+ return 0;
+}
+
+int stack_smasher_test(int argc, char** argv)
+{
+ 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*p) {
+ int a = 0;
+ thumb_function_2(&a);
+}
+
+void arm_function_2(int*p) {
+ int a = 0;
+ thumb_function_1(&a);
+}
+
+void arm_function_1(int*p) {
+ int a = 0;
+ arm_function_2(&a);
+}
+
+int crawl_test(int argc, char** argv)
+{
+ int a = 0;
+ arm_function_1(&a);
+ return 0;
+}
+
diff --git a/tests/memtest/thumb.cpp b/tests/memtest/thumb.cpp
new file mode 100644
index 00000000..a70f4c3b
--- /dev/null
+++ b/tests/memtest/thumb.cpp
@@ -0,0 +1,27 @@
+#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 *arg)
+{
+ int i = 0;
+ printf("0x%x\n", _Unwind_GetIP(context));
+ fflush(stdout);
+ return _URC_NO_REASON;
+}
+
+void thumb_function_1(int*p)
+{
+ int a = 0;
+ arm_function_3(&a);
+}
+
+void thumb_function_2(int*p)
+{
+ int a = 0;
+ printf("unwinding...\n");
+ _Unwind_Backtrace(trace_function, (void*)"backtrace!");
+}
diff --git a/timeinfo/Android.mk b/timeinfo/Android.mk
new file mode 100644
index 00000000..16374155
--- /dev/null
+++ b/timeinfo/Android.mk
@@ -0,0 +1,24 @@
+# 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 := timeinfo
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := tests eng
+LOCAL_SRC_FILES := timeinfo.cpp
+LOCAL_SHARED_LIBRARIES := libhardware
+include $(BUILD_EXECUTABLE)
diff --git a/timeinfo/timeinfo.cpp b/timeinfo/timeinfo.cpp
new file mode 100644
index 00000000..b1af7ced
--- /dev/null
+++ b/timeinfo/timeinfo.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+/* Report realtime, uptime, awake percentage, and sleep percentage to stdout.
+ * Primarily called by powerdroid test harness.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "utils/SystemClock.h"
+
+
+int main(int argc, char *argv[])
+{
+
+ int64_t realtime, uptime;
+ int64_t awaketime, sleeptime;
+
+ uptime = android::uptimeMillis();
+ realtime = android::elapsedRealtime();
+
+ if (realtime == 0) {
+ realtime = 1;
+ }
+
+ awaketime = ((1000 * uptime / realtime) + 5) / 10;
+ sleeptime = ((1000 * (realtime - uptime) / realtime) + 5) / 10;
+
+ printf("%jd %jd %jd %jd\n", (intmax_t) realtime, (intmax_t) uptime,
+ (intmax_t) awaketime, (intmax_t) sleeptime);
+
+}
+
+
+/* vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab */