diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 7341494707810f709855ea85ce03a8ec3ac8dbaf (patch) | |
tree | 3bfd77f6c3acddfd222b1b0f4cf1a3452bcc1863 | |
download | extras-7341494707810f709855ea85ce03a8ec3ac8dbaf.tar.gz |
Initial Contributionandroid-1.0release-1.0cdma-import
56 files changed, 6946 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk new file mode 100644 index 00000000..63185fac --- /dev/null +++ b/Android.mk @@ -0,0 +1,19 @@ +# +# Copyright (C) 2008 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +ifneq ($(TARGET_SIMULATOR),true) + include $(all-subdir-makefiles) +endif diff --git a/latencytop/Android.mk b/latencytop/Android.mk new file mode 100644 index 00000000..84bef410 --- /dev/null +++ b/latencytop/Android.mk @@ -0,0 +1,26 @@ +# Copyright (C) 2008 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := latencytop.c + +LOCAL_MODULE := latencytop + +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) + +LOCAL_MODULE_TAGS := debug tests + +include $(BUILD_EXECUTABLE) diff --git a/latencytop/MODULE_LICENSE_APACHE2 b/latencytop/MODULE_LICENSE_APACHE2 new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/latencytop/MODULE_LICENSE_APACHE2 diff --git a/latencytop/NOTICE b/latencytop/NOTICE new file mode 100644 index 00000000..c5b1efa7 --- /dev/null +++ b/latencytop/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/latencytop/latencytop.c b/latencytop/latencytop.c new file mode 100644 index 00000000..78d7c71d --- /dev/null +++ b/latencytop/latencytop.c @@ -0,0 +1,442 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#define MAX_LINE 512 +#define MAX_FILENAME 64 + +const char *EXPECTED_VERSION = "Latency Top version : v0.1\n"; +const char *SYSCTL_FILE = "/proc/sys/kernel/latencytop"; +const char *GLOBAL_STATS_FILE = "/proc/latency_stats"; +const char *THREAD_STATS_FILE_FORMAT = "/proc/%d/task/%d/latency"; + +struct latency_entry { + struct latency_entry *next; + unsigned long count; + unsigned long max; + unsigned long total; + char reason[MAX_LINE]; +}; + +static inline void check_latencytop() { } + +static struct latency_entry *read_global_stats(struct latency_entry *list, int erase); +static struct latency_entry *read_process_stats(struct latency_entry *list, int erase, int pid); +static struct latency_entry *read_thread_stats(struct latency_entry *list, int erase, int pid, int tid, int fatal); + +static struct latency_entry *alloc_latency_entry(void); +static void free_latency_entry(struct latency_entry *e); + +static void set_latencytop(int on); +static struct latency_entry *read_latency_file(FILE *f, struct latency_entry *list); +static void erase_latency_file(FILE *f); + +static struct latency_entry *find_latency_entry(struct latency_entry *e, char *reason); +static void print_latency_entries(struct latency_entry *head); + +static void signal_handler(int sig); +static void disable_latencytop(void); + +static int numcmp(const long long a, const long long b); +static int lat_cmp(const void *a, const void *b); + +static void clear_screen(void); +static void usage(const char *cmd); + +struct latency_entry *free_entries; + +int main(int argc, char *argv[]) { + struct latency_entry *e; + int delay, iterations; + int pid, tid; + int count, erase; + int i; + + delay = 1; + iterations = 0; + pid = tid = 0; + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-d")) { + if (i >= argc - 1) { + fprintf(stderr, "Option -d expects an argument.\n"); + exit(EXIT_FAILURE); + } + delay = atoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "-n")) { + if (i >= argc - 1) { + fprintf(stderr, "Option -n expects an argument.\n"); + exit(EXIT_FAILURE); + } + iterations = atoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "-h")) { + usage(argv[0]); + exit(EXIT_SUCCESS); + } + if (!strcmp(argv[i], "-p")) { + if (i >= argc - 1) { + fprintf(stderr, "Option -p expects an argument.\n"); + exit(EXIT_FAILURE); + } + pid = atoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "-t")) { + if (i >= argc - 1) { + fprintf(stderr, "Option -t expects an argument.\n"); + exit(EXIT_FAILURE); + } + tid = atoi(argv[++i]); + continue; + } + fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + if (tid && !pid) { + fprintf(stderr, "If you provide a thread ID with -t, you must provide a process ID with -p.\n"); + exit(EXIT_FAILURE); + } + + check_latencytop(); + + free_entries = NULL; + + signal(SIGINT, &signal_handler); + signal(SIGTERM, &signal_handler); + + atexit(&disable_latencytop); + + set_latencytop(1); + + count = 0; + erase = 1; + + while ((iterations == 0) || (count++ < iterations)) { + + sleep(delay); + + e = NULL; + if (pid) { + if (tid) { + e = read_thread_stats(e, erase, pid, tid, 1); + } else { + e = read_process_stats(e, erase, pid); + } + } else { + e = read_global_stats(e, erase); + } + erase = 0; + + clear_screen(); + if (pid) { + if (tid) { + printf("Latencies for thread %d in process %d:\n", tid, pid); + } else { + printf("Latencies for process %d:\n", pid); + } + } else { + printf("Latencies across all processes:\n"); + } + print_latency_entries(e); + } + + set_latencytop(0); + + return 0; +} + +static struct latency_entry *read_global_stats(struct latency_entry *list, int erase) { + FILE *f; + struct latency_entry *e; + + if (erase) { + f = fopen(GLOBAL_STATS_FILE, "w"); + if (!f) { + fprintf(stderr, "Could not open global latency stats file: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + fprintf(f, "erase\n"); + fclose(f); + } + + f = fopen(GLOBAL_STATS_FILE, "r"); + if (!f) { + fprintf(stderr, "Could not open global latency stats file: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + e = read_latency_file(f, list); + + fclose(f); + + return e; +} + +static struct latency_entry *read_process_stats(struct latency_entry *list, int erase, int pid) { + char dirname[MAX_FILENAME]; + DIR *dir; + struct dirent *ent; + struct latency_entry *e; + int tid; + + sprintf(dirname, "/proc/%d/task", pid); + dir = opendir(dirname); + if (!dir) { + fprintf(stderr, "Could not open task dir for process %d.\n", pid); + fprintf(stderr, "Perhaps the process has terminated?\n"); + exit(EXIT_FAILURE); + } + + e = list; + while ((ent = readdir(dir))) { + if (!isdigit(ent->d_name[0])) + continue; + + tid = atoi(ent->d_name); + + e = read_thread_stats(e, erase, pid, tid, 0); + } + + closedir(dir); + + return e; +} + +static struct latency_entry *read_thread_stats(struct latency_entry *list, int erase, int pid, int tid, int fatal) { + char filename[MAX_FILENAME]; + FILE *f; + struct latency_entry *e; + + sprintf(filename, THREAD_STATS_FILE_FORMAT, pid, tid); + + if (erase) { + f = fopen(filename, "w"); + if (!f) { + if (fatal) { + fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno)); + fprintf(stderr, "Perhaps the process or thread has terminated?\n"); + exit(EXIT_FAILURE); + } else { + return list; + } + } + fprintf(f, "erase\n"); + fclose(f); + } + + f = fopen(GLOBAL_STATS_FILE, "r"); + if (!f) { + if (fatal) { + fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno)); + fprintf(stderr, "Perhaps the process or thread has terminated?\n"); + exit(EXIT_FAILURE); + } else { + return list; + } + } + + e = read_latency_file(f, list); + + fclose(f); + + return e; +} + +static struct latency_entry *alloc_latency_entry(void) { + struct latency_entry *e; + + if (free_entries) { + e = free_entries; + free_entries = free_entries->next; + } else { + e = calloc(1, sizeof(struct latency_entry)); + if (!e) { + fprintf(stderr, "Could not allocate latency entry: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + } + + return e; +} + +static void free_latency_entry(struct latency_entry *e) { + e->next = free_entries; + free_entries = e; +} + +static struct latency_entry *find_latency_entry(struct latency_entry *head, char *reason) { + struct latency_entry *e; + + e = head; + + while (e) { + if (!strcmp(e->reason, reason)) + return e; + e = e->next; + } + + return NULL; +} + +static void set_latencytop(int on) { + FILE *f; + + f = fopen(SYSCTL_FILE, "w"); + if (!f) { + fprintf(stderr, "Could not open %s: %s\n", SYSCTL_FILE, strerror(errno)); + exit(EXIT_FAILURE); + } + + fprintf(f, "%d\n", on); + + fclose(f); +} + +static void erase_latency_file(FILE *f) { + fprintf(f, "erase\n"); +} + +static struct latency_entry *read_latency_file(FILE *f, struct latency_entry *list) { + struct latency_entry *e, *head; + char line[MAX_LINE]; + unsigned long count, max, total; + char reason[MAX_LINE]; + + head = list; + + if (!fgets(line, MAX_LINE, f)) { + fprintf(stderr, "Could not read latency file version: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + if (strcmp(line, EXPECTED_VERSION) != 0) { + fprintf(stderr, "Expected version: %s\n", EXPECTED_VERSION); + fprintf(stderr, "But got version: %s", line); + exit(EXIT_FAILURE); + } + + while (fgets(line, MAX_LINE, f)) { + sscanf(line, "%ld %ld %ld %s", &count, &total, &max, reason); + if (max > 0 || total > 0) { + e = find_latency_entry(head, reason); + if (e) { + e->count += count; + if (max > e->max) + e->max = max; + e->total += total; + } else { + e = alloc_latency_entry(); + e->count = count; + e->max = max; + e->total = total; + strcpy(e->reason, reason); + e->next = head; + head = e; + } + } + } + + return head; +} + +static void print_latency_entries(struct latency_entry *head) { + struct latency_entry *e, **array; + unsigned long average; + int i, count; + + e = head; + count = 0; + while (e) { + count++; + e = e->next; + } + + e = head; + array = calloc(count, sizeof(struct latency_entry *)); + if (!array) { + fprintf(stderr, "Error allocating array: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + for (i = 0; i < count; i++) { + array[i] = e; + e = e->next; + } + + qsort(array, count, sizeof(struct latency_entry *), &lat_cmp); + + printf("%10s %10s %7s %s\n", "Maximum", "Average", "Count", "Reason"); + for (i = 0; i < count; i++) { + e = array[i]; + average = e->total / e->count; + printf("%4lu.%02lu ms %4lu.%02lu ms %7ld %s\n", + e->max / 1000, (e->max % 1000) / 10, + average / 1000, (average % 1000) / 10, + e->count, + e->reason); + } + + free(array); +} + +static void signal_handler(int sig) { + exit(EXIT_SUCCESS); +} + +static void disable_latencytop(void) { + set_latencytop(0); +} + +static void clear_screen(void) { + printf("\n\n"); +} + +static void usage(const char *cmd) { + fprintf(stderr, "Usage: %s [ -d delay ] [ -n iterations ] [ -p pid [ -t tid ] ] [ -h ]\n" + " -d delay Time to sleep between updates.\n" + " -n iterations Number of updates to show (0 = infinite).\n" + " -p pid Process to monitor (default is all).\n" + " -t tid Thread (within specified process) to monitor (default is all).\n" + " -h Display this help screen.\n", + cmd); +} + +static int numcmp(const long long a, const long long b) { + if (a < b) return -1; + if (a > b) return 1; + return 0; +} + +static int lat_cmp(const void *a, const void *b) { + const struct latency_entry *pa, *pb; + + pa = (*((struct latency_entry **)a)); + pb = (*((struct latency_entry **)b)); + + return numcmp(pb->max, pa->max); +} diff --git a/libpagemap/Android.mk b/libpagemap/Android.mk new file mode 100644 index 00000000..b38363c8 --- /dev/null +++ b/libpagemap/Android.mk @@ -0,0 +1,30 @@ +# Copyright (C) 2008 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE := libpagemap +LOCAL_MODULE_TAGS := debug +LOCAL_PRELINK_MODULE := false + +LOCAL_SRC_FILES := \ + pm_kernel.c \ + pm_process.c \ + pm_map.c \ + pm_memusage.c + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include + +include $(BUILD_SHARED_LIBRARY) diff --git a/libpagemap/MODULE_LICENSE_APACHE2 b/libpagemap/MODULE_LICENSE_APACHE2 new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/libpagemap/MODULE_LICENSE_APACHE2 diff --git a/libpagemap/NOTICE b/libpagemap/NOTICE new file mode 100644 index 00000000..c5b1efa7 --- /dev/null +++ b/libpagemap/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/libpagemap/include/pagemap/pagemap.h b/libpagemap/include/pagemap/pagemap.h new file mode 100644 index 00000000..09ff29d8 --- /dev/null +++ b/libpagemap/include/pagemap/pagemap.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _PAGEMAP_PAGEMAP_H +#define _PAGEMAP_PAGEMAP_H + +#include <stdint.h> +#include <stdio.h> +#include <sys/types.h> + +typedef struct pm_memusage pm_memusage_t; + +/* Holds the various metrics for memory usage of a process or a mapping. */ +struct pm_memusage { + size_t vss; + size_t rss; + size_t pss; + size_t uss; +}; + +/* Clears a memusage. */ +void pm_memusage_zero(pm_memusage_t *mu); +/* Adds one memusage (a) to another (b). */ +void pm_memusage_add(pm_memusage_t *a, pm_memusage_t *b); + +typedef struct pm_kernel pm_kernel_t; +typedef struct pm_process pm_process_t; +typedef struct pm_map pm_map_t; + +/* pm_kernel_t holds the state necessary to interface to the kernel's pagemap + * system on a global level. */ +struct pm_kernel { + int kpagecount_fd; + int kpageflags_fd; + + int pagesize; +}; + +/* pm_process_t holds the state necessary to interface to a particular process' + * pagemap. */ +struct pm_process { + pm_kernel_t *ker; + + pid_t pid; + + pm_map_t **maps; + int num_maps; + + int pagemap_fd; +}; + +/* pm_map_t holds the state necessary to access information about a particular + * mapping in a particular process. */ +struct pm_map { + pm_process_t *proc; + + unsigned long start; + unsigned long end; + unsigned long offset; + int flags; + + char *name; +}; + +/* Create a pm_kernel_t. */ +int pm_kernel_create(pm_kernel_t **ker_out); + +#define pm_kernel_pagesize(ker) ((ker)->pagesize) + +/* Get a list of probably-existing PIDs (returned through *pids_out). + * Length of the array (in sizeof(pid_t) units) is returned through *len. + * The array should be freed by the caller. */ +int pm_kernel_pids(pm_kernel_t *ker, pid_t **pids_out, size_t *len); + +/* Get the map count (from /proc/kpagecount) of a physical frame. + * The count is returned through *count_out. */ +int pm_kernel_count(pm_kernel_t *ker, unsigned long pfn, uint64_t *count_out); + +/* Get the page flags (from /proc/kpageflags) of a physical frame. + * The count is returned through *flags_out. */ +int pm_kernel_flags(pm_kernel_t *ker, unsigned long pfn, uint64_t *flags_out); + +#define PM_PAGE_LOCKED (1 << 0) +#define PM_PAGE_ERROR (1 << 1) +#define PM_PAGE_REFERENCED (1 << 2) +#define PM_PAGE_UPTODATE (1 << 3) +#define PM_PAGE_DIRTY (1 << 4) +#define PM_PAGE_LRU (1 << 5) +#define PM_PAGE_ACTIVE (1 << 6) +#define PM_PAGE_SLAB (1 << 7) +#define PM_PAGE_WRITEBACK (1 << 8) +#define PM_PAGE_RECLAIM (1 << 9) +#define PM_PAGE_BUDDY (1 << 10) + +/* Destroy a pm_kernel_t. */ +int pm_kernel_destroy(pm_kernel_t *ker); + +/* Get the PID of a pm_process_t. */ +#define pm_process_pid(proc) ((proc)->pid) + +/* Create a pm_process_t and returns it through *proc_out. + * Takes a pm_kernel_t, and the PID of the process. */ +int pm_process_create(pm_kernel_t *ker, pid_t pid, pm_process_t **proc_out); + +/* Get the total memory usage of a process and store in *usage_out. */ +int pm_process_usage(pm_process_t *proc, pm_memusage_t *usage_out); + +/* Get the working set of a process (if ws_out != NULL), and reset it + * (if reset != 0). */ +int pm_process_workingset(pm_process_t *proc, pm_memusage_t *ws_out, int reset); + +/* Get the PFNs corresponding to a range of virtual addresses. + * The array of PFNs is returned through *range_out, and the caller has the + * responsibility to free it. */ +int pm_process_pagemap_range(pm_process_t *proc, + unsigned long low, unsigned long hi, + uint64_t **range_out, size_t *len); + +#define _BITS(x, offset, bits) (((x) >> offset) & ((1LL << ((bits) + 1)) - 1)) + +#define PM_PAGEMAP_PRESENT(x) (_BITS(x, 63, 1)) +#define PM_PAGEMAP_SWAPPED(x) (!_BITS(x, 62, 1)) +#define PM_PAGEMAP_SHIFT(x) (_BITS(x, 55, 6)) +#define PM_PAGEMAP_PFN(x) (_BITS(x, 0, 55)) +#define PM_PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50)) +#define PM_PAGEMAP_SWAP_TYPE(x) (_BITS(x, 0, 5)) + +/* Get the maps in the virtual address space of this process. + * Returns an array of pointers to pm_map_t through *maps. + * The array should be freed by the caller, but the maps should not be + * modified or destroyed. */ +int pm_process_maps(pm_process_t *proc, pm_map_t ***maps_out, size_t *len); + +/* Destroy a pm_process_t. */ +int pm_process_destroy(pm_process_t *proc); + +/* Get the name, flags, start/end address, or offset of a map. */ +#define pm_map_name(map) ((map)->name) +#define pm_map_flags(map) ((map)->flags) +#define PM_MAP_READ 1 +#define PM_MAP_WRITE 2 +#define PM_MAP_EXEC 4 +#define pm_map_start(map) ((map)->start) +#define pm_map_end(map) ((map)->end) +#define pm_map_offset(map) ((map)->offset) + +/* Get the PFNs of the pages in the virtual address space of this map. + * Array of PFNs is returned through *pagemap_out, and should be freed by the + * caller. */ +int pm_map_pagemap(pm_map_t *map, uint64_t **pagemap_out, size_t *len); + +/* Get the memory usage of this map alone. */ +int pm_map_usage(pm_map_t *map, pm_memusage_t *usage_out); + +/* Get the working set of this map alone. */ +int pm_map_workingset(pm_map_t *map, pm_memusage_t *ws_out); + +#endif diff --git a/libpagemap/pm_kernel.c b/libpagemap/pm_kernel.c new file mode 100644 index 00000000..3615f1ac --- /dev/null +++ b/libpagemap/pm_kernel.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include <pagemap/pagemap.h> + +int pm_kernel_create(pm_kernel_t **ker_out) { + pm_kernel_t *ker; + int error; + + if (!ker_out) + return 1; + + ker = calloc(1, sizeof(*ker)); + if (!ker) + return errno; + + ker->kpagecount_fd = open("/proc/kpagecount", O_RDONLY); + if (ker->kpagecount_fd < 0) { + error = errno; + free(ker); + return error; + } + + ker->kpageflags_fd = open("/proc/kpageflags", O_RDONLY); + if (ker->kpageflags_fd < 0) { + error = errno; + close(ker->kpagecount_fd); + free(ker); + return error; + } + + ker->pagesize = getpagesize(); + + *ker_out = ker; + + return 0; +} + +#define INIT_PIDS 20 +int pm_kernel_pids(pm_kernel_t *ker, pid_t **pids_out, size_t *len) { + DIR *proc; + struct dirent *dir; + pid_t pid, *pids, *new_pids; + size_t pids_count, pids_size; + int error; + + proc = opendir("/proc"); + if (!proc) + return errno; + + pids = malloc(INIT_PIDS * sizeof(pid_t)); + if (!pids) { + closedir(proc); + return errno; + } + pids_count = 0; pids_size = INIT_PIDS; + + while ((dir = readdir(proc))) { + if (sscanf(dir->d_name, "%d", &pid) < 1) + continue; + + if (pids_count >= pids_size) { + new_pids = realloc(pids, 2 * pids_size * sizeof(pid_t)); + if (!new_pids) { + error = errno; + free(pids); + closedir(proc); + return error; + } + pids = new_pids; + pids_size = 2 * pids_size; + } + + pids[pids_count] = pid; + + pids_count++; + } + + closedir(proc); + + new_pids = realloc(pids, pids_count * sizeof(pid_t)); + if (!new_pids) { + error = errno; + free(pids); + return error; + } + + *pids_out = new_pids; + *len = pids_count; + + return 0; +} + +int pm_kernel_count(pm_kernel_t *ker, unsigned long pfn, uint64_t *count_out) { + off_t off; + + if (!ker || !count_out) + return -1; + + off = lseek(ker->kpagecount_fd, pfn * sizeof(uint64_t), SEEK_SET); + if (off == (off_t)-1) + return errno; + if (read(ker->kpagecount_fd, count_out, sizeof(uint64_t)) < + (ssize_t)sizeof(uint64_t)) + return errno; + + return 0; +} + +int pm_kernel_flags(pm_kernel_t *ker, unsigned long pfn, uint64_t *flags_out) { + off_t off; + + if (!ker || !flags_out) + return -1; + + off = lseek(ker->kpageflags_fd, pfn * sizeof(uint64_t), SEEK_SET); + if (off == (off_t)-1) + return errno; + if (read(ker->kpageflags_fd, flags_out, sizeof(uint64_t)) < + (ssize_t)sizeof(uint64_t)) + return errno; + + return 0; +} + +int pm_kernel_destroy(pm_kernel_t *ker) { + if (!ker) + return -1; + + close(ker->kpagecount_fd); + close(ker->kpageflags_fd); + + free(ker); + + return 0; +} diff --git a/libpagemap/pm_map.c b/libpagemap/pm_map.c new file mode 100644 index 00000000..f683ba6c --- /dev/null +++ b/libpagemap/pm_map.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <string.h> + +#include <pagemap/pagemap.h> + +int pm_map_pagemap(pm_map_t *map, uint64_t **pagemap_out, size_t *len) { + if (!map) + return -1; + + return pm_process_pagemap_range(map->proc, map->start, map->end, + pagemap_out, len); +} + +int pm_map_usage(pm_map_t *map, pm_memusage_t *usage_out) { + uint64_t *pagemap; + size_t len, i; + uint64_t count; + pm_memusage_t usage; + int error; + + if (!map || !usage_out) + return -1; + + error = pm_map_pagemap(map, &pagemap, &len); + if (error) return error; + + pm_memusage_zero(&usage); + + for (i = 0; i < len; i++) { + if (!PM_PAGEMAP_PRESENT(pagemap[i]) || + PM_PAGEMAP_SWAPPED(pagemap[i])) + continue; + + error = pm_kernel_count(map->proc->ker, PM_PAGEMAP_PFN(pagemap[i]), + &count); + if (error) goto out; + + usage.vss += map->proc->ker->pagesize; + usage.rss += (count >= 1) ? (map->proc->ker->pagesize) : (0); + usage.pss += (count >= 1) ? (map->proc->ker->pagesize / count) : (0); + usage.uss += (count == 1) ? (map->proc->ker->pagesize) : (0); + } + + memcpy(usage_out, &usage, sizeof(usage)); + + error = 0; + +out: + free(pagemap); + + return error; +} + +int pm_map_workingset(pm_map_t *map, pm_memusage_t *ws_out) { + uint64_t *pagemap; + size_t len, i; + uint64_t count, flags; + pm_memusage_t ws; + int error; + + if (!map || !ws_out) + return -1; + + error = pm_map_pagemap(map, &pagemap, &len); + if (error) return error; + + pm_memusage_zero(&ws); + + for (i = 0; i < len; i++) { + if (!PM_PAGEMAP_PRESENT(pagemap[i]) || + PM_PAGEMAP_SWAPPED(pagemap[i])) + continue; + + error = pm_kernel_flags(map->proc->ker, PM_PAGEMAP_PFN(pagemap[i]), + &flags); + if (error) goto out; + + if (!(flags & PM_PAGE_REFERENCED)) + continue; + + error = pm_kernel_count(map->proc->ker, PM_PAGEMAP_PFN(pagemap[i]), + &count); + if (error) goto out; + + ws.vss += map->proc->ker->pagesize; + ws.rss += (count >= 1) ? (map->proc->ker->pagesize) : (0); + ws.pss += (count >= 1) ? (map->proc->ker->pagesize / count) : (0); + ws.uss += (count == 1) ? (map->proc->ker->pagesize) : (0); + } + + memcpy(ws_out, &ws, sizeof(ws)); + + error = 0; + +out: + free(pagemap); + + return 0; +} + +int pm_map_destroy(pm_map_t *map) { + if (!map) + return -1; + + free(map->name); + free(map); + + return 0; +} diff --git a/libpagemap/pm_map.h b/libpagemap/pm_map.h new file mode 100644 index 00000000..08dc4485 --- /dev/null +++ b/libpagemap/pm_map.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBS_PAGEMAP_PM_MAP_H +#define _LIBS_PAGEMAP_PM_MAP_H + +#include <pagemap/pagemap.h> + +int pm_map_destroy(pm_map_t *map); + +#endif diff --git a/libpagemap/pm_memusage.c b/libpagemap/pm_memusage.c new file mode 100644 index 00000000..9c5db92e --- /dev/null +++ b/libpagemap/pm_memusage.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <pagemap/pagemap.h> + +void pm_memusage_zero(pm_memusage_t *mu) { + mu->vss = mu->rss = mu->pss = mu->uss = 0; +} + +void pm_memusage_add(pm_memusage_t *a, pm_memusage_t *b) { + a->vss += b->vss; + a->rss += b->rss; + a->pss += b->pss; + a->uss += b->uss; +} diff --git a/libpagemap/pm_process.c b/libpagemap/pm_process.c new file mode 100644 index 00000000..1ab367d8 --- /dev/null +++ b/libpagemap/pm_process.c @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <pagemap/pagemap.h> + +#include "pm_map.h" + +static int read_maps(pm_process_t *proc); + +#define MAX_FILENAME 64 + +int pm_process_create(pm_kernel_t *ker, pid_t pid, pm_process_t **proc_out) { + pm_process_t *proc; + char filename[MAX_FILENAME]; + int error; + + if (!ker || !proc_out) + return -1; + + proc = calloc(1, sizeof(*proc)); + if (!proc) + return errno; + + proc->ker = ker; + proc->pid = pid; + + error = snprintf(filename, MAX_FILENAME, "/proc/%d/pagemap", pid); + if (error < 0 || error >= MAX_FILENAME) { + error = (error < 0) ? (errno) : (-1); + free(proc); + return error; + } + + proc->pagemap_fd = open(filename, O_RDONLY); + if (proc->pagemap_fd < 0) { + error = errno; + free(proc); + return error; + } + + error = read_maps(proc); + if (error) { + free(proc); + return error; + } + + *proc_out = proc; + + return 0; +} + +int pm_process_usage(pm_process_t *proc, pm_memusage_t *usage_out) { + pm_memusage_t usage, map_usage; + int error; + int i; + + if (!proc || !usage_out) + return -1; + + pm_memusage_zero(&usage); + + for (i = 0; i < proc->num_maps; i++) { + error = pm_map_usage(proc->maps[i], &map_usage); + if (error) return error; + + pm_memusage_add(&usage, &map_usage); + } + + memcpy(usage_out, &usage, sizeof(pm_memusage_t)); + + return 0; +} + +int pm_process_pagemap_range(pm_process_t *proc, + unsigned long low, unsigned long high, + uint64_t **range_out, size_t *len) { + int firstpage, numpages; + uint64_t *range; + off_t off; + int error; + + if (!proc || (low >= high) || !range_out || !len) + return -1; + + firstpage = low / proc->ker->pagesize; + numpages = (high - low) / proc->ker->pagesize; + + range = malloc(numpages * sizeof(uint64_t)); + if (!range) + return errno; + + off = lseek(proc->pagemap_fd, firstpage * sizeof(uint64_t), SEEK_SET); + if (off == (off_t)-1) { + error = errno; + free(range); + return error; + } + error = read(proc->pagemap_fd, (char*)range, numpages * sizeof(uint64_t)); + if (error < numpages * sizeof(uint64_t)) { + error = (error < 0) ? errno : -1; + free(range); + return error; + } + + *range_out = range; + *len = numpages; + + return 0; +} + +int pm_process_maps(pm_process_t *proc, pm_map_t ***maps_out, size_t *len) { + pm_map_t **maps; + + if (!proc || !maps_out || !len) + return -1; + + if (proc->num_maps) { + maps = malloc(proc->num_maps * sizeof(pm_map_t*)); + if (!maps) + return errno; + + memcpy(maps, proc->maps, proc->num_maps * sizeof(pm_map_t*)); + + *maps_out = maps; + } else { + *maps_out = NULL; + } + *len = proc->num_maps; + + return 0; +} + +int pm_process_workingset(pm_process_t *proc, + pm_memusage_t *ws_out, int reset) { + pm_memusage_t ws, map_ws; + char filename[MAX_FILENAME]; + int fd; + int i, j; + int error; + + if (!proc) + return -1; + + if (ws_out) { + pm_memusage_zero(&ws); + for (i = 0; i < proc->num_maps; i++) { + error = pm_map_workingset(proc->maps[i], &map_ws); + if (error) return error; + + pm_memusage_add(&ws, &map_ws); + } + + memcpy(ws_out, &ws, sizeof(ws)); + } + + if (reset) { + error = snprintf(filename, MAX_FILENAME, "/proc/%d/clear_refs", + proc->pid); + if (error < 0 || error >= MAX_FILENAME) { + return (error < 0) ? (errno) : (-1); + } + + fd = open(filename, O_WRONLY); + if (fd < 0) + return errno; + + write(fd, "1\n", strlen("1\n")); + + close(fd); + } + + return 0; +} + +int pm_process_destroy(pm_process_t *proc) { + if (!proc) + return -1; + + free(proc->maps); + close(proc->pagemap_fd); + free(proc); + + return 0; +} + +#define INITIAL_MAPS 10 +#define MAX_LINE 256 +#define MAX_PERMS 5 + +/* + * #define FOO 123 + * S(FOO) => "123" + */ +#define _S(n) #n +#define S(n) _S(n) + +static int read_maps(pm_process_t *proc) { + char filename[MAX_FILENAME]; + char line[MAX_LINE], name[MAX_LINE], perms[MAX_PERMS]; + FILE *maps_f; + pm_map_t *map, **maps, **new_maps; + int maps_count, maps_size; + int error; + + if (!proc) + return -1; + + maps = calloc(INITIAL_MAPS, sizeof(pm_map_t*)); + if (!maps) + return errno; + maps_count = 0; maps_size = INITIAL_MAPS; + + error = snprintf(filename, MAX_FILENAME, "/proc/%d/maps", proc->pid); + if (error < 0 || error >= MAX_FILENAME) + return (error < 0) ? (errno) : (-1); + + maps_f = fopen(filename, "r"); + if (!maps_f) + return errno; + + while (fgets(line, MAX_LINE, maps_f)) { + if (maps_count >= maps_size) { + new_maps = realloc(maps, 2 * maps_size * sizeof(pm_map_t*)); + if (!new_maps) { + error = errno; + free(maps); + fclose(maps_f); + return error; + } + maps = new_maps; + maps_size *= 2; + } + + maps[maps_count] = map = calloc(1, sizeof(*map)); + + map->proc = proc; + + sscanf(line, "%lx-%lx %s %lx %*s %*d %" S(MAX_LINE) "s", + &map->start, &map->end, perms, &map->offset, name); + + map->name = malloc(strlen(name) + 1); + if (!map->name) { + error = errno; + for (; maps_count > 0; maps_count--) + pm_map_destroy(maps[maps_count]); + free(maps); + return error; + } + strcpy(map->name, name); + if (perms[0] == 'r') map->flags |= PM_MAP_READ; + if (perms[1] == 'w') map->flags |= PM_MAP_WRITE; + if (perms[2] == 'x') map->flags |= PM_MAP_EXEC; + + maps_count++; + } + + fclose(maps_f); + + new_maps = realloc(maps, maps_count * sizeof(pm_map_t*)); + if (maps_count && !new_maps) { + error = errno; + free(maps); + return error; + } + + proc->maps = new_maps; + proc->num_maps = maps_count; + + return 0; +} diff --git a/librank/Android.mk b/librank/Android.mk new file mode 100644 index 00000000..300b3f59 --- /dev/null +++ b/librank/Android.mk @@ -0,0 +1,30 @@ +# Copyright (C) 2008 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := librank.c + +LOCAL_C_INCLUDES := $(call include-path-for, libpagemap) + +LOCAL_SHARED_LIBRARIES := libpagemap + +LOCAL_MODULE := librank + +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) + +LOCAL_MODULE_TAGS := debug + +include $(BUILD_EXECUTABLE) diff --git a/librank/MODULE_LICENSE_APACHE2 b/librank/MODULE_LICENSE_APACHE2 new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/librank/MODULE_LICENSE_APACHE2 diff --git a/librank/NOTICE b/librank/NOTICE new file mode 100644 index 00000000..c5b1efa7 --- /dev/null +++ b/librank/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/librank/librank.c b/librank/librank.c new file mode 100644 index 00000000..13b20974 --- /dev/null +++ b/librank/librank.c @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <assert.h> +#include <dirent.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +#include <pagemap/pagemap.h> + +#define MAX_CMDLINE 256 + +struct process_info { + pid_t pid; + char cmdline[MAX_CMDLINE]; +}; + +struct mapping_info { + struct process_info *proc; + pm_memusage_t usage; +}; + +struct library_info { + struct library_info *next; + char *name; + struct mapping_info **mappings; + int mappings_count; + int mappings_size; + pm_memusage_t total_usage; +}; + +static void usage(char *myname); +static int getprocname(pid_t pid, char *buf, size_t len); +static int numcmp(long long a, long long b); +static int licmp(const void *a, const void *b); + +char *library_name_blacklist[] = { "[heap]", "[stack]", "", NULL }; + +#define declare_sort(field) \ + static int sort_by_ ## field (const void *a, const void *b) + +declare_sort(vss); +declare_sort(rss); +declare_sort(pss); +declare_sort(uss); + +#define INIT_LIBRARIES 16 +#define INIT_MAPPINGS 4 + +static int order; + +struct library_info **libraries; +int libraries_count; +int libraries_size; + +struct library_info *get_library(char *name) { + int i; + struct library_info *library; + + for (i = 0; library_name_blacklist[i]; i++) + if (!strcmp(name, library_name_blacklist[i])) + return NULL; + + for (i = 0; i < libraries_count; i++) { + if (!strcmp(libraries[i]->name, name)) + return libraries[i]; + } + + if (libraries_count >= libraries_size) { + libraries = realloc(libraries, 2 * libraries_size * sizeof(struct library_info *)); + if (!libraries) { + fprintf(stderr, "Couldn't resize libraries array: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + libraries_size = 2 * libraries_size; + } + + library = calloc(1, sizeof(*library)); + if (!library) { + fprintf(stderr, "Couldn't allocate space for library struct: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + library->name = malloc(strlen(name) + 1); + if (!library->name) { + fprintf(stderr, "Couldn't allocate space for library name: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + strcpy(library->name, name); + library->mappings = malloc(INIT_MAPPINGS * sizeof(struct mapping_info *)); + if (!library->mappings) { + fprintf(stderr, "Couldn't allocate space for library mappings array: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + library->mappings_count = 0; library->mappings_size = INIT_MAPPINGS; + pm_memusage_zero(&library->total_usage); + + libraries[libraries_count++] = library; + + return library; +} + +struct mapping_info *get_mapping(struct library_info *library, struct process_info *proc) { + struct mapping_info *mapping; + int i; + + for (i = 0; i < library->mappings_count; i++) { + if (library->mappings[i]->proc == proc) + return library->mappings[i]; + } + + if (library->mappings_count >= library->mappings_size) { + library->mappings = realloc(library->mappings, + 2 * library->mappings_size * sizeof(struct mapping*)); + if (!library->mappings) { + fprintf(stderr, "Couldn't resize mappings array: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + library->mappings_size = 2 * library->mappings_size; + } + + mapping = calloc(1, sizeof(*mapping)); + if (!mapping) { + fprintf(stderr, "Couldn't allocate space for mapping struct: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + mapping->proc = proc; + pm_memusage_zero(&mapping->usage); + + library->mappings[library->mappings_count++] = mapping; + + return mapping; +} + +struct process_info *get_process(pid_t pid) { + struct process_info *process; + + process = calloc(1, sizeof(*process)); + if (!process) { + fprintf(stderr, "Couldn't allocate space for process struct: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + process->pid = pid; + getprocname(pid, process->cmdline, sizeof(process->cmdline)); + + return process; +} + +int main(int argc, char *argv[]) { + char cmdline[256]; + char *prefix; + size_t prefix_len; + int (*compfn)(const void *a, const void *b); + + pm_kernel_t *ker; + pm_process_t *proc; + + pid_t *pids; + size_t num_procs; + + pm_map_t **maps; + size_t num_maps; + pm_memusage_t map_usage; + + struct library_info *li, **lis; + struct mapping_info *mi, **mis; + struct process_info *pi; + + int i, j, error; + + compfn = &sort_by_pss; + order = -1; + prefix = NULL; + prefix_len = 0; + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-P")) { + if (i + 1 >= argc) { + fprintf(stderr, "Option -P requires an argument.\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + prefix = argv[++i]; + prefix_len = strlen(prefix); + continue; + } + if (!strcmp(argv[i], "-v")) { compfn = &sort_by_vss; continue; } + if (!strcmp(argv[i], "-r")) { compfn = &sort_by_rss; continue; } + if (!strcmp(argv[i], "-p")) { compfn = &sort_by_pss; continue; } + if (!strcmp(argv[i], "-u")) { compfn = &sort_by_uss; continue; } + if (!strcmp(argv[i], "-R")) { order *= -1; continue; } + if (!strcmp(argv[i], "-h")) { usage(argv[0]); exit(0); } + fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + libraries = malloc(INIT_LIBRARIES * sizeof(struct library_info *)); + libraries_count = 0; libraries_size = INIT_LIBRARIES; + + error = pm_kernel_create(&ker); + if (error) { + fprintf(stderr, "Error initializing kernel interface -- " + "does this kernel have pagemap?\n"); + exit(EXIT_FAILURE); + } + + error = pm_kernel_pids(ker, &pids, &num_procs); + if (error) { + fprintf(stderr, "Error listing processes.\n"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < num_procs; i++) { + error = pm_process_create(ker, pids[i], &proc); + if (error) { + fprintf(stderr, "warning: could not create process interface for %d\n", pids[i]); + continue; + } + + pi = get_process(pids[i]); + + error = pm_process_maps(proc, &maps, &num_maps); + if (error) { + fprintf(stderr, "Error listing maps for process %d.\n", proc->pid); + exit(EXIT_FAILURE); + } + + for (j = 0; j < num_maps; j++) { + if (prefix && (strncmp(pm_map_name(maps[j]), prefix, prefix_len))) + continue; + + li = get_library(pm_map_name(maps[j])); + if (!li) + continue; + + mi = get_mapping(li, pi); + + error = pm_map_usage(maps[j], &map_usage); + if (error) { + fprintf(stderr, "Error getting map memory usage of " + "map %s in process %d.\n", + pm_map_name(maps[j]), proc->pid); + exit(EXIT_FAILURE); + } + pm_memusage_add(&mi->usage, &map_usage); + pm_memusage_add(&li->total_usage, &map_usage); + } + } + + printf( " %6s %6s %6s %6s %6s %s\n", "RSStot", "VSS", "RSS", "PSS", "USS", "Name/PID"); + fflush(stdout); + + qsort(libraries, libraries_count, sizeof(libraries[0]), &licmp); + + for (i = 0; i < libraries_count; i++) { + li = libraries[i]; + + printf("%6dK %6s %6s %6s %6s %s\n", li->total_usage.pss / 1024, "", "", "", "", li->name); + fflush(stdout); + + qsort(li->mappings, li->mappings_count, sizeof(li->mappings[0]), compfn); + + for (j = 0; j < li->mappings_count; j++) { + mi = li->mappings[j]; + pi = mi->proc; + printf( " %6s %6dK %6dK %6dK %6dK %s [%d]\n", "", + mi->usage.vss / 1024, + mi->usage.rss / 1024, + mi->usage.pss / 1024, + mi->usage.uss / 1024, + pi->cmdline, + pi->pid); + } + printf("\n"); + fflush(stdout); + } + + return 0; +} + +static void usage(char *myname) { + fprintf(stderr, "Usage: %s [ -P | -L ] [ -v | -r | -p | -u | -h ]\n" + "\n" + "Sort options:\n" + " -v Sort processes by VSS.\n" + " -r Sort processes by RSS.\n" + " -p Sort processes by PSS.\n" + " -u Sort processes by USS.\n" + " (Default sort order is PSS.)\n" + " -P /path Limit libraries displayed to those in path.\n" + " -R Reverse sort order (default is descending).\n" + " -h Display this help screen.\n", + myname); +} + +static int getprocname(pid_t pid, char *buf, size_t len) { + char filename[20]; + FILE *f; + + sprintf(filename, "/proc/%d/cmdline", pid); + f = fopen(filename, "r"); + if (!f) { *buf = '\0'; return 1; } + if (!fgets(buf, len, f)) { *buf = '\0'; return 2; } + fclose(f); + return 0; +} + +static int numcmp(long long a, long long b) { + if (a < b) return -1; + if (a > b) return 1; + return 0; +} + +static int licmp(const void *a, const void *b) { + return order * numcmp( + (*((struct library_info**)a))->total_usage.pss, + (*((struct library_info**)b))->total_usage.pss + ); +} + +#define create_sort(field, compfn) \ + static int sort_by_ ## field (const void *a, const void *b) { \ + return order * compfn( \ + (*((struct mapping_info**)a))->usage.field, \ + (*((struct mapping_info**)b))->usage.field \ + ); \ + } + +create_sort(vss, numcmp) +create_sort(rss, numcmp) +create_sort(pss, numcmp) +create_sort(uss, numcmp) diff --git a/procmem/Android.mk b/procmem/Android.mk new file mode 100644 index 00000000..ffd56604 --- /dev/null +++ b/procmem/Android.mk @@ -0,0 +1,30 @@ +# Copyright (C) 2008 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := procmem.c + +LOCAL_C_INCLUDES := $(call include-path-for, libpagemap) + +LOCAL_SHARED_LIBRARIES := libpagemap + +LOCAL_MODULE := procmem + +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) + +LOCAL_MODULE_TAGS := debug + +include $(BUILD_EXECUTABLE) diff --git a/procmem/MODULE_LICENSE_APACHE2 b/procmem/MODULE_LICENSE_APACHE2 new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/procmem/MODULE_LICENSE_APACHE2 diff --git a/procmem/NOTICE b/procmem/NOTICE new file mode 100644 index 00000000..c5b1efa7 --- /dev/null +++ b/procmem/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/procmem/procmem.c b/procmem/procmem.c new file mode 100644 index 00000000..03c9f51f --- /dev/null +++ b/procmem/procmem.c @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <pagemap/pagemap.h> + +/* Information about a single mapping */ +struct map_info { + pm_map_t *map; + pm_memusage_t usage; + /* page counts */ + unsigned long shared_clean; + unsigned long shared_dirty; + unsigned long private_clean; + unsigned long private_dirty; +}; + +/* display the help screen */ +static void usage(const char *cmd); + +/* qsort compare function to compare maps by PSS */ +int comp_pss(const void *a, const void *b); + +int main(int argc, char *argv[]) { + pid_t pid; + + /* libpagemap context */ + pm_kernel_t *ker; + int pagesize; /* cached for speed */ + pm_process_t *proc; + + /* maps and such */ + pm_map_t **maps; int num_maps; + + struct map_info **mis; + struct map_info *mi; + + /* pagemap information */ + uint64_t *pagemap; int num_pages; + unsigned long address; uint64_t mapentry; + uint64_t count, flags; + + /* totals */ + unsigned long total_shared_clean, total_shared_dirty, total_private_clean, total_private_dirty; + pm_memusage_t total_usage; + + /* command-line options */ + int ws; +#define WS_OFF (0) +#define WS_ONLY (1) +#define WS_RESET (2) + int (*compfn)(const void *a, const void *b); + int hide_zeros; + + /* temporary variables */ + int i, j; + char *endptr; + int error; + + if (argc < 2) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + ws = WS_OFF; + compfn = NULL; + hide_zeros = 0; + for (i = 1; i < argc - 1; i++) { + if (!strcmp(argv[i], "-w")) { ws = WS_ONLY; continue; } + if (!strcmp(argv[i], "-W")) { ws = WS_RESET; continue; } + if (!strcmp(argv[i], "-m")) { compfn = NULL; continue; } + if (!strcmp(argv[i], "-p")) { compfn = &comp_pss; continue; } + if (!strcmp(argv[i], "-h")) { hide_zeros = 1; continue; } + fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + pid = (pid_t)strtol(argv[argc - 1], &endptr, 10); + if (*endptr != '\0') { + fprintf(stderr, "Invalid PID \"%s\".\n", argv[argc - 1]); + exit(EXIT_FAILURE); + } + + error = pm_kernel_create(&ker); + if (error) { + fprintf(stderr, "error creating kernel interface -- " + "does this kernel have pagemap?\n"); + exit(EXIT_FAILURE); + } + + pagesize = pm_kernel_pagesize(ker); + + error = pm_process_create(ker, pid, &proc); + if (error) { + fprintf(stderr, "error creating process interface -- " + "does process %d really exist?\n", pid); + exit(EXIT_FAILURE); + } + + if (ws == WS_RESET) { + error = pm_process_workingset(proc, NULL, 1); + if (error) { + fprintf(stderr, "error resetting working set for process.\n"); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); + } + + /* get maps, and allocate our map_info array */ + error = pm_process_maps(proc, &maps, &num_maps); + if (error) { + fprintf(stderr, "error listing maps.\n"); + exit(EXIT_FAILURE); + } + + mis = (struct map_info **)calloc(num_maps, sizeof(struct map_info *)); + if (!mis) { + fprintf(stderr, "error allocating map_info array: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + /* print header */ + if (ws == WS_ONLY) { + printf("%7s %7s %7s %7s %7s %7s %7s %s\n", + "WRss", "WPss", "WUss", "WShCl", "WShDi", "WPrCl", "WPrDi", "Name"); + printf("%7s %7s %7s %7s %7s %7s %7s %s\n", + "-------", "-------", "-------", "-------", "-------", "-------", "-------", ""); + } else { + printf("%7s %7s %7s %7s %7s %7s %7s %7s %s\n", + "Vss", "Rss", "Pss", "Uss", "ShCl", "ShDi", "PrCl", "PrDi", "Name"); + printf("%7s %7s %7s %7s %7s %7s %7s %7s %s\n", + "-------", "-------", "-------", "-------", "-------", "-------", "-------", "-------", ""); + } + + /* zero things */ + pm_memusage_zero(&total_usage); + total_shared_clean = total_shared_dirty = total_private_clean = total_private_dirty = 0; + + for (i = 0; i < num_maps; i++) { + mi = (struct map_info *)calloc(1, sizeof(struct map_info)); + if (!mi) { + fprintf(stderr, "error allocating map_info: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + mi->map = maps[i]; + + /* get, and sum, memory usage */ + + if (ws == WS_ONLY) + error = pm_map_workingset(mi->map, &mi->usage); + else + error = pm_map_usage(mi->map, &mi->usage); + if (error) { + fflush(stdout); + fprintf(stderr, "error getting usage for map.\n"); + continue; + } + + pm_memusage_add(&total_usage, &mi->usage); + + /* get, and sum, individual page counts */ + + error = pm_map_pagemap(mi->map, &pagemap, &num_pages); + if (error) { + fflush(stdout); + fprintf(stderr, "error getting pagemap for map.\n"); + continue; + } + + mi->shared_clean = mi->shared_dirty = mi->private_clean = mi->private_dirty = 0; + + for (j = 0; j < num_pages; j++) { + address = pm_map_start(mi->map) + j * ker->pagesize; + mapentry = pagemap[j]; + + if (PM_PAGEMAP_PRESENT(mapentry) && !PM_PAGEMAP_SWAPPED(mapentry)) { + + error = pm_kernel_count(ker, PM_PAGEMAP_PFN(mapentry), &count); + if (error) { + fflush(stdout); + fprintf(stderr, "error getting count for frame.\n"); + } + + error = pm_kernel_flags(ker, PM_PAGEMAP_PFN(mapentry), &flags); + if (error) { + fflush(stdout); + fprintf(stderr, "error getting flags for frame.\n"); + } + + if ((ws != WS_ONLY) || (flags & PM_PAGE_REFERENCED)) { + if (count > 1) { + if (flags & PM_PAGE_DIRTY) + mi->shared_dirty++; + else + mi->shared_clean++; + } else { + if (flags & PM_PAGE_DIRTY) + mi->private_dirty++; + else + mi->private_clean++; + } + } + } + } + + total_shared_clean += mi->shared_clean; + total_shared_dirty += mi->shared_dirty; + total_private_clean += mi->private_clean; + total_private_dirty += mi->private_dirty; + + /* add to array */ + mis[i] = mi; + } + + /* sort the array, if requested (compfn == NULL for original order) */ + if (compfn) + qsort(mis, num_maps, sizeof(mis[0]), compfn); + + for (i = 0; i < num_maps; i++) { + mi = mis[i]; + + if (hide_zeros && !mi->usage.rss) + continue; + + if (ws == WS_ONLY) { + printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n", + (long)mi->usage.rss / 1024, + (long)mi->usage.pss / 1024, + (long)mi->usage.uss / 1024, + mi->shared_clean * pagesize / 1024, + mi->shared_dirty * pagesize / 1024, + mi->private_clean * pagesize / 1024, + mi->private_dirty * pagesize / 1024, + pm_map_name(mi->map) + ); + } else { + printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n", + (long)mi->usage.vss / 1024, + (long)mi->usage.rss / 1024, + (long)mi->usage.pss / 1024, + (long)mi->usage.uss / 1024, + mi->shared_clean * pagesize / 1024, + mi->shared_dirty * pagesize / 1024, + mi->private_clean * pagesize / 1024, + mi->private_dirty * pagesize / 1024, + pm_map_name(mi->map) + ); + } + } + + /* print totals */ + if (ws == WS_ONLY) { + printf("%7s %7s %7s %7s %7s %7s %7s %s\n", + "-------", "-------", "-------", "-------", "-------", "-------", "-------", ""); + printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n", + (long)total_usage.rss / 1024, + (long)total_usage.pss / 1024, + (long)total_usage.uss / 1024, + total_shared_clean * pagesize / 1024, + total_shared_dirty * pagesize / 1024, + total_private_clean * pagesize / 1024, + total_private_dirty * pagesize / 1024, + "TOTAL" + ); + } else { + printf("%7s %7s %7s %7s %7s %7s %7s %7s %s\n", + "-------", "-------", "-------", "-------", "-------", "-------", "-------", "-------", ""); + printf("%6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %6ldK %s\n", + (long)total_usage.vss / 1024, + (long)total_usage.rss / 1024, + (long)total_usage.pss / 1024, + (long)total_usage.uss / 1024, + total_shared_clean * pagesize / 1024, + total_shared_dirty * pagesize / 1024, + total_private_clean * pagesize / 1024, + total_private_dirty * pagesize / 1024, + "TOTAL" + ); + } + + return 0; +} + +static void usage(const char *cmd) { + fprintf(stderr, "Usage: %s [ -w | -W ] [ -p | -m ] [ -h ] pid\n" + " -w Displays statistics for the working set only.\n" + " -W Resets the working set of the process.\n" + " -p Sort by PSS.\n" + " -m Sort by mapping order (as read from /proc).\n" + " -h Hide maps with no RSS.\n", + cmd); +} + +int comp_pss(const void *a, const void *b) { + struct map_info *ma, *mb; + + ma = *((struct map_info **)a); + mb = *((struct map_info **)b); + + if (mb->usage.pss < ma->usage.pss) return -1; + if (mb->usage.pss > ma->usage.pss) return 1; + return 0; +} diff --git a/procrank/Android.mk b/procrank/Android.mk new file mode 100644 index 00000000..eb487105 --- /dev/null +++ b/procrank/Android.mk @@ -0,0 +1,30 @@ +# Copyright (C) 2008 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := procrank.c + +LOCAL_C_INCLUDES := $(call include-path-for, libpagemap) + +LOCAL_SHARED_LIBRARIES := libpagemap + +LOCAL_MODULE := procrank + +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) + +LOCAL_MODULE_TAGS := debug + +include $(BUILD_EXECUTABLE) diff --git a/procrank/MODULE_LICENSE_APACHE2 b/procrank/MODULE_LICENSE_APACHE2 new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/procrank/MODULE_LICENSE_APACHE2 diff --git a/procrank/NOTICE b/procrank/NOTICE new file mode 100644 index 00000000..c5b1efa7 --- /dev/null +++ b/procrank/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/procrank/procrank.c b/procrank/procrank.c new file mode 100644 index 00000000..585fddcd --- /dev/null +++ b/procrank/procrank.c @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <dirent.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/types.h> +#include <unistd.h> + +#include <pagemap/pagemap.h> + +struct proc_info { + pid_t pid; + pm_memusage_t usage; + unsigned long wss; +}; + +static void usage(char *myname); +static int getprocname(pid_t pid, char *buf, size_t len); +static int numcmp(long long a, long long b); + +#define declare_sort(field) \ + static int sort_by_ ## field (const void *a, const void *b) + +declare_sort(vss); +declare_sort(rss); +declare_sort(pss); +declare_sort(uss); + +int (*compfn)(const void *a, const void *b); +static int order; + +#define MAX_PROCS 256 + +int main(int argc, char *argv[]) { + pm_kernel_t *ker; + pm_process_t *proc; + pid_t *pids; + struct proc_info *procs[MAX_PROCS]; + size_t num_procs; + char cmdline[256]; + int error; + + #define WS_OFF 0 + #define WS_ONLY 1 + #define WS_RESET 2 + int ws; + + int i, j; + + compfn = &sort_by_pss; + order = -1; + ws = WS_OFF; + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-v")) { compfn = &sort_by_vss; continue; } + if (!strcmp(argv[i], "-r")) { compfn = &sort_by_rss; continue; } + if (!strcmp(argv[i], "-p")) { compfn = &sort_by_pss; continue; } + if (!strcmp(argv[i], "-u")) { compfn = &sort_by_uss; continue; } + if (!strcmp(argv[i], "-w")) { ws = WS_ONLY; continue; } + if (!strcmp(argv[i], "-W")) { ws = WS_RESET; continue; } + if (!strcmp(argv[i], "-R")) { order *= -1; continue; } + if (!strcmp(argv[i], "-h")) { usage(argv[0]); exit(0); } + fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + error = pm_kernel_create(&ker); + if (error) { + fprintf(stderr, "Error creating kernel interface -- " + "does this kernel have pagemap?\n"); + exit(EXIT_FAILURE); + } + + error = pm_kernel_pids(ker, &pids, &num_procs); + if (error) { + fprintf(stderr, "Error listing processes.\n"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < num_procs; i++) { + procs[i] = malloc(sizeof(struct proc_info)); + if (!procs[i]) { + fprintf(stderr, "malloc: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + procs[i]->pid = pids[i]; + error = pm_process_create(ker, pids[i], &proc); + if (!error) { + switch (ws) { + case WS_OFF: + pm_process_usage(proc, &procs[i]->usage); + break; + case WS_ONLY: + pm_process_workingset(proc, &procs[i]->usage, 0); + break; + case WS_RESET: + pm_process_workingset(proc, NULL, 1); + break; + } + pm_process_destroy(proc); + } else { + fprintf(stderr, "warning: could not create process interface for %d\n", pids[i]); + pm_memusage_zero(&procs[i]->usage); + } + } + + free(pids); + + if (ws == WS_RESET) exit(0); + + j = 0; + for (i = 0; i < num_procs; i++) { + if (procs[i]->usage.vss) + procs[j++] = procs[i]; + } + num_procs = j; + + qsort(procs, num_procs, sizeof(procs[0]), compfn); + + if (ws) + printf("%5s %7s %7s %7s %s\n", "PID", "WRss", "WPss", "WUss", "cmdline"); + else + printf("%5s %7s %7s %7s %7s %s\n", "PID", "Vss", "Rss", "Pss", "Uss", "cmdline"); + for (i = 0; i < num_procs; i++) { + getprocname(procs[i]->pid, cmdline, sizeof(cmdline)); + if (ws) + printf("%5d %6dK %6dK %6dK %s\n", + procs[i]->pid, + procs[i]->usage.rss / 1024, + procs[i]->usage.pss / 1024, + procs[i]->usage.uss / 1024, + cmdline + ); + else + printf("%5d %6dK %6dK %6dK %6dK %s\n", + procs[i]->pid, + procs[i]->usage.vss / 1024, + procs[i]->usage.rss / 1024, + procs[i]->usage.pss / 1024, + procs[i]->usage.uss / 1024, + cmdline + ); + } + + return 0; +} + +static void usage(char *myname) { + fprintf(stderr, "Usage: %s [ -W ] [ -v | -r | -p | -u | -h ]\n" + " -v Sort by VSS.\n" + " -r Sort by RSS.\n" + " -p Sort by PSS.\n" + " -u Sort by USS.\n" + " (Default sort order is PSS.)\n" + " -R Reverse sort order (default is descending).\n" + " -w Display statistics for working set only.\n" + " -W Reset working set of all processes.\n" + " -h Display this help screen.\n", + myname); +} + +static int getprocname(pid_t pid, char *buf, size_t len) { + char filename[20]; + FILE *f; + + sprintf(filename, "/proc/%d/cmdline", pid); + f = fopen(filename, "r"); + if (!f) { *buf = '\0'; return 1; } + if (!fgets(buf, len, f)) { *buf = '\0'; return 2; } + fclose(f); + return 0; +} + +static int numcmp(long long a, long long b) { + if (a < b) return -1; + if (a > b) return 1; + return 0; +} + +#define create_sort(field, compfn) \ + static int sort_by_ ## field (const void *a, const void *b) { \ + return order * compfn( \ + (*((struct proc_info**)a))->usage.field, \ + (*((struct proc_info**)b))->usage.field \ + ); \ + } + +create_sort(vss, numcmp) +create_sort(rss, numcmp) +create_sort(pss, numcmp) +create_sort(uss, numcmp) diff --git a/showmap/Android.mk b/showmap/Android.mk new file mode 100644 index 00000000..5c90f12f --- /dev/null +++ b/showmap/Android.mk @@ -0,0 +1,13 @@ +# Copyright 2006 The Android Open Source Project + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= showmap.c +LOCAL_SHARED_LIBRARIES := libcutils +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) +LOCAL_MODULE_TAGS := debug +LOCAL_MODULE:= showmap + +include $(BUILD_EXECUTABLE) + diff --git a/showmap/MODULE_LICENSE_APACHE2 b/showmap/MODULE_LICENSE_APACHE2 new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/showmap/MODULE_LICENSE_APACHE2 diff --git a/showmap/NOTICE b/showmap/NOTICE new file mode 100644 index 00000000..c5b1efa7 --- /dev/null +++ b/showmap/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/showmap/showmap.c b/showmap/showmap.c new file mode 100644 index 00000000..e8c7dd50 --- /dev/null +++ b/showmap/showmap.c @@ -0,0 +1,232 @@ +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +#include <ctype.h> +#include <stddef.h> + +typedef struct mapinfo mapinfo; + +struct mapinfo { + mapinfo *next; + unsigned start; + unsigned end; + unsigned size; + unsigned rss; + unsigned pss; + unsigned shared_clean; + unsigned shared_dirty; + unsigned private_clean; + unsigned private_dirty; + char name[1]; +}; + +// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /android/lib/libcomposer.so +// 012345678901234567890123456789012345678901234567890123456789 +// 0 1 2 3 4 5 + +mapinfo *read_mapinfo(FILE *fp) +{ + char line[1024]; + mapinfo *mi; + int len; + int skip; + +again: + skip = 0; + + if(fgets(line, 1024, fp) == 0) return 0; + + len = strlen(line); + if(len < 1) return 0; + line[--len] = 0; + + mi = calloc(1, sizeof(mapinfo) + len + 16); + if(mi == 0) return 0; + + mi->start = strtoul(line, 0, 16); + mi->end = strtoul(line + 9, 0, 16); + + if(len < 50) { + if((mi->start >= 0x10000000) && (mi->start < 0x40000000)) { + strcpy(mi->name, "[stack]"); + } else if(mi->start > 0x50000000) { + strcpy(mi->name, "[lib_bss]"); + } else { + strcpy(mi->name, "[anon]"); + } + } else { + strcpy(mi->name, line + 49); + } + + if(fgets(line, 1024, fp) == 0) goto oops; + if(sscanf(line, "Size: %d kB", &mi->size) != 1) goto oops; + if(fgets(line, 1024, fp) == 0) goto oops; + if(sscanf(line, "Rss: %d kB", &mi->rss) != 1) goto oops; + if(fgets(line, 1024, fp) == 0) goto oops; + if(sscanf(line, "Pss: %d kB", &mi->pss) == 1) + if(fgets(line, 1024, fp) == 0) goto oops; + if(sscanf(line, "Shared_Clean: %d kB", &mi->shared_clean) != 1) goto oops; + if(fgets(line, 1024, fp) == 0) goto oops; + if(sscanf(line, "Shared_Dirty: %d kB", &mi->shared_dirty) != 1) goto oops; + if(fgets(line, 1024, fp) == 0) goto oops; + if(sscanf(line, "Private_Clean: %d kB", &mi->private_clean) != 1) goto oops; + if(fgets(line, 1024, fp) == 0) goto oops; + if(sscanf(line, "Private_Dirty: %d kB", &mi->private_dirty) != 1) goto oops; + if(fgets(line, 1024, fp) == 0) goto oops; + + if(skip) { + free(mi); + goto again; + } + + return mi; +oops: + free(mi); + return 0; +} + + +mapinfo *load_maps(int pid, int verbose) +{ + char tmp[128]; + FILE *fp; + mapinfo *milist = 0; + mapinfo *mi; + + sprintf(tmp, "/proc/%d/smaps", pid); + fp = fopen(tmp, "r"); + if(fp == 0) return 0; + + while((mi = read_mapinfo(fp)) != 0) { + /* if not verbose, coalesce mappings from the same entity */ + if(!verbose && milist) { + if((!strcmp(mi->name, milist->name) && (mi->name[0] != '[')) + || !strcmp(mi->name,"[lib_bss]")) { + milist->size += mi->size; + milist->rss += mi->rss; + milist->pss += mi->pss; + milist->shared_clean += mi->shared_clean; + milist->shared_dirty += mi->shared_dirty; + milist->private_clean += mi->private_clean; + milist->private_dirty += mi->private_dirty; + milist->end = mi->end; + free(mi); + continue; + } + } + + mi->next = milist; + milist = mi; + } + fclose(fp); + + return milist; +} + +static int verbose = 0; +static int terse = 0; +static int addresses = 0; + +int show_map(int pid) +{ + mapinfo *milist; + mapinfo *mi; + unsigned shared_dirty = 0; + unsigned shared_clean = 0; + unsigned private_dirty = 0; + unsigned private_clean = 0; + unsigned rss = 0; + unsigned pss = 0; + unsigned size = 0; + + milist = load_maps(pid, verbose); + if(milist == 0) { + fprintf(stderr,"cannot get /proc/smaps for pid %d\n", pid); + return 1; + } + + if(addresses) { + printf("start end shared private object\n"); + printf("-------- -------- -------- -------- ------------------------------\n"); + } else { + printf("virtual shared shared private private\n"); + printf("size RSS PSS clean dirty clean dirty object\n"); + printf("-------- -------- -------- -------- -------- -------- -------- ------------------------------\n"); + } + for(mi = milist; mi; mi = mi->next){ + shared_clean += mi->shared_clean; + shared_dirty += mi->shared_dirty; + private_clean += mi->private_clean; + private_dirty += mi->private_dirty; + rss += mi->rss; + pss += mi->pss; + size += mi->size; + + if(terse && !mi->private_dirty) continue; + + if(addresses) { + printf("%08x %08x %8d %8d %s\n", mi->start, mi->end, + mi->shared_clean + mi->shared_dirty, + mi->private_clean + mi->private_dirty, + mi->name); + } else { + printf("%8d %8d %8d %8d %8d %8d %8d %s\n", mi->size, + mi->rss, + mi->pss, + mi->shared_clean, mi->shared_dirty, + mi->private_clean, mi->private_dirty, + mi->name); + } + } + if(addresses) { + printf("-------- -------- -------- -------- ------------------------------\n"); + printf(" %8d %8d TOTAL\n", + shared_dirty + shared_clean, + private_dirty + private_clean); + } else { + printf("-------- -------- -------- -------- -------- -------- -------- ------------------------------\n"); + printf("%8d %8d %8d %8d %8d %8d %8d TOTAL\n", size, + rss, pss, + shared_clean, shared_dirty, + private_clean, private_dirty); + } + return 0; +} + +int main(int argc, char *argv[]) +{ + int usage = 1; + + for(argc--, argv++; argc > 0; argc--, argv++) { + if(!strcmp(argv[0],"-v")) { + verbose = 1; + continue; + } + if(!strcmp(argv[0],"-t")) { + terse = 1; + continue; + } + if(!strcmp(argv[0],"-a")) { + addresses = 1; + continue; + } + show_map(atoi(argv[0])); + usage = 0; + } + + if(usage) { + fprintf(stderr, + "showmap [-t] [-v] [-c] <pid>\n" + " -t = terse (show only items with private pages)\n" + " -v = verbose (don't coalesce adjacant maps)\n" + " -a = addresses (show virtual memory map)\n" + ); + } + + return 0; +} diff --git a/showslab/Android.mk b/showslab/Android.mk new file mode 100644 index 00000000..c914a8b6 --- /dev/null +++ b/showslab/Android.mk @@ -0,0 +1,15 @@ +# Copyright 2007 The Android Open Source Project + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= showslab.c +LOCAL_SHARED_LIBRARIES := +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) + +LOCAL_MODULE_TAGS := debug + +LOCAL_MODULE:= showslab + +include $(BUILD_EXECUTABLE) + diff --git a/showslab/MODULE_LICENSE_APACHE2 b/showslab/MODULE_LICENSE_APACHE2 new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/showslab/MODULE_LICENSE_APACHE2 diff --git a/showslab/NOTICE b/showslab/NOTICE new file mode 100644 index 00000000..c5b1efa7 --- /dev/null +++ b/showslab/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/showslab/showslab.c b/showslab/showslab.c new file mode 100644 index 00000000..9c9e60eb --- /dev/null +++ b/showslab/showslab.c @@ -0,0 +1,351 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <ctype.h> +#include <limits.h> + +#define STRINGIFY_ARG(a) #a +#define STRINGIFY(a) STRINGIFY_ARG(a) + +#define DEF_SORT_FUNC sort_nr_objs +#define SLABINFO_LINE_LEN 512 /* size of longest line */ +#define SLABINFO_NAME_LEN 32 /* cache name size (will truncate) */ +#define SLABINFO_FILE "/proc/slabinfo" +#define DEF_NR_ROWS 15 /* default nr of caches to show */ + +/* object representing a slab cache (each line of slabinfo) */ +struct slab_info { + char name[SLABINFO_NAME_LEN]; /* name of this cache */ + struct slab_info *next; + unsigned long nr_pages; /* size of cache in pages */ + unsigned long nr_objs; /* number of objects in this cache */ + unsigned long nr_active_objs; /* number of active objects */ + unsigned long obj_size; /* size of each object */ + unsigned long objs_per_slab; /* number of objects per slab */ + unsigned long nr_slabs; /* number of slabs in this cache */ + unsigned long use; /* percent full: total / active */ +}; + +/* object representing system-wide statistics */ +struct slab_stat { + unsigned long total_size; /* size of all objects */ + unsigned long active_size; /* size of all active objects */ + unsigned long nr_objs; /* total number of objects */ + unsigned long nr_active_objs; /* total number of active objects */ + unsigned long nr_slabs; /* total number of slabs */ + unsigned long nr_active_slabs; /* total number of active slabs*/ + unsigned long nr_caches; /* number of caches */ + unsigned long nr_active_caches; /* number of active caches */ + unsigned long avg_obj_size; /* average object size */ + unsigned long min_obj_size; /* size of smallest object */ + unsigned long max_obj_size; /* size of largest object */ +}; + +typedef int (*sort_t)(const struct slab_info *, const struct slab_info *); +static sort_t sort_func; + +/* + * get_slabinfo - open, read, and parse a slabinfo 2.x file, which has the + * following format: + * + * slabinfo - version: 2.1 + * <name> <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> + * : tunables <limit> <batchcount> <sharedfactor> + * : slabdata <active_slabs> <num_slabs> <sharedavail> + * + * Returns the head of the new list of slab_info structures, or NULL on error. + */ +static struct slab_info * get_slabinfo(struct slab_stat *stats) +{ + struct slab_info *head = NULL, *p = NULL, *prev = NULL; + FILE *slabfile; + char line[SLABINFO_LINE_LEN]; + unsigned int major, minor; + + slabfile = fopen(SLABINFO_FILE, "r"); + if (!slabfile) { + perror("fopen"); + return NULL; + } + + if (!fgets(line, SLABINFO_LINE_LEN, slabfile)) { + fprintf(stderr, "cannot read from " SLABINFO_FILE "\n"); + return NULL; + } + + if (sscanf(line, "slabinfo - version: %u.%u", &major, &minor) != 2) { + fprintf(stderr, "unable to parse slabinfo version!\n"); + return NULL; + } + + if (major != 2 || minor > 1) { + fprintf(stderr, "we only support slabinfo 2.0 and 2.1!\n"); + return NULL; + } + + stats->min_obj_size = INT_MAX; + + while (fgets(line, SLABINFO_LINE_LEN, slabfile)) { + unsigned long nr_active_slabs, pages_per_slab; + int ret; + + if (line[0] == '#') + continue; + + p = malloc(sizeof (struct slab_info)); + if (!p) { + perror("malloc"); + head = NULL; + break; + } + if (stats->nr_caches++ == 0) + head = prev = p; + + ret = sscanf(line, "%" STRINGIFY(SLABINFO_NAME_LEN) "s" + " %lu %lu %lu %lu %lu : tunables %*d %*d %*d : \ + slabdata %lu %lu %*d", p->name, + &p->nr_active_objs, &p->nr_objs, + &p->obj_size, &p->objs_per_slab, + &pages_per_slab, + &nr_active_slabs, + &p->nr_slabs); + + if (ret != 8) { + fprintf(stderr, "unrecognizable data in slabinfo!\n"); + head = NULL; + break; + } + + if (p->obj_size < stats->min_obj_size) + stats->min_obj_size = p->obj_size; + if (p->obj_size > stats->max_obj_size) + stats->max_obj_size = p->obj_size; + + p->nr_pages = p->nr_slabs * pages_per_slab; + + if (p->nr_objs) { + p->use = 100 * p->nr_active_objs / p->nr_objs; + stats->nr_active_caches++; + } else + p->use = 0; + + stats->nr_objs += p->nr_objs; + stats->nr_active_objs += p->nr_active_objs; + stats->total_size += p->nr_objs * p->obj_size; + stats->active_size += p->nr_active_objs * p->obj_size; + stats->nr_slabs += p->nr_slabs; + stats->nr_active_slabs += nr_active_slabs; + + prev->next = p; + prev = p; + } + + if (fclose(slabfile)) + perror("fclose"); + + if (p) + p->next = NULL; + if (stats->nr_objs) + stats->avg_obj_size = stats->total_size / stats->nr_objs; + + return head; +} + +/* + * free_slablist - deallocate the memory associated with each node in the + * provided slab_info linked list + */ +static void free_slablist(struct slab_info *list) +{ + while (list) { + struct slab_info *temp = list->next; + free(list); + list = temp; + } +} + +static struct slab_info *merge_objs(struct slab_info *a, struct slab_info *b) +{ + struct slab_info list; + struct slab_info *p = &list; + + while (a && b) { + if (sort_func(a, b)) { + p->next = a; + p = a; + a = a->next; + } else { + p->next = b; + p = b; + b = b->next; + } + } + + p->next = (a == NULL) ? b : a; + return list.next; +} + +/* + * slabsort - merge sort the slab_info linked list based on sort_func + */ +static struct slab_info *slabsort(struct slab_info *list) +{ + struct slab_info *a, *b; + + if (!list || !list->next) + return list; + + a = list; + b = list->next; + + while (b && b->next) { + list = list->next; + b = b->next->next; + } + + b = list->next; + list->next = NULL; + + return merge_objs(slabsort(a), slabsort(b)); +} + +/* + * Sort Routines. Each of these should be associated with a command-line + * search option. The functions should fit the prototype: + * + * int sort_foo(const struct slab_info *a, const struct slab_info *b) + * + * They return zero if the first parameter is smaller than the second. + * Otherwise, they return nonzero. + */ + +static int sort_name(const struct slab_info *a, const struct slab_info *b) +{ + return (strcmp(a->name, b->name) < 0 ) ? 1: 0; +} + +#define BUILD_SORT_FUNC(VAL) \ + static int sort_ ## VAL \ + (const struct slab_info *a, const struct slab_info *b) { \ + return (a-> VAL > b-> VAL); } + +BUILD_SORT_FUNC(nr_objs) +BUILD_SORT_FUNC(nr_active_objs) +BUILD_SORT_FUNC(obj_size) +BUILD_SORT_FUNC(objs_per_slab) +BUILD_SORT_FUNC(nr_slabs) +BUILD_SORT_FUNC(use) +BUILD_SORT_FUNC(nr_pages) + +/* + * set_sort_func - return the slab_sort_func that matches the given key. + * On unrecognizable key, the call returns NULL. + */ +static void * set_sort_func(char key) +{ + switch (tolower(key)) { + case 'a': + return sort_nr_active_objs; + case 'c': + return sort_nr_pages; + case 'l': + return sort_nr_slabs; + case 'n': + return sort_name; + case 'o': + return sort_nr_objs; + case 'p': + return sort_objs_per_slab; + case 's': + return sort_obj_size; + case 'u': + return sort_use; + default: + return NULL; + } +} + +int main(int argc, char *argv[]) +{ + struct slab_info *list, *p; + struct slab_stat stats = { .nr_objs = 0 }; + unsigned int page_size = getpagesize() / 1024, nr_rows = DEF_NR_ROWS, i; + + sort_func = DEF_SORT_FUNC; + + if (argc > 1) { + /* FIXME: Ugh. */ + if (argc == 3 && !strcmp(argv[1], "-n")) { + errno = 0; + nr_rows = (unsigned int) strtoul(argv[2], NULL, 0); + if (errno) { + perror("strtoul"); + exit(EXIT_FAILURE); + } + } + else if (argc == 3 && !strcmp(argv[1], "-s")) + sort_func = set_sort_func(argv[2][0]) ? : DEF_SORT_FUNC; + else { + fprintf(stderr, "usage: %s [options]\n\n", argv[0]); + fprintf(stderr, "options:\n"); + fprintf(stderr, " -s S specify sort criteria S\n"); + fprintf(stderr, " -h display this help\n\n"); + fprintf(stderr, "Valid sort criteria:\n"); + fprintf(stderr, " a: number of Active objects\n"); + fprintf(stderr, " c: Cache size\n"); + fprintf(stderr, " l: number of sLabs\n"); + fprintf(stderr, " n: Name\n"); + fprintf(stderr, " o: number of Objects\n"); + fprintf(stderr, " p: objects Per slab\n"); + fprintf(stderr, " s: object Size\n"); + fprintf(stderr, " u: cache Utilization\n"); + exit(EXIT_FAILURE); + } + } + + list = get_slabinfo (&stats); + if (!list) + exit(EXIT_FAILURE); + + printf(" Active / Total Objects (%% used) : %lu / %lu (%.1f%%)\n" + " Active / Total Slabs (%% used) : %lu / %lu (%.1f%%)\n" + " Active / Total Caches (%% used) : %lu / %lu (%.1f%%)\n" + " Active / Total Size (%% used) : %.2fK / %.2fK (%.1f%%)\n" + " Min / Avg / Max Object Size : %.2fK / %.2fK / %.2fK\n\n", + stats.nr_active_objs, + stats.nr_objs, + 100.0 * stats.nr_active_objs / stats.nr_objs, + stats.nr_active_slabs, + stats.nr_slabs, + 100.0 * stats.nr_active_slabs / stats.nr_slabs, + stats.nr_active_caches, + stats.nr_caches, + 100.0 * stats.nr_active_caches / stats.nr_caches, + stats.active_size / 1024.0, + stats.total_size / 1024.0, + 100.0 * stats.active_size / stats.total_size, + stats.min_obj_size / 1024.0, + stats.avg_obj_size / 1024.0, + stats.max_obj_size / 1024.0); + + printf("%6s %6s %4s %8s %6s %8s %10s %-23s\n", + "OBJS", "ACTIVE", "USE", "OBJ SIZE", "SLABS", + "OBJ/SLAB", "CACHE SIZE", "NAME"); + + p = list = slabsort(list); + for (i = 0; i < nr_rows && p; i++) { + printf("%6lu %6lu %3lu%% %7.2fK %6lu %8lu %9luK %-23s\n", + p->nr_objs, p->nr_active_objs, p->use, + p->obj_size / 1024.0, p->nr_slabs, + p->objs_per_slab, + p->nr_pages * page_size, + p->name); + p = p->next; + } + + free_slablist(list); + + return 0; +} diff --git a/sound/Android.mk b/sound/Android.mk new file mode 100644 index 00000000..7a58998b --- /dev/null +++ b/sound/Android.mk @@ -0,0 +1,8 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := sound +LOCAL_SRC_FILES := playwav.c +LOCAL_MODULE_TAGS := tests +include $(BUILD_EXECUTABLE) + diff --git a/sound/playwav.c b/sound/playwav.c new file mode 100644 index 00000000..6d6bce75 --- /dev/null +++ b/sound/playwav.c @@ -0,0 +1,376 @@ +/* Copyright (C) 2008 The Android Open Source Project + */ + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <stdint.h> +#include <sys/mman.h> +#include <sys/ioctl.h> + +#include <linux/ioctl.h> + +#define AUDIO_IOCTL_MAGIC 'a' + +#define AUDIO_START _IOW(AUDIO_IOCTL_MAGIC, 0, unsigned) +#define AUDIO_STOP _IOW(AUDIO_IOCTL_MAGIC, 1, unsigned) +#define AUDIO_FLUSH _IOW(AUDIO_IOCTL_MAGIC, 2, unsigned) +#define AUDIO_GET_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 3, unsigned) +#define AUDIO_SET_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 4, unsigned) +#define AUDIO_GET_STATS _IOR(AUDIO_IOCTL_MAGIC, 5, unsigned) + +struct msm_audio_config { + uint32_t buffer_size; + uint32_t buffer_count; + uint32_t channel_count; + uint32_t sample_rate; + uint32_t codec_type; + uint32_t unused[3]; +}; + +struct msm_audio_stats { + uint32_t out_bytes; + uint32_t unused[3]; +}; + +int pcm_play(unsigned rate, unsigned channels, + int (*fill)(void *buf, unsigned sz, void *cookie), + void *cookie) +{ + struct msm_audio_config config; + struct msm_audio_stats stats; + unsigned sz, n; + char buf[8192]; + int afd; + + afd = open("/dev/msm_pcm_out", O_RDWR); + if (afd < 0) { + perror("pcm_play: cannot open audio device"); + return -1; + } + + if(ioctl(afd, AUDIO_GET_CONFIG, &config)) { + perror("could not get config"); + return -1; + } + + config.channel_count = channels; + config.sample_rate = rate; + if (ioctl(afd, AUDIO_SET_CONFIG, &config)) { + perror("could not set config"); + return -1; + } + sz = config.buffer_size; + if (sz > sizeof(buf)) { + fprintf(stderr,"too big\n"); + return -1; + } + + fprintf(stderr,"prefill\n"); + for (n = 0; n < config.buffer_count; n++) { + if (fill(buf, sz, cookie)) + break; + if (write(afd, buf, sz) != sz) + break; + } + + fprintf(stderr,"start\n"); + ioctl(afd, AUDIO_START, 0); + + for (;;) { +#if 0 + if (ioctl(afd, AUDIO_GET_STATS, &stats) == 0) + fprintf(stderr,"%10d\n", stats.out_bytes); +#endif + if (fill(buf, sz, cookie)) + break; + if (write(afd, buf, sz) != sz) + break; + } + +done: + close(afd); + return 0; +} + +/* http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */ + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +#define FORMAT_PCM 1 + +struct wav_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t riff_fmt; + uint32_t fmt_id; + uint32_t fmt_sz; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */ + uint16_t block_align; /* num_channels * bps / 8 */ + uint16_t bits_per_sample; + uint32_t data_id; + uint32_t data_sz; +}; + + +static char *next; +static unsigned avail; + +int fill_buffer(void *buf, unsigned sz, void *cookie) +{ + if (sz > avail) + return -1; + memcpy(buf, next, sz); + next += sz; + avail -= sz; + return 0; +} + +void play_file(unsigned rate, unsigned channels, + int fd, unsigned count) +{ + next = malloc(count); + if (!next) { + fprintf(stderr,"could not allocate %d bytes\n", count); + return; + } + if (read(fd, next, count) != count) { + fprintf(stderr,"could not read %d bytes\n", count); + return; + } + avail = count; + pcm_play(rate, channels, fill_buffer, 0); +} + +int wav_play(const char *fn) +{ + struct wav_header hdr; + unsigned rate, channels; + int fd; + fd = open(fn, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "playwav: cannot open '%s'\n", fn); + return -1; + } + if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + fprintf(stderr, "playwav: cannot read header\n"); + return -1; + } + fprintf(stderr,"playwav: %d ch, %d hz, %d bit, %s\n", + hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample, + hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown"); + + if ((hdr.riff_id != ID_RIFF) || + (hdr.riff_fmt != ID_WAVE) || + (hdr.fmt_id != ID_FMT)) { + fprintf(stderr, "playwav: '%s' is not a riff/wave file\n", fn); + return -1; + } + if ((hdr.audio_format != FORMAT_PCM) || + (hdr.fmt_sz != 16)) { + fprintf(stderr, "playwav: '%s' is not pcm format\n", fn); + return -1; + } + if (hdr.bits_per_sample != 16) { + fprintf(stderr, "playwav: '%s' is not 16bit per sample\n", fn); + return -1; + } + + play_file(hdr.sample_rate, hdr.num_channels, + fd, hdr.data_sz); + + return 0; +} + +int wav_rec(const char *fn, unsigned channels, unsigned rate) +{ + struct wav_header hdr; + unsigned char buf[8192]; + struct msm_audio_config cfg; + unsigned sz, n; + int fd, afd; + unsigned total = 0; + unsigned char tmp; + + hdr.riff_id = ID_RIFF; + hdr.riff_sz = 0; + hdr.riff_fmt = ID_WAVE; + hdr.fmt_id = ID_FMT; + hdr.fmt_sz = 16; + hdr.audio_format = FORMAT_PCM; + hdr.num_channels = channels; + hdr.sample_rate = rate; + hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2; + hdr.block_align = hdr.num_channels * 2; + hdr.bits_per_sample = 16; + hdr.data_id = ID_DATA; + hdr.data_sz = 0; + + fd = open(fn, O_CREAT | O_RDWR, 0666); + if (fd < 0) { + perror("cannot open output file"); + return -1; + } + write(fd, &hdr, sizeof(hdr)); + + afd = open("/dev/msm_pcm_in", O_RDWR); + if (afd < 0) { + perror("cannot open msm_pcm_in"); + close(fd); + return -1; + } + + /* config change should be a read-modify-write operation */ + if (ioctl(afd, AUDIO_GET_CONFIG, &cfg)) { + perror("cannot read audio config"); + goto fail; + } + + cfg.channel_count = hdr.num_channels; + cfg.sample_rate = hdr.sample_rate; + if (ioctl(afd, AUDIO_SET_CONFIG, &cfg)) { + perror("cannot write audio config"); + goto fail; + } + + if (ioctl(afd, AUDIO_GET_CONFIG, &cfg)) { + perror("cannot read audio config"); + goto fail; + } + + sz = cfg.buffer_size; + fprintf(stderr,"buffer size %d x %d\n", sz, cfg.buffer_count); + if (sz > sizeof(buf)) { + fprintf(stderr,"buffer size %d too large\n", sz); + goto fail; + } + + if (ioctl(afd, AUDIO_START, 0)) { + perror("cannot start audio"); + goto fail; + } + + fcntl(0, F_SETFL, O_NONBLOCK); + fprintf(stderr,"\n*** RECORDING * HIT ENTER TO STOP ***\n"); + + for (;;) { + while (read(0, &tmp, 1) == 1) { + if ((tmp == 13) || (tmp == 10)) goto done; + } + if (read(afd, buf, sz) != sz) { + perror("cannot read buffer"); + goto fail; + } + if (write(fd, buf, sz) != sz) { + perror("cannot write buffer"); + goto fail; + } + total += sz; + + } +done: + close(afd); + + /* update lengths in header */ + hdr.data_sz = total; + hdr.riff_sz = total + 8 + 16 + 8; + lseek(fd, 0, SEEK_SET); + write(fd, &hdr, sizeof(hdr)); + close(fd); + return 0; + +fail: + close(afd); + close(fd); + unlink(fn); + return -1; +} + +int mp3_play(const char *fn) +{ + char buf[64*1024]; + int r; + int fd, afd; + + fd = open(fn, O_RDONLY); + if (fd < 0) { + perror("cannot open mp3 file"); + return -1; + } + + afd = open("/dev/msm_mp3", O_RDWR); + if (afd < 0) { + close(fd); + perror("cannot open mp3 output device"); + return -1; + } + + fprintf(stderr,"MP3 PLAY\n"); + ioctl(afd, AUDIO_START, 0); + + for (;;) { + r = read(fd, buf, 64*1024); + if (r <= 0) break; + r = write(afd, buf, r); + if (r < 0) break; + } + + close(fd); + close(afd); +} + +int main(int argc, char **argv) +{ + const char *fn = 0; + int play = 1; + unsigned channels = 1; + unsigned rate = 44100; + + argc--; + argv++; + while (argc > 0) { + if (!strcmp(argv[0],"-rec")) { + play = 0; + } else if (!strcmp(argv[0],"-play")) { + play = 1; + } else if (!strcmp(argv[0],"-stereo")) { + channels = 2; + } else if (!strcmp(argv[0],"-mono")) { + channels = 1; + } else if (!strcmp(argv[0],"-rate")) { + argc--; + argv++; + if (argc == 0) { + fprintf(stderr,"playwav: -rate requires a parameter\n"); + return -1; + } + rate = atoi(argv[0]); + } else { + fn = argv[0]; + } + argc--; + argv++; + } + + if (fn == 0) { + fn = play ? "/data/out.wav" : "/data/rec.wav"; + } + + if (play) { + const char *dot = strrchr(fn, '.'); + if (dot && !strcmp(dot,".mp3")) { + return mp3_play(fn); + } else { + return wav_play(fn); + } + } else { + return wav_rec(fn, channels, rate); + } + return 0; +} diff --git a/su/Android.mk b/su/Android.mk new file mode 100644 index 00000000..dd412d59 --- /dev/null +++ b/su/Android.mk @@ -0,0 +1,15 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= su.c + +LOCAL_MODULE:= su + +LOCAL_FORCE_STATIC_EXECUTABLE := true + +LOCAL_STATIC_LIBRARIES := libc + +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) +LOCAL_MODULE_TAGS := debug tests + +include $(BUILD_EXECUTABLE) diff --git a/su/MODULE_LICENSE_APACHE2 b/su/MODULE_LICENSE_APACHE2 new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/su/MODULE_LICENSE_APACHE2 diff --git a/su/NOTICE b/su/NOTICE new file mode 100644 index 00000000..c5b1efa7 --- /dev/null +++ b/su/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/su/su.c b/su/su.c new file mode 100644 index 00000000..aac981ea --- /dev/null +++ b/su/su.c @@ -0,0 +1,86 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> + +#include <unistd.h> +#include <time.h> + +#include <pwd.h> + +/* + * SU can be given a specific command to exec. UID _must_ be + * specified for this (ie argc => 3). Full path of file must be specified. + * + * Usage: + * su 1000 + * su 1000 /system/bin/ls -l + */ +int main(int argc, char **argv) +{ + struct passwd *pw; + int uid, gid; + + if(argc < 2) { + uid = gid = 0; + } else { + pw = getpwnam(argv[1]); + + if(pw == 0) { + uid = gid = atoi(argv[1]); + } else { + uid = pw->pw_uid; + gid = pw->pw_gid; + } + } + + if(setgid(gid) || setuid(uid)) { + fprintf(stderr,"su: permission denied\n"); + return 1; + } + + /* User specified command for exec. */ + if (argc == 3 ) { + if (execlp(argv[2], argv[2], NULL) < 0) { + fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2], + strerror(errno)); + return -errno; + } + } else if (argc > 3) { + /* Copy the rest of the args from main. */ + char *exec_args[argc - 1]; + memset(exec_args, 0, sizeof(exec_args)); + memcpy(exec_args, &argv[2], sizeof(exec_args)); + if (execv(argv[2], exec_args) < 0) { + fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2], + strerror(errno)); + return -errno; + } + } + + /* Default exec shell. */ + execlp("/system/bin/sh", "sh", NULL); + + fprintf(stderr, "su: exec failed\n"); + return 1; +} + diff --git a/tests/Android.mk b/tests/Android.mk new file mode 100644 index 00000000..582ddc90 --- /dev/null +++ b/tests/Android.mk @@ -0,0 +1,3 @@ +ifeq ($(TARGET_ARCH),arm) +include $(call all-subdir-makefiles) +endif diff --git a/tests/cpueater/Android.mk b/tests/cpueater/Android.mk new file mode 100644 index 00000000..88e3cd83 --- /dev/null +++ b/tests/cpueater/Android.mk @@ -0,0 +1,24 @@ +# Copyright (C) 2008 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Copyright The Android Open Source Project + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := cpueater +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) +LOCAL_MODULE_TAGS := tests eng +LOCAL_SRC_FILES := cpueater.c +include $(BUILD_EXECUTABLE) + diff --git a/tests/cpueater/cpueater.c b/tests/cpueater/cpueater.c new file mode 100644 index 00000000..b7d69ff9 --- /dev/null +++ b/tests/cpueater/cpueater.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Simple cpu eater busy loop. Runs as a daemon. prints the child PID to + * std so you can easily kill it later. + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> + + +int main(int argc, char *argv[]) +{ + pid_t pid; + int life_universe_and_everything; + int fd; + + switch(fork()) { + case -1: + perror(argv[0]); + exit(1); + break; + case 0: /* child */ + chdir("/"); + umask(0); + setpgrp(); + setsid(); + /* fork again to fully detach from controlling terminal. */ + switch(pid = fork()) { + case -1: + break; + case 0: /* second child */ + /* redirect to /dev/null */ + close(0); + open("/dev/null", 0); + close(1); + if(open("/dev/null", O_WRONLY) < 0) { + perror("/dev/null"); + exit(1); + } + fflush(stdout); + close(2); + dup(1); + for (fd = 3; fd < 256; fd++) { + close(fd); + } + /* busy looper */ + while (1) { + life_universe_and_everything = 42 * 2; + } + default: + /* so caller can easily kill it later. */ + printf("%d\n", pid); + exit(0); + break; + } + break; + default: + exit(0); + break; + } +} + + +/* vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab */ + diff --git a/tests/fstest/Android.mk b/tests/fstest/Android.mk new file mode 100644 index 00000000..bf4f17c3 --- /dev/null +++ b/tests/fstest/Android.mk @@ -0,0 +1,43 @@ +# Copyright (C) 2008 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := perm_checker.c + +LOCAL_SHARED_LIBRARIES := libc + +LOCAL_MODULE := perm_checker + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_EXECUTABLE) + +#### + +include $(CLEAR_VARS) + +LOCAL_MODULE := perm_checker.conf + +LOCAL_MODULE_TAGS := tests + +LOCAL_MODULE_CLASS := ETC + +LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/ + +LOCAL_SRC_FILES := $(LOCAL_MODULE) + +include $(BUILD_PREBUILT) diff --git a/tests/fstest/README b/tests/fstest/README new file mode 100644 index 00000000..e4f8194c --- /dev/null +++ b/tests/fstest/README @@ -0,0 +1,68 @@ +All files and directories will be matched against entries taken from +/etc/perm_checker.conf, and any file/directory which fails the ruleset +will cause an error message along with a corresponding explicit (fully +specified and minimal) rule for that file/directory to be printed on +stdout. If only the message "Passed." is printed on stdout, all files are +correctly matched by perm_checker.conf. + +A file or directory will always fail the ruleset unless there is AT LEAST +one matching rule. If there is an explicit (fully specified) <spec> +matching the file or directory name, it will fail if and only if that +explicit <spec> rule fails (i.e., other matching <spec> rules will be +ignored). Otherwise, it will fail if _any_ matching wildcard or recursive +<spec> rule fails to hold. + +Entries in the perm_checker.conf file are of the following form: + +<spec> <min_mode> <max_mode> <min_uid> <max_uid> <min_gid> <max_gid> + +Where <spec> is one of the following: + +A fully specified path name, which must end in / ex: /dev/ +A fully specified filename, symlink, device node, etc. ex: /dev/tty0 + +A recursive path specification, which ends in /... ex: /dev/... +A wildcard file specification, which ends in * ex: /dev/tty* + +By convention /dev/* will include all files directly in /dev/, but not files +that are in subdirectories of /dev/, such as /dev/input/, unlike a +recursive path specification. The wildcard notation * will never result in +a match to a directory name. + +NOTE: Symbolic links are treated specially to prevent infinite recursion +and simplify the ruleset. Symbolic links are ignored unless an explicit +rule with the same name as the symlink exists, in which case the permissions +on the rule must match the permissions on the symlink itself, not the target. + +<min_mode> is a numeric mode mask, and a mode will match it if and only if +(min_mode & mode) == min_mode. + +<max_mode> is a numeric mode mask, and a mode will match it if and only if +(max_mode | mode) == max_mode. + +<min_uid> may be either a numeric user id, or a user name (which must not +start with a number). If it is a user name, getpwnam() will be used to +translate it to a numeric user id. + +<max_uid>, <min_gid>, and <max_gid> have similar syntax to <min_uid>. + + +-- Tips -- + +I recommend to use 19999 as the maximum uid/gid whenever any valid +application uid/gid is acceptable. + +Once the test is installed, it can be executed via: + +adb shell perm_checker + +To get a list of all failing rules: + +adb shell perm_checker | grep "^# INFO #" | sort | uniq + +To get a fully specified set of rules for all failing files: + +adb shell perm_checker | grep -v "^#" + +NOTE: There may be failing files even if no rules have failed, since a +file that does not match any rule is a failure. diff --git a/tests/fstest/perm_checker.c b/tests/fstest/perm_checker.c new file mode 100644 index 00000000..5cead10b --- /dev/null +++ b/tests/fstest/perm_checker.c @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// A simple file permissions checker. See associated README. + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> + +#include <sys/stat.h> +#include <unistd.h> +#include <time.h> + +#include <pwd.h> +#include <grp.h> + +#include <linux/kdev_t.h> + +#define PERMS(M) (M & ~S_IFMT) +#define MAX_NAME_LEN 4096 +#define MAX_UID_LEN 256 +#define MAX_GID_LEN MAX_UID_LEN + +enum perm_rule_type {EXACT_FILE = 0, EXACT_DIR, WILDCARD, RECURSIVE, + NUM_PR_TYPES}; + +struct perm_rule { + char *rule_text; + int rule_line; + char *spec; + mode_t min_mode; + mode_t max_mode; + uid_t min_uid; + uid_t max_uid; + gid_t min_gid; + gid_t max_gid; + enum perm_rule_type type; + struct perm_rule *next; +}; + +typedef struct perm_rule perm_rule_t; + +static perm_rule_t *rules[NUM_PR_TYPES]; + +static uid_t str2uid(char *str, int line_num) +{ + struct passwd *pw; + + if (isdigit(str[0])) + return (uid_t) atol(str); + + if (!(pw = getpwnam(str))) { + printf("# ERROR # Invalid uid '%s' reading line %d\n", str, line_num); + exit(255); + } + return pw->pw_uid; +} + +static gid_t str2gid(char *str, int line_num) +{ + struct group *gr; + + if (isdigit(str[0])) + return (uid_t) atol(str); + + if (!(gr = getgrnam(str))) { + printf("# ERROR # Invalid gid '%s' reading line %d\n", str, line_num); + exit(255); + } + return gr->gr_gid; +} + +static int read_rules(FILE *fp) +{ + char spec[MAX_NAME_LEN + 5]; // Allows for "/..." suffix + terminator + char min_uid_buf[MAX_UID_LEN + 1], max_uid_buf[MAX_UID_LEN + 1]; + char min_gid_buf[MAX_GID_LEN + 1], max_gid_buf[MAX_GID_LEN + 1]; + char rule_text_buf[MAX_NAME_LEN + 2*MAX_UID_LEN + 2*MAX_GID_LEN + 9]; + unsigned long min_mode, max_mode; + perm_rule_t *pr; + int res; + int num_rules = 0, num_lines = 0; + + // Note: Use of an unsafe C function here is OK, since this is a test + while ((res = fscanf(fp, "%s %lo %lo %s %s %s %s\n", spec, + &min_mode, &max_mode, min_uid_buf, max_uid_buf, + min_gid_buf, max_gid_buf)) != EOF) { + num_lines++; + if (res < 7) { + printf("# WARNING # Invalid rule on line number %d\n", num_lines); + continue; + } + if (!(pr = malloc(sizeof(perm_rule_t)))) { + printf("Out of memory.\n"); + exit(255); + } + if (snprintf(rule_text_buf, sizeof(rule_text_buf), + "%s %lo %lo %s %s %s %s", spec, min_mode, max_mode, + min_uid_buf, max_uid_buf, min_gid_buf, max_gid_buf) + >= (long int) sizeof(rule_text_buf)) { + // This should never happen, but just in case... + printf("# ERROR # Maximum length limits exceeded on line %d\n", + num_lines); + exit(255); + } + pr->rule_text = strndup(rule_text_buf, sizeof(rule_text_buf)); + pr->rule_line = num_lines; + if (strstr(spec, "/...")) { + pr->spec = strndup(spec, strlen(spec) - 3); + pr->type = RECURSIVE; + } else if (spec[strlen(spec) - 1] == '*') { + pr->spec = strndup(spec, strlen(spec) - 1); + pr->type = WILDCARD; + } else if (spec[strlen(spec) - 1] == '/') { + pr->spec = strdup(spec); + pr->type = EXACT_DIR; + } else { + pr->spec = strdup(spec); + pr->type = EXACT_FILE; + } + if ((pr->spec == NULL) || (pr->rule_text == NULL)) { + printf("Out of memory.\n"); + exit(255); + } + pr->min_mode = min_mode; + pr->max_mode = max_mode; + pr->min_uid = str2uid(min_uid_buf, num_lines); + pr->max_uid = str2uid(max_uid_buf, num_lines); + pr->min_gid = str2gid(min_gid_buf, num_lines); + pr->max_gid = str2gid(max_gid_buf, num_lines); + + // Add the rule to the appropriate set + pr->next = rules[pr->type]; + rules[pr->type] = pr; + num_rules++; +#if 0 // Useful for debugging + printf("rule #%d: type = %d spec = %s min_mode = %o max_mode = %o " + "min_uid = %d max_uid = %d min_gid = %d max_gid = %d\n", + num_rules, pr->type, pr->spec, pr->min_mode, pr->max_mode, + pr->min_uid, pr->max_uid, pr->min_gid, pr->max_gid); +#endif + } + return num_lines - num_rules; +} + +static void print_failed_rule(const perm_rule_t *pr) +{ + printf("# INFO # Failed rule #%d: %s\n", pr->rule_line, pr->rule_text); +} + +static void print_new_rule(const char *name, mode_t mode, uid_t uid, gid_t gid) +{ + struct passwd *pw; + struct group *gr; + gr = getgrgid(gid); + pw = getpwuid(uid); + printf("%s %4o %4o %s %d %s %d\n", name, mode, mode, pw->pw_name, uid, + gr->gr_name, gid); +} + +// Returns 1 if the rule passes, prints the failure and returns 0 if not +static int pass_rule(const perm_rule_t *pr, mode_t mode, uid_t uid, gid_t gid) +{ + if (((pr->min_mode & mode) == pr->min_mode) && + ((pr->max_mode | mode) == pr->max_mode) && + (pr->min_gid <= gid) && (pr->max_gid >= gid) && + (pr->min_uid <= uid) && (pr->max_uid >= uid)) + return 1; + print_failed_rule(pr); + return 0; +} + +// Returns 0 on success +static int validate_file(const char *name, mode_t mode, uid_t uid, gid_t gid) +{ + perm_rule_t *pr; + int rules_matched = 0; + int retval = 0; + + pr = rules[EXACT_FILE]; + while (pr != NULL) { + if (strcmp(name, pr->spec) == 0) { + if (!pass_rule(pr, mode, uid, gid)) + retval++; + else + rules_matched++; // Exact match found + } + pr = pr->next; + } + + if ((retval + rules_matched) > 1) + printf("# WARNING # Multiple exact rules for file: %s\n", name); + + // If any exact rule matched or failed, we are done with this file + if (retval) + print_new_rule(name, mode, uid, gid); + if (rules_matched || retval) + return retval; + + pr = rules[WILDCARD]; + while (pr != NULL) { + // Check if the spec is a prefix of the filename, and that the file + // is actually in the same directory as the wildcard. + if ((strstr(name, pr->spec) == name) && + (!strchr(name + strlen(pr->spec), '/'))) { + if (!pass_rule(pr, mode, uid, gid)) + retval++; + else + rules_matched++; + } + pr = pr->next; + } + + pr = rules[RECURSIVE]; + while (pr != NULL) { + if (strstr(name, pr->spec) == name) { + if (!pass_rule(pr, mode, uid, gid)) + retval++; + else + rules_matched++; + } + pr = pr->next; + } + + if (!rules_matched) + retval++; // In case no rules either matched or failed, be sure to fail + + if (retval) + print_new_rule(name, mode, uid, gid); + + return retval; +} + +// Returns 0 on success +static int validate_link(const char *name, mode_t mode, uid_t uid, gid_t gid) +{ + perm_rule_t *pr; + int rules_matched = 0; + int retval = 0; + + // For now, we match links against "exact" file rules only + pr = rules[EXACT_FILE]; + while (pr != NULL) { + if (strcmp(name, pr->spec) == 0) { + if (!pass_rule(pr, mode, uid, gid)) + retval++; + else + rules_matched++; // Exact match found + } + pr = pr->next; + } + + if ((retval + rules_matched) > 1) + printf("# WARNING # Multiple exact rules for link: %s\n", name); + if (retval) + print_new_rule(name, mode, uid, gid); + + // Note: Unlike files, if no rules matches for links, retval = 0 (success). + return retval; +} + +// Returns 0 on success +static int validate_dir(const char *name, mode_t mode, uid_t uid, gid_t gid) +{ + perm_rule_t *pr; + int rules_matched = 0; + int retval = 0; + + pr = rules[EXACT_DIR]; + while (pr != NULL) { + if (strcmp(name, pr->spec) == 0) { + if (!pass_rule(pr, mode, uid, gid)) + retval++; + else + rules_matched++; // Exact match found + } + pr = pr->next; + } + + if ((retval + rules_matched) > 1) + printf("# WARNING # Multiple exact rules for directory: %s\n", name); + + // If any exact rule matched or failed, we are done with this directory + if (retval) + print_new_rule(name, mode, uid, gid); + if (rules_matched || retval) + return retval; + + pr = rules[RECURSIVE]; + while (pr != NULL) { + if (strstr(name, pr->spec) == name) { + if (!pass_rule(pr, mode, uid, gid)) + retval++; + else + rules_matched++; + } + pr = pr->next; + } + + if (!rules_matched) + retval++; // In case no rules either matched or failed, be sure to fail + + if (retval) + print_new_rule(name, mode, uid, gid); + + return retval; +} + +// Returns 0 on success +static int check_path(const char *name) +{ + char namebuf[MAX_NAME_LEN + 1]; + char tmp[MAX_NAME_LEN + 1]; + DIR *d; + struct dirent *de; + struct stat s; + int err; + int retval = 0; + + err = lstat(name, &s); + if (err < 0) { + if (errno != ENOENT) + { + perror(name); + return 1; + } + return 0; // File doesn't exist anymore + } + + if (S_ISDIR(s.st_mode)) { + if (name[strlen(name) - 1] != '/') + snprintf(namebuf, sizeof(namebuf), "%s/", name); + else + snprintf(namebuf, sizeof(namebuf), "%s", name); + + retval |= validate_dir(namebuf, PERMS(s.st_mode), s.st_uid, s.st_gid); + d = opendir(namebuf); + if(d == 0) { + printf("%s : opendir failed: %s\n", namebuf, strerror(errno)); + return 1; + } + + while ((de = readdir(d)) != 0) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) + continue; + snprintf(tmp, sizeof(tmp), "%s%s", namebuf, de->d_name); + retval |= check_path(tmp); + } + closedir(d); + return retval; + } else if (S_ISLNK(s.st_mode)) { + validate_link(name, PERMS(s.st_mode), s.st_uid, s.st_gid); + } else { + return validate_file(name, PERMS(s.st_mode), s.st_uid, s.st_gid); + } +} + +int main(int argc, char **argv) +{ + FILE *fp; + int i; + + // Initialize ruleset pointers + for (i = 0; i < NUM_PR_TYPES; i++) + rules[i] = NULL; + + if (!(fp = fopen("/etc/perm_checker.conf", "r"))) { + printf("Error opening /etc/perm_checker.conf\n"); + exit(255); + } + read_rules(fp); + fclose(fp); + + if (check_path("/")) + return 255; + + printf("Passed.\n"); + return 0; +} diff --git a/tests/fstest/perm_checker.conf b/tests/fstest/perm_checker.conf new file mode 100644 index 00000000..460f2e4a --- /dev/null +++ b/tests/fstest/perm_checker.conf @@ -0,0 +1,150 @@ +/ 755 755 root root root root +/* 400 755 root root root root +/cache/ 770 770 system system cache cache +/cache/... 770 770 system system cache cache +/cache/lost+found/ 700 770 root root root root +/d/ 755 755 root root root root +/d/... 000 770 root root root root +/data/ 771 771 system system system system +/data/* 000 744 system system system system +/data/anr/ 000 751 root system log log +/data/anr/... 000 662 root system log log +/data/app/ 771 771 system system system system +/data/app/... 644 664 system system system system +/data/dalvik-cache/ 750 751 root root root root +/data/dalvik-cache/... 400 744 root 19999 root 19999 +/data/data 701 771 system system system system +/data/data/... 000 775 system 19999 system 19999 +/data/testinfo/ 770 771 root system root system +/data/testinfo/* 000 664 root system root system +/data/tombstones/ 755 755 system system system system +/data/tombstones/* 000 600 system 19999 system 19999 +/data/lost+found/ 700 770 root root root root +/data/misc/ 1711 1771 root system root misc +/data/misc/akmd_set.txt 600 640 root compass compass compass +/data/misc/rild* 600 660 root radio root radio +/data/misc/hcid/ 770 770 bluetooth bluetooth bluetooth bluetooth +/data/misc/wifi/ 000 1771 system wifi system wifi +/data/misc/wifi/... 000 770 root wifi root wifi +/data/local/ 771 771 shell shell shell shell +/data/local/tmp/ 771 1771 shell shell shell shell +/data/app_private/ 700 771 system system system system +/data/system/... 000 770 system system system system +/dev/ 1777 1777 root root root root +/dev/alarm 660 660 root system root system +/dev/ashmem 666 666 root root root root +/dev/android_adb 600 600 root root root root +/dev/android_ums 640 640 mount mount mount mount +/dev/binder 666 666 root root root root +/dev/console 600 600 root root root root +/dev/full 666 666 root root root root +/dev/hw3d 660 660 system system graphics graphics +/dev/htc-acoustic 600 640 radio radio radio radio +/dev/network_throughput 600 660 root system root system +/dev/network_latency 600 660 root system root system +/dev/cpu_dma_latency 600 660 root system root system +/dev/mem 600 600 root root root root +/dev/msm_mp3 600 660 root system root audio +/dev/msm_pcm_in 660 660 system system audio audio +/dev/msm_pcm_out 660 660 system system audio audio +/dev/msm_perf 600 600 root root root root +/dev/null 666 666 root root root root +/dev/pmem_adsp 660 660 system system audio audio +/dev/pmem 660 660 system system graphics graphics +/dev/ppp 600 600 root root root root +/dev/psaux 600 600 root root root root +/dev/ptmx 666 666 root root root root +/dev/random 666 666 root root root root +/dev/smd0 640 640 radio radio radio radio +/dev/ttyMSM0 600 600 bluetooth bluetooth bluetooth bluetooth +/dev/urandom 666 666 root root root root +/dev/zero 666 666 root root root root +/dev/akm* 640 640 compass compass system system +/dev/km* 600 600 root root root root +/dev/mt9* 600 660 system system system system +/dev/pmem_gpu* 660 660 system system graphics graphics +/dev/qmi* 600 640 radio radio radio radio +/dev/rtc* 600 600 root root root root +/dev/smd* 600 600 root root root root +/dev/tty* 600 600 root root root root +/dev/vc* 600 600 root root root root +/dev/adsp/ 750 755 root root root root +/dev/adsp/* 660 660 system system audio audio +/dev/block/ 750 775 root root root root +/dev/block/* 600 600 root root root root +/dev/graphics/ 755 755 root root root root +/dev/graphics/* 660 660 root root graphics graphics +/dev/input/ 755 755 root root root root +/dev/input/* 660 660 root root input input +/dev/log/ 755 755 root root root root +/dev/log/* 662 662 root root log log +/dev/oncrpc/ 755 755 root root root root +/dev/oncrpc/... 000 660 root camera root camera +/dev/pts/ 755 755 root root root root +/dev/pts/* 600 600 root system root system +/dev/mtd/ 750 775 root root root root +/dev/mtd/* 600 600 root root root root +/dev/socket/ 750 755 root system root system +/dev/socket/dbus 660 660 root bluetooth bluetooth bluetooth +/dev/socket/installd 600 660 system system system system +/dev/socket/mountd 660 660 root mount root mount +/dev/socket/property_service 666 666 root system root system +/dev/socket/rild 660 660 root radio radio radio +/dev/socket/usbd 660 660 root mount mount mount +/dev/socket/zygote 666 666 root root root root +/etc 777 777 root root root root +/proc/ 555 555 root root root root +/proc/... 000 777 root 19999 root 19999 +/proc/sys/kernel/sched_nr_migrate 000 1664 root root root root +/root/ 700 700 root root root root +/sdcard/ 000 077 system system system system +/sdcard/... 000 077 system system system system +/sbin/ 700 770 root root root root +/sbin/... 700 775 root root root root +/sys/ 755 775 root system root system +/sys/... 000 775 root system root system +/sys/android_power/acquire_full_wake_lock 664 664 radio radio system system +/sys/android_power/acquire_partial_wake_lock 664 664 radio radio system system +/sys/android_power/release_wake_lock 664 664 radio radio system system +/sys/android_power/request_state 664 664 radio radio system system +/sys/android_power/state 664 664 radio radio system system +/sys/module/board_trout/parameters/bluetooth_power_on 660 660 root bluetooth bluetooth bluetooth +/sys/qemu_trace/process_name 000 777 root system root system +/sys/qemu_trace/state 000 777 root system root system +/sys/qemu_trace/symbol 000 777 root system root system +/system/ 755 755 root root root root +/system/* 000 664 root system root system +/system/app/ 755 755 root root root root +/system/app/... 600 644 root root root root +/system/bin/... 000 755 root system root system +/system/xbin/... 000 755 root system root system +/system/etc/ 755 755 root root root root +/system/etc/... 000 664 root system root audio +/system/etc/firmware/ 700 755 root root root root +/system/etc/init.goldfish.sh 500 550 root root root root +/system/etc/init.gprs-pppd 500 550 root root root root +/system/etc/init.testmenu 500 550 root root root root +/system/etc/perm_checker.conf 000 777 root system root system +/system/etc/ppp/ 755 775 root system root system +/system/etc/ppp/chap-secrets 600 660 root system root system +/system/etc/ppp/ip-down 500 550 root system root system +/system/etc/ppp/ip-up 500 550 root system root system +/system/etc/security/ 755 755 root root root root +/system/etc/wifi/ 750 755 root system root system +/system/lib/ 755 755 root root root root +/system/lib/... 600 644 root root root root +/system/lib/modules/ 755 755 root root root root +/system/lost+found/ 700 770 root root root root +/system/fonts/ 755 755 root root root root +/system/fonts/... 644 644 root root root root +/system/framework/ 755 755 root root root root +/system/framework/... 600 644 root root root root +/system/media/ 755 755 root root root root +/system/media/... 644 644 root root root root +/system/media/audio/ 755 755 root root root root +/system/media/audio/notifications/ 755 755 root root root root +/system/media/audio/ringtones/ 755 755 root root root root +/system/sounds/ 755 755 root root root root +/system/sounds/... 644 644 root root root root +/system/usr/... 400 755 root root root root +/sqlite_stmt_journals 1777 1777 root root root root diff --git a/tests/icachetest/Android.mk b/tests/icachetest/Android.mk new file mode 100644 index 00000000..fca07ee1 --- /dev/null +++ b/tests/icachetest/Android.mk @@ -0,0 +1,14 @@ +# Copyright 2006 The Android Open Source Project + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= icache_main.c icache.S icache2.S + +LOCAL_SHARED_LIBRARIES := libc + +LOCAL_MODULE:= icache + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_EXECUTABLE) diff --git a/tests/icachetest/icache.S b/tests/icachetest/icache.S new file mode 100644 index 00000000..e5a24277 --- /dev/null +++ b/tests/icachetest/icache.S @@ -0,0 +1,180 @@ +/* + * icache.s + * + * + * Copyright 2005 The Android Open Source Project + * + */ + + .text + .global icache_test + .align + + +#define LOOP \ + subs r2, r2, #1 ; \ + mov r0, r0 ; \ + mov r0, r0 ; \ + mov r0, r0 ; \ + mov r0, r0 ; \ + mov r0, r0 ; \ + beq end_loop ; \ + mov r0, r0 ; \ + + + + /* + * r0 = loop_count + * r1 = step + */ + + .align 5 + +icache_test: + mov r0, r0 + mov r0, r0 + mov r0, r0 + mov r0, r0 + mov r0, r0 + +end_loop: + subs r0, r0, r1 + mov r2, r1 + bxmi lr + + + /* here we're aligned on a cache line */ + + /* each loop iteration is one cache line + repeat this block 2048 times... */ + + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + + b end_loop diff --git a/tests/icachetest/icache2.S b/tests/icachetest/icache2.S new file mode 100644 index 00000000..5e06dba9 --- /dev/null +++ b/tests/icachetest/icache2.S @@ -0,0 +1,170 @@ +/* + * icache.s + * + * + * Copyright 2005 The Android Open Source Project + * + */ + + .text + .align + + .global icache_test2 + +#define LOOP \ + mov r0, r0 ; \ + mov r0, r0 ; \ + mov r0, r0 ; \ + mov r0, r0 ; \ + mov r0, r0 ; \ + mov r0, r0 ; \ + mov r0, r0 ; \ + mov r0, r0 ; + + + /* + * r0 = loop_count + * r1 = step + * r2 = mask + */ + +icache_test2: +end_loop: + + /* each loop iteration is one cache line + repeat this block 2048 times... */ + + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP LOOP + + subs r0, r0, #1 + bgt end_loop + bx lr + + diff --git a/tests/icachetest/icache_main.c b/tests/icachetest/icache_main.c new file mode 100644 index 00000000..93f36d47 --- /dev/null +++ b/tests/icachetest/icache_main.c @@ -0,0 +1,34 @@ +#include <stdio.h> +#include <sys/time.h> + +extern void icache_test(long count, long step); +extern void icache_test2(long count); + +int main() +{ + printf("[bytes]\t[us]\n"); + + struct timeval now, tm; + long long t; + long MBs; + long i; + long step = 32; + for (i=0 ; step<=2048 ; i++, step+=32) + { + long value; + gettimeofday(&now, 0); + icache_test(0x800000L, step); + gettimeofday(&tm, 0); + t = (tm.tv_sec*1000000LL+tm.tv_usec) - (now.tv_sec*1000000LL+now.tv_usec); + printf("%6ld\t%lld\n", step*32, t); + } + + gettimeofday(&now, 0); + icache_test2(0x800000L / 2048); + gettimeofday(&tm, 0); + t = (tm.tv_sec*1000000LL+tm.tv_usec) - (now.tv_sec*1000000LL+now.tv_usec); + MBs = (8388608LL*32*1000000) / (t * (1024*1024)); + printf("\n%6lld us\t%ld MB/s\n", t, MBs); + + return 0; +} diff --git a/tests/memtest/Android.mk b/tests/memtest/Android.mk new file mode 100644 index 00000000..d0500b23 --- /dev/null +++ b/tests/memtest/Android.mk @@ -0,0 +1,20 @@ +# Copyright 2006 The Android Open Source Project + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= memtest.cpp.arm \ + thumb.cpp + + +LOCAL_SHARED_LIBRARIES := libc +#libutils libhardware + +LOCAL_MODULE:= memtest + +LOCAL_MODULE_TAGS := tests + +## LOCAL_CFLAGS += -fstack-protector-all +LOCAL_CFLAGS += -fomit-frame-pointer + +include $(BUILD_EXECUTABLE) diff --git a/tests/memtest/memtest.cpp b/tests/memtest/memtest.cpp new file mode 100644 index 00000000..d6cc9b21 --- /dev/null +++ b/tests/memtest/memtest.cpp @@ -0,0 +1,763 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <time.h> +#include <unistd.h> +#include <sched.h> +#include <sys/resource.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <sys/mman.h> + +#if 0 +const int DCACHE_SIZE = 8*1024; +const int CPU_FREQ_EST = 195; +const int BRANCH_CYCLE = 3; +#else +const int DCACHE_SIZE = 32*1024; +const int CPU_FREQ_EST = 384; +const int BRANCH_CYCLE = 2; +#endif + +typedef long long nsecs_t; + +static nsecs_t system_time() +{ + struct timespec t; + t.tv_sec = t.tv_nsec = 0; + clock_gettime(CLOCK_MONOTONIC, &t); + return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec; +} + +nsecs_t loop_overhead(size_t count) __attribute__((noinline)); +nsecs_t loop_overhead(size_t count) +{ + nsecs_t overhead = -system_time(); + do { + asm volatile ("":::"memory"); + } while (--count); + overhead += system_time(); + return overhead; +} + +static void preload(volatile char* addr, size_t s) +{ + for (size_t i=0 ; i<s ; i+=32) { + char c = addr[i]; + (void)c; + } +} + +static void usage(char* p) { + printf( "Usage: %s <test> <options>\n" + "<test> is one of the following:\n" + " cpufreq\n" + " memcpy [perf [fast] | test]\n" + " memset [perf | test]\n" + " memcmp [perf | test]\n" + " strlen [perf | test]\n" + " malloc [fill]\n" + " madvise\n" + " resampler\n" + " crash\n" + " stack (stack smasher)\n" + " crawl\n" + , p); +} + +int cpufreq_test(int argc, char** argv); +int memcpy_test(int argc, char** argv); +int memset_test(int argc, char** argv); +int memcmp_test(int argc, char** argv); +int strlen_test(int argc, char** argv); +int malloc_test(int argc, char** argv); +int madvise_test(int argc, char** argv); +int crash_test(int argc, char** argv); +int stack_smasher_test(int argc, char** argv); +int crawl_test(int argc, char** argv); + +#if 0 +#pragma mark - +#pragma mark main +#endif + +int main(int argc, char** argv) +{ + if (argc == 1) { + usage(argv[0]); + return 0; + } + int err = -1; + if (!strcmp(argv[1], "cpufreq")) err = cpufreq_test(argc-1, argv+1); + else if (!strcmp(argv[1], "memcpy")) err = memcpy_test(argc-1, argv+1); + else if (!strcmp(argv[1], "memset")) err = memset_test(argc-1, argv+1); + else if (!strcmp(argv[1], "memcmp")) err = memcmp_test(argc-1, argv+1); + else if (!strcmp(argv[1], "strlen")) err = strlen_test(argc-1, argv+1); + else if (!strcmp(argv[1], "malloc")) err = malloc_test(argc-1, argv+1); + else if (!strcmp(argv[1], "madvise")) err = madvise_test(argc-1, argv+1); + else if (!strcmp(argv[1], "crash")) err = crash_test(argc-1, argv+1); + else if (!strcmp(argv[1], "stack")) err = stack_smasher_test(argc-1, argv+1); + else if (!strcmp(argv[1], "crawl")) err = crawl_test(argc-1, argv+1); + if (err) { + usage(argv[0]); + } + return 0; +} + +#if 0 +#pragma mark - +#pragma mark memcpy +#endif + +int validate_memcpy(char* s, char* d, size_t size); +int validate_memset(char* s, char c, size_t size); + +int memcpy_test(int argc, char** argv) +{ + int option = 0; + if (argc >= 2) { + if (!strcmp(argv[1], "perf")) option = 0; + else if (!strcmp(argv[1], "test")) option = 1; + else return -1; + } + + const int MAX_SIZE = 1024*1024; // 1MB + const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 150 MB/s + const int UNCACHED_SPEED_EST = (CPU_FREQ_EST/4)*1024*1024; // 60 MB/s + char* src = (char*)malloc(MAX_SIZE+4+8+32); + char* dst = (char*)malloc(MAX_SIZE+4+8+32); + memset(src, 0, MAX_SIZE+4+8+32); + memset(dst, 0, MAX_SIZE+4+8+32); + + if (option == 0) { + bool fast = (argc>=3 && !strcmp(argv[2], "fast")); + printf("memcpy() performance test is running, please wait...\n"); + fflush(stdout); + usleep(10000); + setpriority(PRIO_PROCESS, 0, -20); + static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE }; + + struct result_t { int size; float res; }; + result_t* results = (result_t*)src; + int nbr = 0; + int size = 0; + for (int i=0 ; ; i++) { + if (!fast) { + if (size<128) size += 8; + else if (size<1024) size += 128; + else if (size<16384) size += 1024; + else size <<= 1; + } else { + if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0])) + break; + size = FAST_SIZES[i]; + } + if (size > MAX_SIZE) { + break; + } + + const int REPEAT = (((size < DCACHE_SIZE) ? + (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size) / 2; + // ~0.5 second per test + + const nsecs_t overhead = loop_overhead(REPEAT); + + // tweak to make it a bad case + char* ddd = (char*)((long(dst+31)&~31) + 4); + char* sss = (char*)((long(src+31)&~31) + 28); + + for (int offset=0 ; offset<=2 ; offset +=2 ) { + memcpy(dst, src, size); // just make sure to load the caches I/D + nsecs_t t = -system_time(); + register int count = REPEAT; + do { + memcpy(ddd, sss+offset, size); + } while (--count); + t += system_time() - overhead; + const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t); + results[nbr].size = size; + results[nbr].res = throughput; + nbr++; + } + } + + printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (nc)"); + for (int i=0 ; i<nbr ; i+=2) { + printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res); + } + } else if (option == 1) { + printf("memcpy() validation test is running, please wait...\n"); + fflush(stdout); + char* curr = (char*)src; + for (int i=0 ; i<MAX_SIZE ; i++) { + char c = rand(); + *curr++ = c != 0x55 ? c : 0xAA; + } + char* s = src + 1024; + char* d = dst + 1024; + int nb = 0; + for (int size=0 ; size<4096 && !nb ; size++) { + nb += validate_memcpy(s, d, size); + for (int o=1 ; o<32 && !nb ; o++) { + nb += validate_memcpy(s+o, d, size); + nb += validate_memcpy(s, d+o, size); + nb += validate_memcpy(s+o, d+o, size); + } + } + if (nb) printf("%d error(s) found\n", nb); + else printf("success!\n"); + } + fflush(stdout); + free(dst); + free(src); + return 0; +} + +int validate_memcpy(char* s, char* d, size_t size) +{ + int nberr = 0; + memset(d-4, 0x55, size+8); + memcpy(s, d, size); + if (memcmp(s,d,size)) { + printf("*** memcpy(%p,%p,%lu) destination != source\n",s,d,size); + nberr++; + } + bool r = (d[size]==0x55)&&(d[size+1]==0x55)&&(d[size+2]==0x55)&&(d[size+3]==0x55); + if (!r) { + printf("*** memcpy(%p,%p,%lu) clobbered past end of destination!\n",s,d,size); + nberr++; + } + r = (d[-1]==0x55)&&(d[-2]==0x55)&&(d[-3]==0x55)&&(d[-4]==0x55); + if (!r) { + printf("*** memcpy(%p,%p,%lu) clobbered before start of destination!\n",s,d,size); + nberr++; + } + return nberr; +} + + +#if 0 +#pragma mark - +#pragma mark memset +#endif + +int memset_test(int argc, char** argv) +{ + int option = 0; + if (argc >= 2) { + if (!strcmp(argv[1], "perf")) option = 0; + else if (!strcmp(argv[1], "test")) option = 1; + else return -1; + } + + const int MAX_SIZE = 1024*1024; // 1MB + const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s + const int UNCACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s + char* dst = (char*)malloc(MAX_SIZE+4+8); + + if (option == 0) { + printf("memset() performance test is running, please wait...\n"); + fflush(stdout); + usleep(10000); + setpriority(PRIO_PROCESS, 0, -20); + + static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE }; + const size_t FAST_SIZES_COUNT = sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]); + struct result_t { int size; float res; }; + result_t results[FAST_SIZES_COUNT*2]; + int nbr = 0; + int size = 0; + for (int i=0 ; ; i++) { + if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0])) + break; + size = FAST_SIZES[i]; + if (size > MAX_SIZE) { + break; + } + const int REPEAT = (((size < DCACHE_SIZE) ? + (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size); + // ~0.5 second per test + + const nsecs_t overhead = loop_overhead(REPEAT); + + for (int j=0 ; j<2 ; j++) { + if (j==0) preload(dst, DCACHE_SIZE*4); // flush D + else preload(dst, size); // load D + nsecs_t t = -system_time(); + size_t count = REPEAT; + do { + memset(dst, 0, size); + } while (--count); + t += system_time() - overhead; + + const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t); + results[nbr].size = size; + results[nbr].res = throughput; + nbr++; + } + } + + printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (cached)"); + for (int i=0 ; i<nbr ; i+=2) { + printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res); + } + } else if (option == 1) { + printf("memset() validation test is running, please wait...\n"); + fflush(stdout); + char* d = dst + 1024; + int nb = 0; + for (int o=1 ; o<32 ; o++) { + for (int size=0 ; size<4096 && !nb ; size++) { + nb += validate_memset(d, char(o), size); + nb += validate_memset(d+o, char(o), size); + } + } + if (nb) printf("%d error(s) found\n", nb); + else printf("success!\n"); + } + fflush(stdout); + free(dst); + return 0; +} + +int validate_memset(char* d, char c, size_t size) +{ + int nberr = 0; + for (size_t i=0; i<size ; d[i++]=0xaa) ; + d[-1] = 0x55; + d[size+1] = 0x55; + memset(d, c, size); + if (d[size+1]!=0x55) { + printf("*** memset(%p,%02x,%lu) clobbered past end of destination!\n",d,(int)c,size); + nberr++; + } + if (d[-1]!=0x55) { + printf("*** memset(%p,%02x,%lu) clobbered before start of destination!\n",d,(int)c,size); + nberr++; + } + for (size_t i=0 ; i<size ; i++) { + if (d[i] != c) { + printf("*** memset(%p,%02x,%lu) failed at offset %lu\n",d,(int)c,size, i); + nberr++; + break; + } + } + return nberr; +} + +#if 0 +#pragma mark - +#pragma mark memcmp +#endif + +static int ref_memcmp(const void *s1, const void *s2, size_t n) +{ + const unsigned char *c1 = (const unsigned char *)s1, *c2 = (const unsigned char *)s2; + int d = 0; + + while ( n-- ) { + d = (int)*c1++ - (int)*c2++; + if ( d ) + break; + } + + return d; +} + +int validate_memcmp(const char* s, const char* d, size_t size) +{ + + int a = ref_memcmp(s, d, size); + int b = memcmp(s, d, size); + //printf("%d, %d\n", a, b); + if (a != b) { + printf("*** memcmp(%p,%p,%lu) failed %d should be %d\n",s,d,size,b,a); + return 1; + } + return 0; +} + +int memcmp_test(int argc, char** argv) +{ + int option = 0; + if (argc >= 2) { + if (!strcmp(argv[1], "perf")) option = 0; + else if (!strcmp(argv[1], "test")) option = 1; + else return -1; + } + + const int MAX_SIZE = 1024*1024; // 1MB + const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 150 MB/s + const int UNCACHED_SPEED_EST = (CPU_FREQ_EST/4)*1024*1024; // 60 MB/s + char* src = (char*)malloc(MAX_SIZE+4+8+32); + char* dst = (char*)malloc(MAX_SIZE+4+8+32); + + if (option == 0) { + printf("memcmp() performance test is running, please wait...\n"); + fflush(stdout); + usleep(10000); + setpriority(PRIO_PROCESS, 0, -20); + + static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE }; + + struct result_t { int size; float res; }; + result_t* results = (result_t*)src; + int nbr = 0; + int size = 0; + for (int i=0 ; ; i++) { + if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0])) + break; + size = FAST_SIZES[i]; + if (size > MAX_SIZE) { + break; + } + + const int REPEAT = (((size < DCACHE_SIZE) ? + (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size) / 2; + // ~0.5 second per test + + const nsecs_t overhead = loop_overhead(REPEAT); + + // tweak to make it a bad case + char* ddd = (char*)((long(dst+31)&~31) + 4); + char* sss = (char*)((long(src+31)&~31) + 28); + + for (int offset=0 ; offset<=2 ; offset +=2 ) { + memcpy(ddd, sss+offset, size); // just make sure to load the caches I/D + nsecs_t t = -system_time(); + register int count = REPEAT; + char c; + c = memcmp(ddd, sss+offset, size); + //printf("size %d, memcmp -> %d\n", size, (int)c); + do { + c = memcmp(ddd, sss+offset, size); + asm volatile (""::"r"(c):"memory"); + } while (--count); + t += system_time() - overhead; + const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t); + results[nbr].size = size; + results[nbr].res = throughput; + nbr++; + } + } + + printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (nc)"); + for (int i=0 ; i<nbr ; i+=2) { + printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res); + } + } else { + printf("memcmp() validation test is running, please wait...\n"); + fflush(stdout); + + const char* const s = (const char*)src + 1024; + const char* const d = (const char*)dst + 1024; + int nb = 0; + for (int j=0 ; j<32 ; j++) { + + char *curr0 = (char*)src; + char *curr1 = (char*)dst; + for (int i=0 ; i<MAX_SIZE ; i++) { + char c = rand(); + *curr0++ = c; + *curr1++ = c; + } + if (j) { + src[1024 + j] ^= 0xFF; + } + + + for (int size=0 ; size<32 && !nb ; size++) { + for (int o=0 ; o<4 ; o++) { + nb += validate_memcmp(s+o, d+o, size); + } + // memmove((char*)d+1, d, size); + for (int o=0 ; o<4 ; o++) { + nb += validate_memcmp(s, d+o, size); + } + } + } + if (nb) printf("%d error(s) found\n", nb); + else printf("success!\n"); + } + fflush(stdout); + free(dst); + free(src); + return 0; +} + +#if 0 +#pragma mark - +#pragma mark strlen +#endif + +int strlen_test(int argc, char** argv) +{ + int option = 0; + if (argc >= 2) { + if (!strcmp(argv[1], "perf")) option = 0; + else if (!strcmp(argv[1], "test")) option = 1; + else return -1; + } + + const int MAX_SIZE = 1024*1024; // 1MB + const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s + const int UNCACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s + char* str = (char*)calloc(MAX_SIZE+4+8, 1); + + if (option == 0) { + printf("strlen() performance test is running, please wait...\n"); + fflush(stdout); + usleep(10000); + setpriority(PRIO_PROCESS, 0, -20); + + static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE }; + const size_t FAST_SIZES_COUNT = sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]); + struct result_t { int size; float res; }; + result_t results[FAST_SIZES_COUNT*2]; + int nbr = 0; + int size = 0; + for (int i=0 ; ; i++) { + if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0])) + break; + size = FAST_SIZES[i]; + if (size > MAX_SIZE) { + break; + } + const int REPEAT = (((size < DCACHE_SIZE) ? + (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size); + // ~0.5 second per test + + const nsecs_t overhead = loop_overhead(REPEAT); + + for (int j=0 ; j<2 ; j++) { + memset(str, 'A', size-1); + if (j==0) preload(str, DCACHE_SIZE*4); // flush D + else preload(str, size); // load D + + nsecs_t t = -system_time(); + size_t count = REPEAT; + int c=0; + do { + c = strlen(str); + asm volatile (""::"r"(c):"memory"); + } while (--count); + t += system_time() - overhead; + + const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t); + results[nbr].size = size; + results[nbr].res = throughput; + nbr++; + } + } + + printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (cached)"); + for (int i=0 ; i<nbr ; i+=2) { + printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res); + } + } + + fflush(stdout); + free(str); + return 0; +} + + +#if 0 +#pragma mark - +#pragma mark malloc +#endif + +int malloc_test(int argc, char** argv) +{ + bool fill = (argc>=2 && !strcmp(argv[1], "fill")); + size_t total = 0; + size_t size = 0x40000000; + while (size) { + void* addr = malloc(size); + if (addr == 0) { + printf("size = %9lu failed\n", size); + size >>= 1; + } else { + total += size; + printf("size = %9lu, addr = %p (total = %9lu (%lu MB))\n", + size, addr, total, total / (1024*1024)); + if (fill) { + printf("filling...\n"); + fflush(stdout); + memset(addr, 0, size); + } + size = size + size>>1; + } + } + printf("done. allocated %lu MB\n", total / (1024*1024)); + return 0; +} + +#if 0 +#pragma mark - +#pragma mark madvise +#endif + +int madvise_test(int argc, char** argv) +{ + for (int i=0 ; i<2 ; i++) { + size_t size = i==0 ? 4096 : 48*1024*1024; // 48 MB + printf("Allocating %lu MB... ", size/(1024*1024)); fflush(stdout); + void* addr1 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + printf("%p (%s)\n", addr1, addr1==(void*)-1 ? "failed" : "OK"); fflush(stdout); + + printf("touching %p...\n", addr1); fflush(stdout); + memset(addr1, 0x55, size); + + printf("advising DONTNEED...\n"); fflush(stdout); + madvise(addr1, size, MADV_DONTNEED); + + printf("reading back %p...\n", addr1); fflush(stdout); + if (*(long*)addr1 == 0) { + printf("madvise freed some pages\n"); + } else if (*(long*)addr1 == 0x55555555) { + printf("pages are still there\n"); + } else { + printf("getting garbage back\n"); + } + + printf("Allocating %lu MB... ", size/(1024*1024)); fflush(stdout); + void* addr2 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + printf("%p (%s)\n", addr2, addr2==(void*)-1 ? "failed" : "OK"); fflush(stdout); + + printf("touching %p...\n", addr2); fflush(stdout); + memset(addr2, 0xAA, size); + + printf("unmap %p ...\n", addr2); fflush(stdout); + munmap(addr2, size); + + printf("touching %p...\n", addr1); fflush(stdout); + memset(addr1, 0x55, size); + + printf("unmap %p ...\n", addr1); fflush(stdout); + munmap(addr1, size); + } + + printf("Done\n"); fflush(stdout); + return 0; +} + +#if 0 +#pragma mark - +#pragma mark cpufreq +#endif + +int cpufreq_test(int argc, char** argv) +{ + struct timespec res; + clock_getres(CLOCK_REALTIME, &res); + printf("CLOCK_REALTIME resolution: %lu ns\n", res.tv_nsec); + clock_getres(CLOCK_MONOTONIC, &res); + printf("CLOCK_MONOTONIC resolution: %lu ns\n", res.tv_nsec); + clock_getres(CLOCK_PROCESS_CPUTIME_ID, &res); + printf("CLOCK_PROCESS_CPUTIME_ID resolution: %lu ns\n", res.tv_nsec); + clock_getres(CLOCK_THREAD_CPUTIME_ID, &res); + printf("CLOCK_THREAD_CPUTIME_ID resolution: %lu ns\n", res.tv_nsec); + + if (clock_getres(CLOCK_REALTIME_HR, &res) != 0) + printf("CLOCK_REALTIME_HR resolution: %lu ns\n", res.tv_nsec); + else + printf("CLOCK_REALTIME_HR not supported\n"); + + if (clock_getres(CLOCK_MONOTONIC_HR, &res) != 0) + printf("CLOCK_MONOTONIC_HR resolution: %lu ns\n", res.tv_nsec); + else + printf("CLOCK_MONOTONIC_HR not supported\n"); + + printf("\nEstimating the CPU frequency, please wait...\n"); + fflush(stdout); + usleep(10000); + setpriority(PRIO_PROCESS, 0, -20); + + const int LOOP_CYCLES = 1+BRANCH_CYCLE; // 1 cycle + 3 cycles for the branch + const size_t REPEAT = CPU_FREQ_EST*1000000; // ~4 seconds (4cycles/loop) + register size_t count = REPEAT; + nsecs_t t = system_time(); + do { // this loop generates 1+3 cycles + asm volatile ("":::"memory"); + } while (--count); + t = system_time() - t; + const float freq = t ? (1000.0f*float(REPEAT)*LOOP_CYCLES) / t : 0; + printf("this CPU frequency: %ld MHz\n", long(freq+0.5f)); + return 0; +} + +#if 0 +#pragma mark - +#pragma mark crash_test +#endif + +int crash_test(int argc, char** argv) +{ + printf("about to crash...\n"); + asm volatile( + "mov r0, #0 \n" + "mov r1, #1 \n" + "mov r2, #2 \n" + "mov r3, #3 \n" + "ldr r12, [r0] \n" + ); + + return 0; +} + +int stack_smasher_test(int argc, char** argv) +{ + int dummy = 0; + printf("corrupting our stack...\n"); + *(volatile long long*)&dummy = 0; + return 0; +} + +// -------------------------------------------------------------------- + +extern "C" void thumb_function_1(int*p); +extern "C" void thumb_function_2(int*p); +extern "C" void arm_function_3(int*p); +extern "C" void arm_function_2(int*p); +extern "C" void arm_function_1(int*p); + +void arm_function_3(int*p) { + int a = 0; + thumb_function_2(&a); +} + +void arm_function_2(int*p) { + int a = 0; + thumb_function_1(&a); +} + +void arm_function_1(int*p) { + int a = 0; + arm_function_2(&a); +} + +int crawl_test(int argc, char** argv) +{ + int a = 0; + arm_function_1(&a); + return 0; +} + diff --git a/tests/memtest/thumb.cpp b/tests/memtest/thumb.cpp new file mode 100644 index 00000000..a70f4c3b --- /dev/null +++ b/tests/memtest/thumb.cpp @@ -0,0 +1,27 @@ +#include <stdio.h> +#include <unwind.h> + +extern "C" void arm_function_3(int*p); +extern "C" void thumb_function_1(int*p); +extern "C" void thumb_function_2(int*p); + +extern "C" _Unwind_Reason_Code trace_function(_Unwind_Context *context, void *arg) +{ + int i = 0; + printf("0x%x\n", _Unwind_GetIP(context)); + fflush(stdout); + return _URC_NO_REASON; +} + +void thumb_function_1(int*p) +{ + int a = 0; + arm_function_3(&a); +} + +void thumb_function_2(int*p) +{ + int a = 0; + printf("unwinding...\n"); + _Unwind_Backtrace(trace_function, (void*)"backtrace!"); +} diff --git a/timeinfo/Android.mk b/timeinfo/Android.mk new file mode 100644 index 00000000..16374155 --- /dev/null +++ b/timeinfo/Android.mk @@ -0,0 +1,24 @@ +# Copyright (C) 2008 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Copyright The Android Open Source Project + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := timeinfo +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) +LOCAL_MODULE_TAGS := tests eng +LOCAL_SRC_FILES := timeinfo.cpp +LOCAL_SHARED_LIBRARIES := libhardware +include $(BUILD_EXECUTABLE) diff --git a/timeinfo/timeinfo.cpp b/timeinfo/timeinfo.cpp new file mode 100644 index 00000000..b1af7ced --- /dev/null +++ b/timeinfo/timeinfo.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Report realtime, uptime, awake percentage, and sleep percentage to stdout. + * Primarily called by powerdroid test harness. + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "utils/SystemClock.h" + + +int main(int argc, char *argv[]) +{ + + int64_t realtime, uptime; + int64_t awaketime, sleeptime; + + uptime = android::uptimeMillis(); + realtime = android::elapsedRealtime(); + + if (realtime == 0) { + realtime = 1; + } + + awaketime = ((1000 * uptime / realtime) + 5) / 10; + sleeptime = ((1000 * (realtime - uptime) / realtime) + 5) / 10; + + printf("%jd %jd %jd %jd\n", (intmax_t) realtime, (intmax_t) uptime, + (intmax_t) awaketime, (intmax_t) sleeptime); + +} + + +/* vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab */ |