OSDN Git Service

Initial Contribution
authorThe Android Open Source Project <initial-contribution@android.com>
Tue, 21 Oct 2008 14:00:00 +0000 (07:00 -0700)
committerThe Android Open Source Project <initial-contribution@android.com>
Tue, 21 Oct 2008 14:00:00 +0000 (07:00 -0700)
56 files changed:
Android.mk [new file with mode: 0644]
latencytop/Android.mk [new file with mode: 0644]
latencytop/MODULE_LICENSE_APACHE2 [new file with mode: 0644]
latencytop/NOTICE [new file with mode: 0644]
latencytop/latencytop.c [new file with mode: 0644]
libpagemap/Android.mk [new file with mode: 0644]
libpagemap/MODULE_LICENSE_APACHE2 [new file with mode: 0644]
libpagemap/NOTICE [new file with mode: 0644]
libpagemap/include/pagemap/pagemap.h [new file with mode: 0644]
libpagemap/pm_kernel.c [new file with mode: 0644]
libpagemap/pm_map.c [new file with mode: 0644]
libpagemap/pm_map.h [new file with mode: 0644]
libpagemap/pm_memusage.c [new file with mode: 0644]
libpagemap/pm_process.c [new file with mode: 0644]
librank/Android.mk [new file with mode: 0644]
librank/MODULE_LICENSE_APACHE2 [new file with mode: 0644]
librank/NOTICE [new file with mode: 0644]
librank/librank.c [new file with mode: 0644]
procmem/Android.mk [new file with mode: 0644]
procmem/MODULE_LICENSE_APACHE2 [new file with mode: 0644]
procmem/NOTICE [new file with mode: 0644]
procmem/procmem.c [new file with mode: 0644]
procrank/Android.mk [new file with mode: 0644]
procrank/MODULE_LICENSE_APACHE2 [new file with mode: 0644]
procrank/NOTICE [new file with mode: 0644]
procrank/procrank.c [new file with mode: 0644]
showmap/Android.mk [new file with mode: 0644]
showmap/MODULE_LICENSE_APACHE2 [new file with mode: 0644]
showmap/NOTICE [new file with mode: 0644]
showmap/showmap.c [new file with mode: 0644]
showslab/Android.mk [new file with mode: 0644]
showslab/MODULE_LICENSE_APACHE2 [new file with mode: 0644]
showslab/NOTICE [new file with mode: 0644]
showslab/showslab.c [new file with mode: 0644]
sound/Android.mk [new file with mode: 0644]
sound/playwav.c [new file with mode: 0644]
su/Android.mk [new file with mode: 0644]
su/MODULE_LICENSE_APACHE2 [new file with mode: 0644]
su/NOTICE [new file with mode: 0644]
su/su.c [new file with mode: 0644]
tests/Android.mk [new file with mode: 0644]
tests/cpueater/Android.mk [new file with mode: 0644]
tests/cpueater/cpueater.c [new file with mode: 0644]
tests/fstest/Android.mk [new file with mode: 0644]
tests/fstest/README [new file with mode: 0644]
tests/fstest/perm_checker.c [new file with mode: 0644]
tests/fstest/perm_checker.conf [new file with mode: 0644]
tests/icachetest/Android.mk [new file with mode: 0644]
tests/icachetest/icache.S [new file with mode: 0644]
tests/icachetest/icache2.S [new file with mode: 0644]
tests/icachetest/icache_main.c [new file with mode: 0644]
tests/memtest/Android.mk [new file with mode: 0644]
tests/memtest/memtest.cpp [new file with mode: 0644]
tests/memtest/thumb.cpp [new file with mode: 0644]
timeinfo/Android.mk [new file with mode: 0644]
timeinfo/timeinfo.cpp [new file with mode: 0644]

diff --git a/Android.mk b/Android.mk
new file mode 100644 (file)
index 0000000..63185fa
--- /dev/null
@@ -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 (file)
index 0000000..84bef41
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/latencytop/NOTICE b/latencytop/NOTICE
new file mode 100644 (file)
index 0000000..c5b1efa
--- /dev/null
@@ -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 (file)
index 0000000..78d7c71
--- /dev/null
@@ -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 (file)
index 0000000..b38363c
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/libpagemap/NOTICE b/libpagemap/NOTICE
new file mode 100644 (file)
index 0000000..c5b1efa
--- /dev/null
@@ -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 (file)
index 0000000..09ff29d
--- /dev/null
@@ -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 (file)
index 0000000..3615f1a
--- /dev/null
@@ -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 (file)
index 0000000..f683ba6
--- /dev/null
@@ -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 (file)
index 0000000..08dc448
--- /dev/null
@@ -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 (file)
index 0000000..9c5db92
--- /dev/null
@@ -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 (file)
index 0000000..1ab367d
--- /dev/null
@@ -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 (file)
index 0000000..300b3f5
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/librank/NOTICE b/librank/NOTICE
new file mode 100644 (file)
index 0000000..c5b1efa
--- /dev/null
@@ -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 (file)
index 0000000..13b2097
--- /dev/null
@@ -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 (file)
index 0000000..ffd5660
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/procmem/NOTICE b/procmem/NOTICE
new file mode 100644 (file)
index 0000000..c5b1efa
--- /dev/null
@@ -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 (file)
index 0000000..03c9f51
--- /dev/null
@@ -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 (file)
index 0000000..eb48710
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/procrank/NOTICE b/procrank/NOTICE
new file mode 100644 (file)
index 0000000..c5b1efa
--- /dev/null
@@ -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 (file)
index 0000000..585fddc
--- /dev/null
@@ -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 (file)
index 0000000..5c90f12
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/showmap/NOTICE b/showmap/NOTICE
new file mode 100644 (file)
index 0000000..c5b1efa
--- /dev/null
@@ -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 (file)
index 0000000..e8c7dd5
--- /dev/null
@@ -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 (file)
index 0000000..c914a8b
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/showslab/NOTICE b/showslab/NOTICE
new file mode 100644 (file)
index 0000000..c5b1efa
--- /dev/null
@@ -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 (file)
index 0000000..9c9e60e
--- /dev/null
@@ -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 (file)
index 0000000..7a58998
--- /dev/null
@@ -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 (file)
index 0000000..6d6bce7
--- /dev/null
@@ -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 (file)
index 0000000..dd412d5
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/su/NOTICE b/su/NOTICE
new file mode 100644 (file)
index 0000000..c5b1efa
--- /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 (file)
index 0000000..aac981e
--- /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 (file)
index 0000000..582ddc9
--- /dev/null
@@ -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 (file)
index 0000000..88e3cd8
--- /dev/null
@@ -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 (file)
index 0000000..b7d69ff
--- /dev/null
@@ -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 (file)
index 0000000..bf4f17c
--- /dev/null
@@ -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 (file)
index 0000000..e4f8194
--- /dev/null
@@ -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 (file)
index 0000000..5cead10
--- /dev/null
@@ -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 (file)
index 0000000..460f2e4
--- /dev/null
@@ -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 (file)
index 0000000..fca07ee
--- /dev/null
@@ -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 (file)
index 0000000..e5a2427
--- /dev/null
@@ -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 (file)
index 0000000..5e06dba
--- /dev/null
@@ -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 (file)
index 0000000..93f36d4
--- /dev/null
@@ -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 (file)
index 0000000..d0500b2
--- /dev/null
@@ -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 (file)
index 0000000..d6cc9b2
--- /dev/null
@@ -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 (file)
index 0000000..a70f4c3
--- /dev/null
@@ -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 (file)
index 0000000..1637415
--- /dev/null
@@ -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 (file)
index 0000000..b1af7ce
--- /dev/null
@@ -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 */