diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:32:58 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:32:58 -0800 |
commit | e16cb84e2324f05334d18dcf5956f20f44262b62 (patch) | |
tree | c87defa74181089778bc8e5671e2896d95d4e2b0 | |
parent | 19ddb4b1680760e2d6863c3003976882ebd9d0fa (diff) | |
download | extras-e16cb84e2324f05334d18dcf5956f20f44262b62.tar.gz |
auto import from //depot/cupcake/@135843
101 files changed, 10857 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..4abd56a8 --- /dev/null +++ b/showmap/showmap.c @@ -0,0 +1,234 @@ +#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(fgets(line, 1024, fp) == 0) goto oops; + + if(skip) { + free(mi); + goto again; + } + + return mi; +oops: + fprintf(stderr, "WARNING: Format of /proc/<pid>/smaps has changed!\n"); + 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..bb37d4a9 --- /dev/null +++ b/sound/playwav.c @@ -0,0 +1,377 @@ +/* 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); + return 0; +} + +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..5c9ca106 --- /dev/null +++ b/su/su.c @@ -0,0 +1,85 @@ +/* +** +** 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). + * + * Usage: + * su 1000 + * su 1000 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 (execvp(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/bionic/libc/Android.mk b/tests/bionic/libc/Android.mk new file mode 100644 index 00000000..89d9ade2 --- /dev/null +++ b/tests/bionic/libc/Android.mk @@ -0,0 +1,140 @@ +# 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. +# +# Build control file for Bionic's test programs +# define the BIONIC_TESTS environment variable to build the test programs +# +ifdef BIONIC_TESTS + +LOCAL_PATH:= $(call my-dir) + +# used to define a simple test program and build it as a standalone +# device executable. +# +# you can use EXTRA_CFLAGS to indicate additional CFLAGS to use +# in the build. the variable will be cleaned on exit +# +define device-test + $(foreach file,$(1), \ + $(eval include $(CLEAR_VARS)) \ + $(eval LOCAL_SRC_FILES := $(file)) \ + $(eval LOCAL_MODULE := $(notdir $(file:%.c=%))) \ + $(eval $(info LOCAL_MODULE=$(LOCAL_MODULE))) \ + $(eval LOCAL_CFLAGS += $(EXTRA_CFLAGS)) \ + $(eval LOCAL_MODULE_TAGS := tests) \ + $(eval include $(BUILD_EXECUTABLE)) \ + ) \ + $(eval EXTRA_CFLAGS :=) +endef + +# same as 'device-test' but builds a host executable instead +# you can use EXTRA_LDLIBS to indicate additional linker flags +# +define host-test + $(foreach file,$(1), \ + $(eval include $(CLEAR_VARS)) \ + $(eval LOCAL_SRC_FILES := $(file)) \ + $(eval LOCAL_MODULE := $(notdir $(file:%.c=%))) \ + $(eval $(info LOCAL_MODULE=$(LOCAL_MODULE) file=$(file))) \ + $(eval LOCAL_CFLAGS += $(EXTRA_CFLAGS)) \ + $(eval LOCAL_LDLIBS += $(EXTRA_LDLIBS)) \ + $(eval LOCAL_MODULE_TAGS := tests) \ + $(eval include $(BUILD_HOST_EXECUTABLE)) \ + ) \ + $(eval EXTRA_CFLAGS :=) \ + $(eval EXTRA_LDLIBS :=) +endef + +# First, the tests in 'common' + +sources := \ + common/test_gethostbyname.c \ + common/test_gethostname.c \ + common/test_pthread_cleanup_push.c \ + common/test_pthread_getcpuclockid.c \ + common/test_pthread_join.c \ + common/test_pthread_once.c \ + common/test_semaphore.c \ + common/test_seteuid.c \ + common/test_static_cpp_mutex.cpp \ + common/test_tm_zone.c \ + common/test_udp.c \ + +EXTRA_LDLIBS := -lpthread -lrt +$(call host-test, $(sources)) +$(call device-test, $(sources)) + +sources := \ + common/test_libgen.c \ + +EXTRA_CFLAGS := -DHOST +$(call host-test, $(sources)) +$(call device-test, $(sources)) + +# Second, the Bionic-specific tests + +sources := \ + bionic/test_mutex.c \ + bionic/test_cond.c \ + bionic/test_getgrouplist.c \ + bionic/test_netinet_icmp.c \ + bionic/test_pthread_cond.c \ + bionic/test_pthread_create.c \ + +$(call device-test, $(sources)) + +# Third, the other tests + +sources := \ + other/bench_locks.c \ + other/test_aligned.c \ + other/test_arc4random.c \ + other/test_atomics.c \ + other/test_sysconf.c \ + other/test_system.c \ + other/test_thread_max.c \ + other/test_timer_create.c \ + other/test_timer_create2.c \ + other/test_timer_create3.c \ + other/test_vfprintf_leak.c \ + +$(call device-test, $(sources)) + +# The relocations test is a bit special, since we need +# to build one shared object and one executable that depends +# on it. + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := bionic/lib_relocs.c +LOCAL_MODULE := libtest_relocs +LOCAL_PRELINK_MODULE := false +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := bionic/test_relocs.c +LOCAL_MODULE := test_relocs +LOCAL_SHARED_LIBRARIES := libtest_relocs +include $(BUILD_EXECUTABLE) + +# TODO: Add a variety of GLibc test programs too... + +# Hello World to test libstdc++ support + +sources := \ + common/hello_world.cpp \ + +EXTRA_CFLAGS := -mandroid +#$(call device-test, $(sources)) + +endif # BIONIC_TESTS diff --git a/tests/bionic/libc/MODULE_LICENSE_BSD_AND_GPL b/tests/bionic/libc/MODULE_LICENSE_BSD_AND_GPL new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/tests/bionic/libc/MODULE_LICENSE_BSD_AND_GPL diff --git a/tests/bionic/libc/README.TXT b/tests/bionic/libc/README.TXT new file mode 100644 index 00000000..5576b77b --- /dev/null +++ b/tests/bionic/libc/README.TXT @@ -0,0 +1,32 @@ +This directory contains a set of tests for Android's Bionic C library. + +These sources are not distributed with Bionic itself because some of +these tests come from the GNU C Library, and are licensed under the +GNU Lesser General Public License (LGPL) + +You must define the BIONIC_TESTS environment variable to build these +test programs. For example, do: + + cd system/bionic-tests/ + mm BIONIC_TESTS=1 + +All test programs, except those in the 'other' directory, should exit +with a status code of 0 in case of success, and 1 in case of failure. + +The directory layout is simple: + + common/ + Contains tests that can be compiled either with Bionic or another + C library. + + glibc/ + Contains tests that come from the GNU C Library. However, they can + be compiled with Bionic too. + + bionic/ + Contains tests that can *only* be compiled against Bionic + + other/ + Other unrelated tests. These are not run by the test runner + program but will be installed to your device nevertheless. + Put benchmarks and various debug/info stuff there. diff --git a/tests/bionic/libc/bionic/lib_relocs.c b/tests/bionic/libc/bionic/lib_relocs.c new file mode 100644 index 00000000..af4cf6f8 --- /dev/null +++ b/tests/bionic/libc/bionic/lib_relocs.c @@ -0,0 +1,19 @@ +/* this is part of the test_relocs.c test, which is used to check that + * the relocations generated in a shared object are properly handled + * by the Bionic dynamic linker + */ + +struct foo { int first, second; }; +struct foo Foo = {1, 2}; + +int* FooPtr[] = { &Foo.first, &Foo.second }; + +int func1( void ) +{ + return *FooPtr[0]; +} + +int func2( void ) +{ + return *FooPtr[1]; +} diff --git a/tests/bionic/libc/bionic/test_cond.c b/tests/bionic/libc/bionic/test_cond.c new file mode 100644 index 00000000..6a85f9b4 --- /dev/null +++ b/tests/bionic/libc/bionic/test_cond.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <pthread.h> +#include <semaphore.h> +#include <errno.h> +#include <stdio.h> +#include <time.h> +#include <string.h> +#include <unistd.h> + +static pthread_mutex_t lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER; +static pthread_cond_t wait = PTHREAD_COND_INITIALIZER; + +static void* _thread1(void *__u __attribute__((unused))) +{ + printf("1: obtaining mutex\n"); + pthread_mutex_lock(&lock); + printf("1: waiting on condition variable\n"); + pthread_cond_wait(&wait, &lock); + printf("1: releasing mutex\n"); + pthread_mutex_unlock(&lock); + printf("1: exiting\n"); + return NULL; +} + +static void* _thread2(void *__u __attribute__((unused))) +{ + int cnt = 2; + while(cnt--) { + printf("2: obtaining mutex\n"); + pthread_mutex_lock(&lock); + printf("2: signaling\n"); + pthread_cond_signal(&wait); + printf("2: releasing mutex\n"); + pthread_mutex_unlock(&lock); + } + + printf("2: exiting\n"); + return NULL; +} + +typedef void* (*thread_func)(void*); +static const thread_func thread_routines[] = +{ + &_thread1, + &_thread2, +}; + +int main(void) +{ + pthread_t t[2]; + int nn; + int count = (int)(sizeof t/sizeof t[0]); + + for (nn = 0; nn < count; nn++) { + printf("main: creating thread %d\n", nn+1); + if (pthread_create( &t[nn], NULL, thread_routines[nn], NULL) < 0) { + printf("main: could not create thread %d: %s\n", nn+1, strerror(errno)); + return -2; + } + } + + for (nn = 0; nn < count; nn++) { + printf("main: joining thread %d\n", nn+1); + if (pthread_join(t[nn], NULL)) { + printf("main: could not join thread %d: %s\n", nn+1, strerror(errno)); + return -2; + } + } + + return 0; +} diff --git a/tests/bionic/libc/bionic/test_getgrouplist.c b/tests/bionic/libc/bionic/test_getgrouplist.c new file mode 100644 index 00000000..e5b8ee26 --- /dev/null +++ b/tests/bionic/libc/bionic/test_getgrouplist.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <stdio.h> +#include <grp.h> + +#define MAX_GROUPS 100 +#define TEST_GROUP 1337 +#define TEST_USER "nobodyisreallyhere" + +int main(void) +{ + int count = MAX_GROUPS; + gid_t groups[MAX_GROUPS]; + int ret; + + /* this only tests the funky behaviour of our stubbed getgrouplist() + * implementation. which should only return TEST_GROUP, independent + * of the user + */ + ret = getgrouplist( TEST_USER, TEST_GROUP, groups, &count ); + if (ret != 1) { + fprintf(stderr, "getgrouplist() returned %d (expecting 1), ngroups=%d\n", + ret, count); + return 1; + } + if (groups[0] != TEST_GROUP) { + fprintf(stderr, "getgrouplist() returned group %d (expecting %d)\n", + groups[0], TEST_GROUP); + return 1; + } + printf ("ok\n"); + return 0; +} diff --git a/tests/bionic/libc/bionic/test_mutex.c b/tests/bionic/libc/bionic/test_mutex.c new file mode 100644 index 00000000..02257ba3 --- /dev/null +++ b/tests/bionic/libc/bionic/test_mutex.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#define __USE_UNIX98 1 /* necessary to define pthread_mutexattr_set/gettype in Linux GLIBC headers. doh ! */ +#include <pthread.h> +#include <errno.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> + +static void panic( const char* format, ... ) +{ + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + exit(1); +} + +#define assert(cond) do { if ( !(cond) ) panic( "%s:%d: assertion failure: %s\n", __FILE__, __LINE__, #cond ); } while (0) + +#define expect(call,result) \ + do { \ + int ret = (call); \ + if (ret != (result)) { \ + panic( "%s:%d: call returned %d instead of %d: %s\n", \ + __FILE__, __LINE__, ret, (result), #call ); \ + } \ + } while (0) + + +int main( void ) +{ + pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + pthread_mutexattr_t attr; + int attr_type; + + expect( pthread_mutexattr_init( &attr ), 0 ); + + expect( pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_NORMAL ), 0 ); + expect( pthread_mutexattr_gettype( &attr, &attr_type ), 0 ); + assert( attr_type == PTHREAD_MUTEX_NORMAL ); + + expect( pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK ), 0 ); + expect( pthread_mutexattr_gettype( &attr, &attr_type ), 0 ); + assert( attr_type == PTHREAD_MUTEX_ERRORCHECK ); + + expect( pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ), 0 ); + expect( pthread_mutexattr_gettype( &attr, &attr_type ), 0 ); + assert( attr_type == PTHREAD_MUTEX_RECURSIVE ); + + /* standard mutexes */ + expect( pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_NORMAL ), 0 ); + expect( pthread_mutex_init( &lock, &attr ), 0 ); + expect( pthread_mutex_lock( &lock ), 0 ); + expect( pthread_mutex_unlock( &lock ), 0 ); + expect( pthread_mutex_destroy( &lock ), 0 ); + + /* error-check mutex */ + expect( pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK ), 0 ); + expect( pthread_mutex_init( &lock, &attr ), 0 ); + expect( pthread_mutex_lock( &lock ), 0 ); + expect( pthread_mutex_lock( &lock ), EDEADLK ); + expect( pthread_mutex_unlock( &lock ), 0 ); + expect( pthread_mutex_trylock( &lock ), 0 ); + expect( pthread_mutex_trylock( &lock ), EDEADLK ); + expect( pthread_mutex_unlock( &lock ), 0 ); + expect( pthread_mutex_unlock( &lock ), EPERM ); + expect( pthread_mutex_destroy( &lock ), 0 ); + + /* recursive mutex */ + expect( pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ), 0 ); + expect( pthread_mutex_init( &lock, &attr ), 0 ); + expect( pthread_mutex_lock( &lock ), 0 ); + expect( pthread_mutex_lock( &lock ), 0 ); + expect( pthread_mutex_unlock( &lock ), 0 ); + expect( pthread_mutex_unlock( &lock ), 0 ); + expect( pthread_mutex_trylock( &lock ), 0 ); + expect( pthread_mutex_unlock( &lock ), 0 ); + expect( pthread_mutex_unlock( &lock ), EPERM ); + expect( pthread_mutex_destroy( &lock ), 0 ); + + printf( "ok\n" ); + return 0; +} diff --git a/tests/bionic/libc/bionic/test_netinet_icmp.c b/tests/bionic/libc/bionic/test_netinet_icmp.c new file mode 100644 index 00000000..308ccce9 --- /dev/null +++ b/tests/bionic/libc/bionic/test_netinet_icmp.c @@ -0,0 +1,8 @@ +/* this test simply checks that we can compile the <netinet/ip_icmp.h> header */ +#include <netinet/ip_icmp.h> + +int main( void ) +{ + return 0; +} + diff --git a/tests/bionic/libc/bionic/test_pthread_cond.c b/tests/bionic/libc/bionic/test_pthread_cond.c new file mode 100644 index 00000000..26746fa7 --- /dev/null +++ b/tests/bionic/libc/bionic/test_pthread_cond.c @@ -0,0 +1,83 @@ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> + + +static pthread_cond_t cond1; +static pthread_cond_t cond2; +static pthread_mutex_t test_lock = PTHREAD_MUTEX_INITIALIZER; + +static void * +thread1_func(void* arg) +{ + printf("Thread 1 (arg=%d tid=%d) entered.\n", (unsigned)arg, gettid()); + printf("1 waiting for cond1\n"); + pthread_mutex_lock(&test_lock); + pthread_cond_wait(&cond1, &test_lock ); + pthread_mutex_unlock(&test_lock); + printf("Thread 1 done.\n"); + return 0; +} + +static void * +thread2_func(void* arg) +{ + printf("Thread 2 (arg=%d tid=%d) entered.\n", (unsigned)arg, gettid()); + printf("2 waiting for cond2\n"); + pthread_mutex_lock(&test_lock); + pthread_cond_wait(&cond2, &test_lock ); + pthread_mutex_unlock(&test_lock); + + printf("Thread 2 done.\n"); + return 0; +} + +static void * +thread3_func(void* arg) +{ + printf("Thread 3 (arg=%d tid=%d) entered.\n", (unsigned)arg, gettid()); + printf("3 waiting for cond1\n"); + pthread_mutex_lock(&test_lock); + pthread_cond_wait(&cond1, &test_lock ); + pthread_mutex_unlock(&test_lock); + printf("3 Sleeping\n"); + sleep(2); + printf("3 signal cond2\n"); + pthread_cond_signal(&cond2); + + printf("Thread 3 done.\n"); + return 0; +} + +static void * +thread4_func(void* arg) +{ + printf("Thread 4 (arg=%d tid=%d) entered.\n", (unsigned)arg, gettid()); + printf("4 Sleeping\n"); + sleep(5); + + printf("4 broadcast cond1\n"); + pthread_cond_broadcast(&cond1); + printf("Thread 4 done.\n"); + return 0; +} + +int main(int argc, const char *argv[]) +{ + pthread_t t[4]; + + pthread_cond_init(&cond1, NULL); + pthread_cond_init(&cond2, NULL); + pthread_create( &t[0], NULL, thread1_func, (void *)1 ); + pthread_create( &t[1], NULL, thread2_func, (void *)2 ); + pthread_create( &t[2], NULL, thread3_func, (void *)3 ); + pthread_create( &t[3], NULL, thread4_func, (void *)4 ); + + pthread_join(t[0], NULL); + pthread_join(t[1], NULL); + pthread_join(t[2], NULL); + pthread_join(t[3], NULL); + return 0; +} diff --git a/tests/bionic/libc/bionic/test_pthread_create.c b/tests/bionic/libc/bionic/test_pthread_create.c new file mode 100644 index 00000000..edac0ff1 --- /dev/null +++ b/tests/bionic/libc/bionic/test_pthread_create.c @@ -0,0 +1,30 @@ +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> + +static void * +thread1_func(void* arg) +{ + printf("Thread 1 (arg=%d tid=%d) entered.\n", (unsigned)arg, gettid()); + return 0; +} + +static void * +thread2_func(void* arg) +{ + printf("thread 2 (arg=%d tid=%d) entered.\n", (unsigned)arg, gettid()); + return 1; +} + + +int main( void ) +{ + pthread_t t1, t2; + + pthread_create( &t1, NULL, thread1_func, (void *)1 ); + + pthread_join(t1, NULL); + + printf("OK\n"); + return 0; +} diff --git a/tests/bionic/libc/bionic/test_relocs.c b/tests/bionic/libc/bionic/test_relocs.c new file mode 100644 index 00000000..c42df116 --- /dev/null +++ b/tests/bionic/libc/bionic/test_relocs.c @@ -0,0 +1,25 @@ +/* this little test is written to check that the relocations generated + * in a shared library are correct. it depends on the content of lib_relocs.c + * being compiled as a shared object. + */ +#include <stdio.h> + +extern int func1(void); +extern int func2(void); + +int +main( void ) +{ + int f1, f2, expect1 = 1, expect2 = 2; + + f1 = func1(); + f2 = func2(); + + printf( "func1() returns %d: %s\n", f1, (f1 == expect1) ? "OK" : "FAIL" ); + printf( "func2() returns %d: %s\n", f2, (f2 == expect2) ? "OK" : "FAIL" ); + + if (f1 != expect1 || f2 != expect2) + return 1; + + return 0; +} diff --git a/tests/bionic/libc/common/hello_world.cpp b/tests/bionic/libc/common/hello_world.cpp new file mode 100644 index 00000000..0578d7d8 --- /dev/null +++ b/tests/bionic/libc/common/hello_world.cpp @@ -0,0 +1,8 @@ +#include <iostream> +using namespace std; + +int main() +{ + cout << "Hello World" << endl; + return 0; +} diff --git a/tests/bionic/libc/common/test_gethostbyname.c b/tests/bionic/libc/common/test_gethostbyname.c new file mode 100644 index 00000000..1e932d60 --- /dev/null +++ b/tests/bionic/libc/common/test_gethostbyname.c @@ -0,0 +1,53 @@ +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <sys/types.h> +#include <netdb.h> + +int main( int argc, char** argv ) +{ + char* hostname = "localhost"; + struct hostent* hent; + int i, ret; + + if (argc > 1) + hostname = argv[1]; + + hent = gethostbyname(hostname); + if (hent == NULL) { + printf("gethostbyname(%s) returned NULL !!\n", hostname); + return 1; + } + printf( "gethostbyname(%s) returned:\n", hostname); + printf( " name: %s\n", hent->h_name ); + printf( " aliases:" ); + for (i = 0; hent->h_aliases[i] != NULL; i++) + printf( " %s", hent->h_aliases[i] ); + printf( "\n" ); + printf( " address type: " ); + switch (hent->h_addrtype) { + case AF_INET: printf( "AF_INET\n"); break; + case AF_INET6: printf( "AF_INET6\n"); break; + default: printf("UNKNOWN (%d)\n", hent->h_addrtype); + } + printf( " address: " ); + switch (hent->h_addrtype) { + case AF_INET: + { + const char* dot = ""; + for (i = 0; i < hent->h_length; i++) { + printf("%s%d", dot, ((unsigned char*)hent->h_addr)[i]); + dot = "."; + } + } + break; + + default: + for (i = 0; i < hent->h_length; i++) { + printf( "%02x", ((unsigned char*)hent->h_addr)[i] ); + } + } + printf("\n"); + return 0; +} diff --git a/tests/bionic/libc/common/test_gethostname.c b/tests/bionic/libc/common/test_gethostname.c new file mode 100644 index 00000000..b9dcbafc --- /dev/null +++ b/tests/bionic/libc/common/test_gethostname.c @@ -0,0 +1,20 @@ +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <sys/types.h> + +int main( void ) +{ + char hostname[512]; + int ret; + + ret = gethostname(hostname, sizeof(hostname)); + if (ret < 0) { + printf("gethostname() returned error %d: %s\n", errno, strerror(errno)); + return 1; + } + + printf("gethostname() returned '%s'\n", hostname); + return 0; +} diff --git a/tests/bionic/libc/common/test_libgen.c b/tests/bionic/libc/common/test_libgen.c new file mode 100644 index 00000000..4a2c29e2 --- /dev/null +++ b/tests/bionic/libc/common/test_libgen.c @@ -0,0 +1,221 @@ +// test the basename, dirname, basename_r and dirname_r +#include <libgen.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +static int fail = 0; + +static void +test_basename(char* _input, const char* _expected, int _errno) +{ + char temp[256], *input = _input; + char* ret; +#if HOST + /* GLibc does modify the input string. bummer */ + if (_input) { + strcpy(temp, _input); + input = temp; + } +#endif + errno = 0; + ret = basename(input); + if (_expected == NULL) { + if (ret != NULL) { + fprintf(stderr, + "KO: basename(\"%s\") returned \"%s\", NULL expected)\n", + _input, ret); + fail += 1; + } else if (errno != _errno) { + fprintf(stderr, + "KO: basename(\"%s\") returned NULL with error: %d (%d expected)\n", + _input, errno, _errno); + fail += 1; + } else { + printf( "OK: basename(\"%s\") returned NULL with error %d\n", + _input, _errno ); + } + } else { + if (ret == NULL) { + fprintf(stderr, "KO: basename(\"%s\") returned NULL with error %d\n", + _input, errno); + fail += 1; + } + else if (strcmp(ret, _expected)) { + fprintf(stderr, "KO: basename(\"%s\") returned \"%s\", instead of \"%s\"\n", + _input, ret, _expected); + } + else { + printf( "OK: basename(\"%s\") returned \"%s\"\n", + _input, ret ); + } + } +} + + +#if !HOST +static void +test_basename_r(char* _input, const char* _expected_content, int _expected, char* _buff, size_t _bufflen, int _errno) +{ + int ret; + errno = 0; + ret = basename_r(_input, _buff, _bufflen ); + if (ret != _expected) { + fprintf(stderr, + "KO: basename_r(\"%s\", <buff>, %d) returned %d (expected %d)\n", + _input, _bufflen, ret, _expected); + fail += 1; + return; + } + if (ret == -1) { + if (errno != _errno) { + fprintf(stderr, + "KO: basename_r(\"%s\", <buff>, %d) returned -1 with errno=%d (expected %d)\n", + _input, _bufflen, errno, _errno); + fail += 1; + return; + } + } + else if ( memcmp( _buff, _expected_content, ret ) ) { + fprintf(stderr, + "KO: basename_r(\"%s\", <buff>, %d) returned \"%s\", expected \"%s\"\n", + _input, _bufflen, _buff, _expected_content ); + fail += 1; + return; + } + printf("OK: basename_r(\"%s\", <buff>, %d) returned \"%s\"\n", + _input, _bufflen, _expected_content ); +} + +static void +test_dirname_r(char* _input, const char* _expected_content, int _expected, char* _buff, size_t _bufflen, int _errno) +{ + int ret; + errno = 0; + ret = dirname_r(_input, _buff, _bufflen ); + if (ret != _expected) { + fprintf(stderr, + "KO: dirname_r(\"%s\", <buff>, %d) returned %d (expected %d)\n", + _input, _bufflen, ret, _expected); + fail += 1; + return; + } + if (ret == -1) { + if (errno != _errno) { + fprintf(stderr, + "KO: dirname_r(\"%s\", <buff>, %d) returned -1 with errno=%d (expected %d)\n", + _input, _bufflen, errno, _errno); + fail += 1; + return; + } + } + else if ( memcmp( _buff, _expected_content, ret ) ) { + fprintf(stderr, + "KO: dirname_r(\"%s\", <buff>, %d) returned \"%s\", expected \"%s\"\n", + _input, _bufflen, _buff, _expected_content ); + fail += 1; + return; + } + printf("OK: dirname_r(\"%s\", <buff>, %d) returned \"%s\"\n", + _input, _bufflen, _expected_content ); +} +#endif + + +static void +test_dirname(char* _input, const char* _expected, int _errno) +{ + char temp[256], *input = _input; + char* ret; +#if HOST + /* GLibc does modify the input string. bummer */ + if (_input) { + strcpy(temp, _input); + input = temp; + } +#endif + errno = 0; + ret = dirname(input); + if (_expected == NULL) { + if (ret != NULL) { + fprintf(stderr, + "KO: dirname(\"%s\") returned \"%s\", NULL expected)\n", + _input, ret); + fail += 1; + } else if (errno != _errno) { + fprintf(stderr, + "KO: dirname(\"%s\") returned NULL with error: %d (%d expected)\n", + _input, errno, _errno); + fail += 1; + } else { + printf( "OK: dirname(\"%s\") returned NULL with error %d\n", + _input, _errno ); + } + } else { + if (ret == NULL) { + fprintf(stderr, "KO: dirname(\"%s\") returned NULL with error %d\n", + _input, errno); + fail += 1; + } + else if (strcmp(ret, _expected)) { + fprintf(stderr, "KO: dirname(\"%s\") returned \"%s\", instead of \"%s\"\n", + _input, ret, _expected); + } + else { + printf( "OK: dirname(\"%s\") returned \"%s\"\n", + _input, ret ); + } + } +} + + + + +int main( void ) +{ + char buff[256]; + + test_basename( "", ".", 0 ); + test_basename( "/usr/lib", "lib", 0 ); + test_basename( "/usr/", "usr", 0 ); + test_basename( "usr", "usr", 0 ); + test_basename( "/", "/", 0 ); + test_basename( ".", ".", 0 ); + test_basename( "..", "..", 0 ); + +#if !HOST + test_basename_r( "", ".", 1, NULL, 0, 0 ); + test_basename_r( "", ".", -1, buff, 0, ERANGE ); + test_basename_r( "", ".", -1, buff, 1, ERANGE ); + test_basename_r( "", ".", 1, buff, 2, 0 ); + test_basename_r( "", ".", 1, buff, sizeof(buff), 0 ); + test_basename_r( "/usr/lib", "lib", 3, buff, sizeof(buff), 0 ); + test_basename_r( "/usr/", "usr", 3, buff, sizeof(buff), 0 ); + test_basename_r( "usr", "usr", 3, buff, sizeof(buff), 0 ); + test_basename_r( "/", "/", 1, buff, sizeof(buff), 0 ); + test_basename_r( ".", ".", 1, buff, sizeof(buff), 0 ); + test_basename_r( "..", "..", 2, buff, sizeof(buff), 0 ); +#endif + + test_dirname( "", ".", 0 ); + test_dirname( "/usr/lib", "/usr", 0 ); + test_dirname( "/usr/", "/", 0 ); + test_dirname( "usr", ".", 0 ); + test_dirname( ".", ".", 0 ); + test_dirname( "..", ".", 0 ); + +#if !HOST + test_dirname_r( "", ".", 1, NULL, 0, 0 ); + test_dirname_r( "", ".", -1, buff, 0, ERANGE ); + test_dirname_r( "", ".", -1, buff, 1, ERANGE ); + test_dirname_r( "", ".", 1, buff, 2, 0 ); + test_dirname_r( "/usr/lib", "/usr", 4, buff, sizeof(buff), 0 ); + test_dirname_r( "/usr/", "/", 1, buff, sizeof(buff), 0 ); + test_dirname_r( "usr", ".", 1, buff, sizeof(buff), 0 ); + test_dirname_r( ".", ".", 1, buff, sizeof(buff), 0 ); + test_dirname_r( "..", ".", 1, buff, sizeof(buff), 0 ); +#endif + + return (fail > 0); +} + diff --git a/tests/bionic/libc/common/test_pthread_cleanup_push.c b/tests/bionic/libc/common/test_pthread_cleanup_push.c new file mode 100644 index 00000000..87634adf --- /dev/null +++ b/tests/bionic/libc/common/test_pthread_cleanup_push.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +#define MAGIC1 0xcafebabeU +#define MAGIC2 0x8badf00dU +#define MAGIC3 0x12345667U + +static int g_ok1 = 0; +static int g_ok2 = 0; +static int g_ok3 = 0; + +static void +cleanup1( void* arg ) +{ + if ((unsigned)arg != MAGIC1) + g_ok1 = -1; + else + g_ok1 = +1; +} + +static void +cleanup2( void* arg ) +{ + if ((unsigned)arg != MAGIC2) { + g_ok2 = -1; + } else + g_ok2 = +1; +} + +static void +cleanup3( void* arg ) +{ + if ((unsigned)arg != MAGIC3) + g_ok3 = -1; + else + g_ok3 = +1; +} + + +static void* +thread1_func( void* arg ) +{ + pthread_cleanup_push( cleanup1, (void*)MAGIC1 ); + pthread_cleanup_push( cleanup2, (void*)MAGIC2 ); + pthread_cleanup_push( cleanup3, (void*)MAGIC3 ); + + if (arg != NULL) + pthread_exit(0); + + pthread_cleanup_pop(0); + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + + return NULL; +} + +static int test( int do_exit ) +{ + pthread_t t; + + pthread_create( &t, NULL, thread1_func, (void*)do_exit ); + pthread_join( t, NULL ); + + if (g_ok1 != +1) { + if (g_ok1 == 0) { + fprintf(stderr, "cleanup1 not called !!\n"); + } else { + fprintf(stderr, "cleanup1 called with wrong argument\n" ); + } + exit(1); + } + else if (g_ok2 != +1) { + if (g_ok2 == 0) + fprintf(stderr, "cleanup2 not called !!\n"); + else + fprintf(stderr, "cleanup2 called with wrong argument\n"); + exit(2); + } + else if (do_exit && g_ok3 != +1) { + if (g_ok3 == 0) { + fprintf(stderr, "cleanup3 not called !!\n"); + } else { + fprintf(stderr, "cleanup3 called with bad argument !!\n"); + } + exit(3); + } + else if (!do_exit && g_ok3 != 0) { + if (g_ok3 == 1) { + fprintf(stderr, "cleanup3 wrongly called !!\n"); + } else { + fprintf(stderr, "cleanup3 wrongly called with bad argument !!\n"); + } + exit(3); + } + + return 0; +} + +int main( void ) +{ + test(0); + test(1); + printf("OK\n"); + return 0; +} diff --git a/tests/bionic/libc/common/test_pthread_getcpuclockid.c b/tests/bionic/libc/common/test_pthread_getcpuclockid.c new file mode 100644 index 00000000..2a828088 --- /dev/null +++ b/tests/bionic/libc/common/test_pthread_getcpuclockid.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* this is a small test for pthread_getcpuclockid() and clock_gettime() */ + +#include <time.h> +#include <pthread.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +static void* +thread_func( void* arg ) +{ + pthread_t self = pthread_self(); + struct timespec ts; + clockid_t clock; + int e; + + pthread_mutex_lock( &lock ); + + e = pthread_getcpuclockid( self, &clock ); + if (e != 0) { + fprintf(stderr, "pthread_getcpuclockid(%08lx,) returned error %d: %s\n", self, e, strerror(e)); + pthread_mutex_unlock( &lock ); + return NULL; + } + + ts.tv_sec = 0; + ts.tv_nsec = 300000000 + ((int)arg)*50000000; + nanosleep( &ts, &ts ); + + clock_gettime( clock, &ts ); + fprintf(stderr, "thread %08lx: clock_gettime() returned %g nsecs\n", self, ts.tv_sec*1e9 + ts.tv_nsec); + + pthread_mutex_unlock( &lock ); + + return NULL; +} + +#define MAX_THREADS 16 + +int main( void ) +{ + int nn; + pthread_attr_t attr; + pthread_t threads[MAX_THREADS]; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (nn = 0; nn < MAX_THREADS; nn++) { + pthread_create( &threads[nn], &attr, thread_func, (void*)nn ); + } + for (nn = 0; nn < MAX_THREADS; nn++) { + void* dummy; + pthread_join( threads[nn], &dummy ); + } + return 0; +} diff --git a/tests/bionic/libc/common/test_pthread_join.c b/tests/bionic/libc/common/test_pthread_join.c new file mode 100644 index 00000000..4fe2561a --- /dev/null +++ b/tests/bionic/libc/common/test_pthread_join.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> + +static void* +thread1_func(void* arg) +{ + usleep( 2000*1000 ); + printf("thread 1 exited\n"); + return (void*) 0x8badf00d; +} + +static void* +thread2_func(void* arg) +{ + pthread_t t1 = (pthread_t)arg; + void* result; + + pthread_join(t1, &result); + printf("thread2 received code %08x from thread1\n", (int)result); + return NULL; +} + + +static void* +thread3_func(void* arg) +{ + pthread_t t1 = (pthread_t)arg; + void* result; + + pthread_join(t1, &result); + printf("thread3 received code %08x from thread1\n", (int)result); + return NULL; +} + +int main( void ) +{ + pthread_t t1, t2, t3; + + pthread_create( &t1, NULL, thread1_func, NULL ); + pthread_create( &t2, NULL, thread2_func, (void*)t1 ); + pthread_create( &t3, NULL, thread3_func, (void*)t1 ); + + pthread_join(t2, NULL); + pthread_join(t3, NULL); + + printf("OK\n"); + return 0; +} diff --git a/tests/bionic/libc/common/test_pthread_once.c b/tests/bionic/libc/common/test_pthread_once.c new file mode 100644 index 00000000..3beda913 --- /dev/null +++ b/tests/bionic/libc/common/test_pthread_once.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +#define N_THREADS 100 + +static pthread_once_t once = PTHREAD_ONCE_INIT; + +static int global_count = 0; + +static void +once_function( void ) +{ + struct timespec ts; + + global_count += 1; + + ts.tv_sec = 2; + ts.tv_nsec = 0; + nanosleep (&ts, NULL); +} + +static void* +thread_function(void* arg) +{ + pthread_once( &once, once_function ); + + if (global_count != 1) { + printf ("thread %ld: global == %d\n", (long int) arg, global_count); + exit (1); + } + return NULL; +} + +int main( void ) +{ + pthread_t threads[N_THREADS]; + int nn; + + for (nn = 0; nn < N_THREADS; nn++) { + if (pthread_create( &threads[nn], NULL, thread_function, (void*)(long int)nn) < 0) { + printf("creation of thread %d failed\n", nn); + return 1; + } + } + + for (nn = 0; nn < N_THREADS; nn++) { + if (pthread_join(threads[nn], NULL)) { + printf("joining thread %d failed\n", nn); + return 1; + } + } + return 0; +} diff --git a/tests/bionic/libc/common/test_semaphore.c b/tests/bionic/libc/common/test_semaphore.c new file mode 100644 index 00000000..6792d861 --- /dev/null +++ b/tests/bionic/libc/common/test_semaphore.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <pthread.h> +#include <semaphore.h> +#include <errno.h> +#include <stdio.h> +#include <time.h> +#include <string.h> +#include <unistd.h> + +/* a simple semaphore test, using three threads + * + * a semaphore is initialized with a value of 1 + * + * Thread 1, 2 and 3 start at the same time + * + * Thread 1 takes the semaphore, then sleeps for 2 seconds, then post the semaphore + * Thread 2 sleeps for 1 second, then waits the semaphore, sleeps for 2 seconds, then post the semaphoe + * Thread 3 sleeps 3 seconds, waits for the semaphore + */ + +static sem_t semaphore; + +static void* +_thread1( void* unused ) +{ + printf( "thread 1: waiting for semaphore\n" ); + if ( sem_wait( &semaphore ) < 0 ) { + printf( "thread 1: could not wait for semaphore: %s\n", strerror(errno) ); + return NULL; + } + printf( "thread 1: got the semaphore ! sleeping for 2 seconds\n" ); + sleep( 2 ); + printf( "thread 1: awake !! posting semaphore\n" ); + if ( sem_post( &semaphore ) < 0 ) { + printf( "thread 2: could not post semaphore: %s\n", strerror(errno) ); + } + printf( "thread 1: quitting\n" ); + return NULL; +} + +static void* +_thread2( void* unused ) +{ + printf( "thread 2: sleeping for 1 second\n" ); + sleep(1); + printf( "thread 2: awake !! waiting for semaphore\n" ); + if ( sem_wait( &semaphore ) < 0 ) { + printf( "thread 2: could not wait for semaphore: %s\n", strerror(errno) ); + return NULL; + } + printf( "thread 2: got the semaphore ! sleeping for 2 seconds\n" ); + sleep( 2 ); + printf( "thread 2: awake !! posting semaphore\n" ); + if ( sem_post( &semaphore ) < 0 ) { + printf( "thread 2: could not post semaphore: %s\n", strerror(errno) ); + } + printf( "thread 2: quitting\n" ); + return NULL; +} + + +static void* +_thread3( void* unused ) +{ + printf( "thread 3: sleeping for 3 seconds\n" ); + sleep(3); + printf( "thread 3: awake !! waiting for semaphore\n" ); + if ( sem_wait( &semaphore ) < 0 ) { + printf( "thread 3: could not wait for semaphore: %s\n", strerror(errno) ); + return NULL; + } + printf( "thread 3: got semaphore. quitting\n" ); + return NULL; +} + +typedef void* (*thread_func)(void*); + +static const thread_func thread_routines[] = +{ + &_thread1, + &_thread2, + &_thread3 +}; + +int main( void ) +{ + pthread_t t[3]; + int nn; + + if ( sem_init( &semaphore, 0, 1 ) < 0 ) { + printf( "could not initialize semaphore: %s\n", strerror(errno) ); + return -1; + } + + for ( nn = 0; nn < 3; nn++ ) { + if ( pthread_create( &t[nn], NULL, thread_routines[nn], NULL ) < 0 ) { + printf("could not create thread %d: %s\n", nn+1, strerror(errno) ); + return -2; + } + } + sleep( 5 ); + return 0; +} diff --git a/tests/bionic/libc/common/test_seteuid.c b/tests/bionic/libc/common/test_seteuid.c new file mode 100644 index 00000000..ac330cec --- /dev/null +++ b/tests/bionic/libc/common/test_seteuid.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <unistd.h> +#include <stdio.h> +#include <sys/types.h> + +int main( void ) +{ + uid_t ruid, euid; + + printf( "sizeof(uid_t) = %d sizeof(gid_t) = %d\n", sizeof(uid_t), sizeof(gid_t) ); + + ruid = getuid(); + euid = geteuid(); + printf("Start: ruid=%d euid=%d\n", ruid, euid); + + if (seteuid(9999) != 0) + perror("seteuid(9999)"); + + ruid = getuid(); + euid = geteuid(); + printf("After set: ruid=%d euid=%d\n", ruid, euid); + + if (seteuid(0) != 0) + perror("seteuid(0)"); + + ruid = getuid(); + euid = geteuid(); + printf("After restore: ruid=%d euid=%d\n", ruid, euid); + + return 0; +} diff --git a/tests/bionic/libc/common/test_static_cpp_mutex.cpp b/tests/bionic/libc/common/test_static_cpp_mutex.cpp new file mode 100644 index 00000000..33a56ef4 --- /dev/null +++ b/tests/bionic/libc/common/test_static_cpp_mutex.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* this program is used to test the locking of a recursive mutex in a static C++ constructor + * this operation crashes on some + */ +#include <pthread.h> +#include <stdio.h> + +class Foo { +private: + pthread_mutex_t mMutex; +public: + virtual int getValue(); + Foo(); +}; + +Foo::Foo() +{ + pthread_mutexattr_t mattr; + + pthread_mutexattr_init(&mattr); + pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mMutex, &mattr); + pthread_mutex_lock(&mMutex); + fprintf(stderr, "recursive lock initialized and locked\n" ); +} + +int Foo::getValue() +{ + return 0; +} + +static Foo f; + +int main(void) +{ + printf( "f.getValue() returned: %d\n", f.getValue() ); + return 0; +} diff --git a/tests/bionic/libc/common/test_tm_zone.c b/tests/bionic/libc/common/test_tm_zone.c new file mode 100644 index 00000000..63e06353 --- /dev/null +++ b/tests/bionic/libc/common/test_tm_zone.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* a small program to test the tm_zone setting in Bionic */ +#include <time.h> +#include <stdio.h> +#include <stdlib.h> + +int main( void ) +{ +#ifndef TM_ZONE + fprintf(stderr, "TM_ZONE is not defined in <time.h> !!\n" ); + return 1; +#else + const char* tz = getenv("TZ"); + time_t now = time(NULL); + struct tm tm0; + struct tm* tm; + + if (tz) { + printf( "TZ set to '%s'\n", tz ); + } else + printf( "TZ is not defined\n" ); + + tm = localtime_r( &now, &tm0 ); + printf( "localtime_r() returns timezone abbreviation '%s'\n", tm->TM_ZONE ? tm->TM_ZONE : "<NULL POINTER>" ); + printf( "tzname[0] is '%s'\n", tzname[0] ? tzname[0] : "<NULL POINTER>" ); + printf( "tzname[1] is '%s'\n", tzname[1] ? tzname[1] : "<NULL POINTER>" ); +#endif + return 0; +} diff --git a/tests/bionic/libc/common/test_udp.c b/tests/bionic/libc/common/test_udp.c new file mode 100644 index 00000000..3c9dd079 --- /dev/null +++ b/tests/bionic/libc/common/test_udp.c @@ -0,0 +1,121 @@ +/* this program is used to test UDP networking in Android. + * used to debug the emulator's networking implementation + */ +#define PROGNAME "test_udp" +#define DEFAULT_PORT 7000 + +#include <arpa/inet.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#include <string.h> + +#define BUFLEN 512 +#define NPACK 10 + +void diep(char *s) +{ + perror(s); + exit(1); +} + +static void +usage(int code) +{ + printf("usage: %s [options]\n", PROGNAME); + printf("options:\n"); + printf(" -p<port> use specific port (default %d)\n", DEFAULT_PORT); + printf(" -a<inet> use specific IP address\n"); + printf(" -s run server (default is client)\n"); + exit(code); +} + +int main(int argc, char** argv) +{ + int runServer = 0; + int udpPort = DEFAULT_PORT; + int useLocal = 0; + int address = htonl(INADDR_ANY); + + struct sockaddr_in si_me, si_other; + int s, i, slen=sizeof(si_other); + char buf[BUFLEN]; + + while (argc > 1 && argv[1][0] == '-') { + const char* optName = argv[1]+1; + argc--; + argv++; + + switch (optName[0]) { + case 'p': + udpPort = atoi(optName+1); + if (udpPort < 1024 || udpPort > 65535) { + fprintf(stderr, "UDP port must be between 1024 and 65535\n"); + exit(1); + } + break; + + case 's': + runServer = 1; + break; + + case 'a': + if (inet_aton(optName+1, &si_other.sin_addr) == 0) + diep("inet_aton"); + address = si_other.sin_addr.s_addr; + break; + + default: + usage(1); + } + } + + if (runServer) { + if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) + diep("socket"); + + memset((char *) &si_me, 0, sizeof(si_me)); + si_me.sin_family = AF_INET; + si_me.sin_port = htons(udpPort); + si_me.sin_addr.s_addr = address; + if (bind(s, (struct sockaddr*)&si_me, sizeof(si_me))==-1) + diep("bind"); + + printf("UDP server listening on %s:%d\n", inet_ntoa(si_me.sin_addr), udpPort); + for (i=0; i<NPACK; i++) { + if (recvfrom(s, buf, BUFLEN, 0, (struct sockaddr*)&si_other, (socklen_t*)&slen)==-1) + diep("recvfrom()"); + printf("Received packet from %s:%d\nData: %s\n\n", + inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port), buf); + } + + printf("UDP server closing\n"); + close(s); + } + else /* !runServer */ + { + if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) + diep("socket"); + + memset((char *) &si_other, 0, sizeof(si_other)); + si_other.sin_family = AF_INET; + si_other.sin_port = htons(udpPort); + si_other.sin_addr.s_addr = address; + + printf("UDP client sending packets to %s:%d\n", inet_ntoa(si_other.sin_addr), udpPort); + + for (i=0; i<NPACK; i++) { + printf("Sending packet %d\n", i); + sprintf(buf, "This is packet %d\n", i); + if (sendto(s, buf, BUFLEN, 0, (struct sockaddr*)&si_other, slen)==-1) + diep("sendto()"); + } + + close(s); + printf("UDP client closing\n"); + } + return 0; +} diff --git a/tests/bionic/libc/glibc/assert/test-assert.c b/tests/bionic/libc/glibc/assert/test-assert.c new file mode 100644 index 00000000..26b58d4d --- /dev/null +++ b/tests/bionic/libc/glibc/assert/test-assert.c @@ -0,0 +1,88 @@ +/* Test assert(). + * + * This is hairier than you'd think, involving games with + * stdio and signals. + * + */ + +#include <signal.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <setjmp.h> + +jmp_buf rec; +char buf[160]; + +static void +sigabrt (int unused) +{ + longjmp (rec, 1); /* recover control */ +} + +#undef NDEBUG +#include <assert.h> +static void +assert1 (void) +{ + assert (1 == 2); +} + +static void +assert2 (void) +{ + assert (1 == 1); +} + + +#define NDEBUG +#include <assert.h> +static void +assert3 (void) +{ + assert (2 == 3); +} + +int +main (void) +{ + + volatile int failed = 1; + + fclose (stderr); + stderr = tmpfile (); + if(!stderr) + abort (); + + signal (SIGABRT, sigabrt); + + if (!setjmp (rec)) + assert1 (); + else + failed = 0; /* should happen */ + + if (!setjmp (rec)) + assert2 (); + else + failed = 1; /* should not happen */ + + if (!setjmp (rec)) + assert3 (); + else + failed = 1; /* should not happen */ + + rewind (stderr); + fgets (buf, 160, stderr); + if (!strstr (buf, "1 == 2")) + failed = 1; + + fgets (buf, 160, stderr); + if (strstr (buf, "1 == 1")) + failed = 1; + + fgets (buf, 160, stderr); + if (strstr (buf, "2 == 3")) + failed = 1; + + return failed; +} diff --git a/tests/bionic/libc/other/bench_locks.c b/tests/bionic/libc/other/bench_locks.c new file mode 100644 index 00000000..87b1c4c1 --- /dev/null +++ b/tests/bionic/libc/other/bench_locks.c @@ -0,0 +1,32 @@ +/* a small program to benchmark locking primitives with different implementations */ + +#include <pthread.h> +#include <sys/time.h> +#include <stdio.h> + +static double now(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec + tv.tv_usec/1000000.0; +} + +int main( void ) +{ + double t0, t1; + pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER; + int volatile lock2 = 0; + long count; + const long ITERATIONS = 1000000; + + /* pthread_mutex_lock */ + t0 = now(); + for (count = ITERATIONS; count > 0; count--) { + pthread_mutex_lock(&lock1); + pthread_mutex_unlock(&lock1); + } + t1 = now() - t0; + printf( "pthread_mutex_lock/unlock: %.5g us/op\n", (t1*1000000.0)/ITERATIONS ); + + return 0; +} diff --git a/tests/bionic/libc/other/test_aligned.c b/tests/bionic/libc/other/test_aligned.c new file mode 100644 index 00000000..8a66dd65 --- /dev/null +++ b/tests/bionic/libc/other/test_aligned.c @@ -0,0 +1,117 @@ +#include <stdio.h> +#include <arpa/inet.h> /* for htons() etc.. */ + +static char tab[8]; + +static void +read4( int o, unsigned val ) +{ + unsigned v = htonl(val); + unsigned v2; + + tab[o+0] = (char)(v >> 24); + tab[o+1] = (char)(v >> 16); + tab[o+2] = (char)(v >> 8); + tab[o+3] = (char)(v); + + printf( "read4: offset=%d value=%08x: ", o, val ); + fflush(stdout); + + v2 = *(unsigned*)(tab+o); + + if (v2 != val) { + printf( "FAIL (%08x)\n", v2 ); + } else { + printf( "ok\n" ); + } +} + +static void +writ4( int o, unsigned val ) +{ + unsigned v = htonl(val); + unsigned v2; + + printf( "writ4: offset=%d value=%08x: ", o, val ); + fflush(stdout); + + *(unsigned*)(tab+o) = v; + + v2 = ((unsigned)tab[o+0] << 24) | + ((unsigned)tab[o+1] << 16) | + ((unsigned)tab[o+2] << 8 ) | + ((unsigned)tab[o+3] ); + + if (v2 != val) { + printf( "FAIL (%08x)\n", v2 ); + } else { + printf( "ok\n" ); + } +} + +static void +read2( int o, unsigned val ) +{ + unsigned short v = htons(val); + unsigned short v2; + + tab[o+0] = (char)(v >> 8); + tab[o+1] = (char)(v); + + printf( "read2: offset=%d value=%08x: ", o, val ); + fflush(stdout); + + v2 = *(unsigned short*)(tab+o); + + if (v2 != val) { + printf( "FAIL (%04x)\n", v2 ); + } else { + printf( "ok\n" ); + } +} + +static void +writ2( int o, unsigned val ) +{ + unsigned short v = htons(val); + unsigned short v2; + + printf( "writ2: offset=%d value=%08x: ", o, val ); + fflush(stdout); + + *(unsigned short*)(tab+o) = v; + + v2 = ((unsigned)tab[o+0] << 8) | + ((unsigned)tab[o+1] ); + + if (v2 != val) { + printf( "FAIL (%08x)\n", v2 ); + } else { + printf( "ok\n" ); + } +} + + + +int main(void) +{ + read4( 0, 0x12345678 ); + writ4( 0, 0x12345678 ); + read4( 1, 0x12345678 ); + writ4( 1, 0x12345678 ); + read4( 2, 0x12345678 ); + writ4( 2, 0x12345678 ); + read4( 3, 0x12345678 ); + writ4( 3, 0x12345678 ); + + read2( 0, 0x1234 ); + writ2( 0, 0x1234 ); + read2( 1, 0x1234 ); + writ2( 1, 0x1234 ); + read2( 2, 0x1234 ); + writ2( 2, 0x1234 ); + read2( 3, 0x1234 ); + writ2( 3, 0x1234 ); + + return 0; +} diff --git a/tests/bionic/libc/other/test_arc4random.c b/tests/bionic/libc/other/test_arc4random.c new file mode 100644 index 00000000..4829a2d6 --- /dev/null +++ b/tests/bionic/libc/other/test_arc4random.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <stdio.h> + +int main(int argc, char *argv[]) +{ + unsigned int arc4random(); + + int i; + + for (i = 0; i < 50; i++) { + printf("%u\n", arc4random()); + } + return 0; +} diff --git a/tests/bionic/libc/other/test_atomics.c b/tests/bionic/libc/other/test_atomics.c new file mode 100644 index 00000000..0de2a938 --- /dev/null +++ b/tests/bionic/libc/other/test_atomics.c @@ -0,0 +1,17 @@ +#include <stdio.h> + + +extern int __atomic_dec(volatile int* addr); + +int main(int argc, const char *argv[]) +{ + int x = 5; + + while (x > -20) { + printf("old_x=%d\n", __atomic_dec(&x)); + printf("x=%d\n", x); + } + + printf ("OK\n"); + return 0; +} diff --git a/tests/bionic/libc/other/test_jpeg.c b/tests/bionic/libc/other/test_jpeg.c new file mode 100644 index 00000000..f481b9a3 --- /dev/null +++ b/tests/bionic/libc/other/test_jpeg.c @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* this small program is used to measure the performance of libjpeg decompression + * algorithm... + */ + +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <sys/time.h> +#include "jpeglib.h" +#include <setjmp.h> +#ifdef HAVE_ANDROID_OS +#include <hardware_legacy/qemu_tracing.h> +#endif + +#define USE_STDIO + +#define CHUNK 32768 + +typedef struct { + struct jpeg_source_mgr jpeg_mgr; + char* base; + char* cursor; + char* end; +} SourceMgrRec, *SourceMgr; + +static void +_source_init_source(j_decompress_ptr cinfo) +{ + SourceMgr src = (SourceMgr) cinfo->src; + + src->jpeg_mgr.next_input_byte = (unsigned char*)src->base, + src->jpeg_mgr.bytes_in_buffer = src->end - src->base; +} + +static int +_source_fill_input_buffer(j_decompress_ptr cinfo) +{ + SourceMgr src = (SourceMgr) cinfo->src; + + cinfo->err->error_exit((j_common_ptr)cinfo); + return FALSE; +} + +static void +_source_skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ + SourceMgr src = (SourceMgr) cinfo->src; + + if (src->jpeg_mgr.next_input_byte + num_bytes > (unsigned char*)src->end ) { + cinfo->err->error_exit((j_common_ptr)cinfo); + } + + src->jpeg_mgr.next_input_byte += num_bytes; + src->jpeg_mgr.bytes_in_buffer -= num_bytes; +} + +static int +_source_resync_to_restart( j_decompress_ptr cinfo, int desired) +{ + SourceMgr src = (SourceMgr) cinfo->src; + + src->jpeg_mgr.next_input_byte = (unsigned char*)src->base; + src->jpeg_mgr.bytes_in_buffer = src->end - src->base; + return TRUE; +} + +static void +_source_term_source(j_decompress_ptr cinfo) +{ + // nothing to do +} + +static void +_source_init( SourceMgr src, char* base, long size ) +{ + src->base = base; + src->cursor = base; + src->end = base + size; + + src->jpeg_mgr.init_source = _source_init_source; + src->jpeg_mgr.fill_input_buffer = _source_fill_input_buffer; + src->jpeg_mgr.skip_input_data = _source_skip_input_data; + src->jpeg_mgr.resync_to_restart = _source_resync_to_restart; + src->jpeg_mgr.term_source = _source_term_source; +} + + +typedef struct { + struct jpeg_error_mgr jpeg_mgr; + jmp_buf jumper; + int volatile error; + +} ErrorMgrRec, *ErrorMgr; + +static void _error_exit(j_common_ptr cinfo) +{ + ErrorMgr error = (ErrorMgr) cinfo->err; + + (*error->jpeg_mgr.output_message) (cinfo); + + /* Let the memory manager delete any temp files before we die */ + longjmp(error->jumper, -1); +} + +#ifdef USE_STDIO +int decompress(FILE* input_file, int dct_method, int disable_rgb) +#else +int decompress(char* data, long fsize) +#endif +{ + ErrorMgrRec errmgr; + SourceMgrRec sourcemgr; + struct jpeg_decompress_struct cinfo; + int volatile error = 0; + jmp_buf jumper; + int isRGB; + char* pixels; + JSAMPLE* temprow; + + memset( &cinfo, 0, sizeof(cinfo) ); + memset( &errmgr, 0, sizeof(errmgr) ); + jpeg_create_decompress(&cinfo); + cinfo.err = jpeg_std_error(&errmgr.jpeg_mgr); +#if 0 + errmgr.jpeg_mgr.error_exit = _error_exit; + errmgr.error = 0; +#endif + + if (setjmp(errmgr.jumper) != 0) { + fprintf(stderr, "returning error from jpeglib ---\n" ); + goto Exit; + } + +#ifdef USE_STDIO + /* Specify data source for decompression */ + jpeg_stdio_src(&cinfo, input_file); +#else + _source_init( &sourcemgr, data, fsize ); + cinfo.src = &sourcemgr.jpeg_mgr; +#endif + + jpeg_read_header(&cinfo, 1); + + if (3 == cinfo.num_components && JCS_RGB == cinfo.out_color_space) + isRGB = 1; + else if (1 == cinfo.num_components && JCS_GRAYSCALE == cinfo.out_color_space) + isRGB = 0; // could use Index8 config if we want... + else { + fprintf( stderr, "unsupported jpeg colorspace %d with %d components\n", + cinfo.jpeg_color_space, cinfo.num_components ); + goto Exit; + } + + cinfo.dct_method = dct_method; + if (disable_rgb) + cinfo.out_color_space = JCS_YCbCr; + + jpeg_start_decompress(&cinfo); + + temprow = calloc( cinfo.num_components * cinfo.output_width, sizeof(JSAMPLE) ); + + { + unsigned y; + for (y = 0; y < cinfo.output_height; y++) { + JSAMPLE* rowptr = temprow; + (void)jpeg_read_scanlines(&cinfo, &rowptr, 1); + } + } + jpeg_finish_decompress(&cinfo); + + free( temprow ); +Exit: + jpeg_destroy_decompress(&cinfo); + return error; +} + + +#define DEFAULT_REPEAT 10 + +static void usage(void) +{ + fprintf(stderr, "usage: test_jpeg [options] filename.jpg [filename2.jpg ...]\n" ); + fprintf(stderr, "options: -r NN repeat count (default %d)\n", DEFAULT_REPEAT ); + fprintf(stderr, " -d N idct method (0=default, 1=fastest, 2=slow, 3=float)\n" ); + fprintf(stderr, " -C no RGB color conversion (YCbCr instead)\n" ); + exit(1); +} + +static double +get_time_usec( void ) +{ +#ifdef HAVE_ANDROID_OS + struct timespec ts; + + if ( clock_gettime( CLOCK_MONOTONIC, &ts ) < 0 ) + fprintf(stderr, "clock_gettime: %s\n", strerror(errno) ); + + return ts.tv_sec*1e6 + ts.tv_nsec*1e-3; +#else + struct timeval tv; + if (gettimeofday( &tv, NULL ) < 0) + fprintf(stderr, "gettimeofday: %s\n", strerror(errno) ); + + return tv.tv_sec*1000000. + tv.tv_usec*1.0; +#endif +} + + +int main( int argc, char** argv ) +{ + FILE* f; + int repeat_count = DEFAULT_REPEAT; + int dct_method = JDCT_DEFAULT; + int disable_rgb = 0; + double usec0, usec1; + + if (argc < 2) + usage(); + + for ( ; argc > 1 && argv[1][0] == '-'; argc--, argv++) { + const char* arg = &argv[1][1]; + switch (arg[0]) { + case 'r': + if (arg[1] == 0) { + if (argc < 3) + usage(); + arg = argv[2]; + argc--; + argv++; + } else + arg += 1; + + repeat_count = strtol(arg, NULL, 10); + + if (repeat_count <= 0) + repeat_count = 1; + break; + + case 'C': + disable_rgb = 1; + break; + + case 'd': + if (arg[1] == 0) { + if (argc < 3) + usage(); + arg = argv[2]; + argc--; + argv++; + } else + arg += 1; + + dct_method = strtol(arg, NULL, 10); + switch (dct_method) { + case 0: + dct_method = JDCT_DEFAULT; + break; + case 1: + dct_method = JDCT_IFAST; + break; + case 2: + dct_method = JDCT_ISLOW; + break; + case 3: + dct_method = JDCT_FLOAT; + break; + default: + usage(); + } + break; + + default: + usage(); + } + } + + for ( ; argc > 1; argc--, argv++ ) + { + long fsize; + char* data; + FILE* f = fopen( argv[1], "rb" ); + int rr; + + if (f == NULL) { + fprintf(stderr, "could not open '%s': %s\n", argv[1], strerror(errno) ); + continue; + } + + fseek( f, 0, SEEK_END ); + fsize = ftell(f); + fseek( f, 0, SEEK_SET ); + + usec0 = get_time_usec(); +#ifdef HAVE_ANDROID_OS + qemu_start_tracing(); +#endif +#ifdef USE_STDIO + for ( rr = repeat_count; rr > 0; rr-- ) { + fseek( f, 0, SEEK_SET ); + decompress(f, dct_method, disable_rgb); + } + fclose( f ); +#else + + data = malloc( fsize ); + if (data == NULL) { + if (fsize > 0) + fprintf(stderr, "could not allocate %ld bytes to load '%s'\n", fsize, argv[1] ); + fclose(f); + continue; + } + fread( data, 1, fsize, f ); + fclose(f); + + usec1 = get_time_usec() - usec0; + printf( "compressed load: %10.2f ms (%ld bytes)\n", usec1*1e-3, fsize ); + + usec0 = get_time_usec(); + for ( rr = repeat_count; rr > 0; rr -- ) + { + decompress( data, fsize ); + } + free( data ); +#endif +#ifdef HAVE_ANDROID_OS + qemu_stop_tracing(); +#endif + usec1 = get_time_usec() - usec0; + printf( "decompression took: %10.3f ms (%.2f KB/s, %d passes)\n", usec1/1e3, fsize*(1e6/1024)*repeat_count/usec1, repeat_count ); + } + return 0; +} diff --git a/tests/bionic/libc/other/test_sysconf.c b/tests/bionic/libc/other/test_sysconf.c new file mode 100644 index 00000000..717cbcb3 --- /dev/null +++ b/tests/bionic/libc/other/test_sysconf.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#define T(_name,_cond) \ + errno = 0; \ + printf( "testing %-*s : ", 32, #_name ); \ + ret = sysconf( _name ); \ + if (ret < 0 && errno != 0) { \ + printf( "error: %s\n", strerror(errno) ); \ + } else { \ + if ( ret _cond ) { \ + printf( "OK (%d)\n", ret ); \ + } else { \ + printf( "ERROR: %d does not meet %s\n", ret, #_cond ); \ + } \ + } + +int main( void ) +{ + int ret; + T(_SC_ARG_MAX, > 0); + T(_SC_BC_BASE_MAX, |1 ); + T(_SC_BC_DIM_MAX, |1 ); + T(_SC_BC_SCALE_MAX, |1 ); + T(_SC_BC_STRING_MAX, |1 ); + T(_SC_CHILD_MAX, >0 ); + T(_SC_CLK_TCK, >0 ); + T(_SC_COLL_WEIGHTS_MAX, |1 ); + T(_SC_EXPR_NEST_MAX, |1 ); + T(_SC_LINE_MAX, > 256 ); + T(_SC_NGROUPS_MAX, >0 ); + T(_SC_OPEN_MAX, >128 ); + T(_SC_PASS_MAX, |1 ); + T(_SC_2_C_BIND, >0 ); + T(_SC_2_C_DEV, |1 ); + T(_SC_2_C_VERSION, |1 ); + T(_SC_2_CHAR_TERM, |1 ); + T(_SC_2_FORT_DEV, |1 ); + T(_SC_2_FORT_RUN, |1 ); + T(_SC_2_LOCALEDEF, |1 ); + T(_SC_2_SW_DEV, |1 ); + T(_SC_2_UPE, |1 ); + T(_SC_2_VERSION, |1); + T(_SC_JOB_CONTROL, == 1); + T(_SC_SAVED_IDS, == 1); + T(_SC_VERSION, |1); + T(_SC_RE_DUP_MAX, |1); + T(_SC_STREAM_MAX, > 0); + T(_SC_TZNAME_MAX, |1 ); + T(_SC_XOPEN_CRYPT, |1 ); + T(_SC_XOPEN_ENH_I18N, |1 ); + T(_SC_XOPEN_SHM, |1 ); + T(_SC_XOPEN_VERSION, |1 ); + T(_SC_XOPEN_XCU_VERSION, |1 ); + T(_SC_XOPEN_REALTIME, |1 ); + T(_SC_XOPEN_REALTIME_THREADS, |1 ); + T(_SC_XOPEN_LEGACY, |1 ); + T(_SC_ATEXIT_MAX, >32 ); + T(_SC_IOV_MAX, >0 ); + T(_SC_PAGESIZE, == 4096 ); + T(_SC_PAGE_SIZE, == 4096 ); + T(_SC_XOPEN_UNIX, |1 ); + T(_SC_XBS5_ILP32_OFF32, |1 ); + T(_SC_XBS5_ILP32_OFFBIG, |1 ); + T(_SC_XBS5_LP64_OFF64, |1 ); + T(_SC_XBS5_LPBIG_OFFBIG, |1 ); + T(_SC_AIO_LISTIO_MAX, |1 ); + T(_SC_AIO_MAX, |1 ); + T(_SC_AIO_PRIO_DELTA_MAX, |1 ); + T(_SC_DELAYTIMER_MAX, >0 ); + T(_SC_MQ_OPEN_MAX, |1 ); + T(_SC_MQ_PRIO_MAX, >0 ); + T(_SC_RTSIG_MAX, |1 ); + T(_SC_SEM_NSEMS_MAX, |1 ); + T(_SC_SEM_VALUE_MAX, |1 ); + T(_SC_SIGQUEUE_MAX, >0 ); + T(_SC_TIMER_MAX, |1 ); + T(_SC_ASYNCHRONOUS_IO, |1 ); + T(_SC_FSYNC, |1 ); + T(_SC_MAPPED_FILES, |1 ); + T(_SC_MEMLOCK, |1 ); + T(_SC_MEMLOCK_RANGE, |1 ); + T(_SC_MEMORY_PROTECTION, |1 ); + T(_SC_MESSAGE_PASSING, |1 ); + T(_SC_PRIORITIZED_IO, |1 ); + T(_SC_PRIORITY_SCHEDULING, |1 ); + T(_SC_REALTIME_SIGNALS, |1 ); + T(_SC_SEMAPHORES, |1 ); + T(_SC_SHARED_MEMORY_OBJECTS, |1 ); + T(_SC_SYNCHRONIZED_IO, |1 ); + T(_SC_TIMERS, |1 ); + T(_SC_GETGR_R_SIZE_MAX, |1 ); + T(_SC_GETPW_R_SIZE_MAX, |1 ); + T(_SC_LOGIN_NAME_MAX, |1 ); + T(_SC_THREAD_DESTRUCTOR_ITERATIONS, |1 ); + T(_SC_THREAD_KEYS_MAX, > 0 ); + T(_SC_THREAD_STACK_MIN, >= 8192 ); + T(_SC_THREAD_THREADS_MAX, |1 ); + T(_SC_TTY_NAME_MAX, > 0 ); + T(_SC_THREADS, |1 ); + T(_SC_THREAD_ATTR_STACKADDR, |1 ); + T(_SC_THREAD_ATTR_STACKSIZE, |1 ); + T(_SC_THREAD_PRIORITY_SCHEDULING, |1 ); + T(_SC_THREAD_PRIO_INHERIT, |1 ); + T(_SC_THREAD_PRIO_PROTECT, |1 ); + T(_SC_THREAD_SAFE_FUNCTIONS, |1 ); + return 0; +} diff --git a/tests/bionic/libc/other/test_system.c b/tests/bionic/libc/other/test_system.c new file mode 100644 index 00000000..adb4c56a --- /dev/null +++ b/tests/bionic/libc/other/test_system.c @@ -0,0 +1,28 @@ +#include <stdlib.h> +#include <stdio.h> +#include <sys/wait.h> +#include <errno.h> + +int +main(int argc, char *argv[]) +{ + int rv; + + if (argc < 2) + return -1; + + rv = system(argv[1]); + if (rv < 0) { + fprintf(stderr, "Error calling system(): %d\n", errno); + return 1; + } + + printf("Done!\n"); + + if (WEXITSTATUS(rv) != 0) { + fprintf(stderr, "Command returned non-zero exit code: %d\n", + WEXITSTATUS(rv)); + return 1; + } + return 0; +} diff --git a/tests/bionic/libc/other/test_thread_max.c b/tests/bionic/libc/other/test_thread_max.c new file mode 100644 index 00000000..7aeb5c5a --- /dev/null +++ b/tests/bionic/libc/other/test_thread_max.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <pthread.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> + +static void* +thread_func( void* arg ) +{ + fprintf(stderr, "thread %ld\n", (long)arg ); + return NULL; +} + +int main( void ) +{ + int count; + pthread_attr_t attr; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ); + pthread_attr_setstacksize( &attr, 16*4096 ); + + for ( count = 0; count != ~0; count++ ) { + pthread_t thread; + struct timespec ts; + + if (pthread_create( &thread, &attr, thread_func, (void*)(long)count ) < 0) { + fprintf(stderr, "could not create thread %d\n", count); + break; + } + ts.tv_sec = 0; + ts.tv_nsec = 0.002*1e9; + nanosleep( &ts, &ts ); + } + sleep(1); + return 0; +} diff --git a/tests/bionic/libc/other/test_timer_create.c b/tests/bionic/libc/other/test_timer_create.c new file mode 100644 index 00000000..8995e121 --- /dev/null +++ b/tests/bionic/libc/other/test_timer_create.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <stdio.h> +#include <time.h> +#include <signal.h> +#include <pthread.h> +#include <string.h> +#include <unistd.h> + +void +handle(sigval_t v) +{ + time_t t; + char p[32]; + + time(&t); + strftime(p, sizeof(p), "%T", localtime(&t)); + printf("%s thread %d, val = %d, signal captured.\n", + p, (int)pthread_self(), v.sival_int); + return; +} + +int +create(int seconds, int id) +{ + timer_t tid; + struct sigevent se; + struct itimerspec ts, ots; + + memset(&se, 0, sizeof (se)); + se.sigev_notify = SIGEV_THREAD; + se.sigev_notify_function = handle; + se.sigev_value.sival_int = id; + + if (timer_create (CLOCK_REALTIME, &se, &tid) < 0) + { + perror ("timer_creat"); + return -1; + } + puts ("timer_create successfully."); + ts.it_value.tv_sec = 3; + ts.it_value.tv_nsec = 0; + ts.it_interval.tv_sec = seconds; + ts.it_interval.tv_nsec = 0; + if (timer_settime (tid, TIMER_ABSTIME, &ts, &ots) < 0) + { + perror ("timer_settime"); + return -1; + } + return 0; +} + +int +main (void) +{ + if (create (3, 1) < 0) return 1; + if (create (5, 2) < 0) return 1; + for (;;) + { + sleep (10); + } + return 0; +} diff --git a/tests/bionic/libc/other/test_timer_create2.c b/tests/bionic/libc/other/test_timer_create2.c new file mode 100644 index 00000000..10e95e4e --- /dev/null +++ b/tests/bionic/libc/other/test_timer_create2.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <stdio.h> +#include <time.h> +#include <signal.h> +#include <pthread.h> +#include <string.h> +#include <unistd.h> + +void +handle(int v) +{ + time_t t; + char p[32]; + + time(&t); + strftime(p, sizeof(p), "%T", localtime(&t)); + printf("%s thread %p, val = %d, signal captured.\n", + p, pthread_self(), v); + return; +} + +int +create(int seconds, int id) +{ + timer_t tid; + struct sigevent se; + struct itimerspec ts, ots; + + memset(&se, 0, sizeof (se)); + se.sigev_notify = SIGEV_SIGNAL; + se.sigev_signo = SIGUSR1; + + if (timer_create (CLOCK_REALTIME, &se, &tid) < 0) + { + perror ("timer_creat"); + return -1; + } + printf("timer_create successfully = %d.\n", (int)tid); + ts.it_value.tv_sec = 3; + ts.it_value.tv_nsec = 0; + ts.it_interval.tv_sec = seconds; + ts.it_interval.tv_nsec = 0; + if (timer_settime (tid, TIMER_ABSTIME, &ts, &ots) < 0) + { + perror ("timer_settime"); + return -1; + } + return 0; +} + +int +main (void) +{ + sigset_t mask[1]; + struct sigaction act[1]; + + sigemptyset(mask); + sigaddset(mask, SIGUSR1); + sigprocmask(SIG_UNBLOCK,mask,NULL); + + memset(act, 0, sizeof(*act)); + act->sa_handler = handle; + sigaction( SIGUSR1, act, NULL ); + + printf("main thread is %p\n", pthread_self()); + + if (create (3, 1) < 0) return 1; + if (create (5, 2) < 0) return 1; + for (;;) + { + sleep (10); + } + return 0; +} diff --git a/tests/bionic/libc/other/test_timer_create3.c b/tests/bionic/libc/other/test_timer_create3.c new file mode 100644 index 00000000..193f37ef --- /dev/null +++ b/tests/bionic/libc/other/test_timer_create3.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <stdio.h> +#include <time.h> +#include <signal.h> +#include <pthread.h> +#include <string.h> +#include <unistd.h> + +static timer_t tid; +static int count; + +/* this test program is there to check that disarming a timer + * can be done by calling timer_settime() with an it_interval + * value of 0 + */ +void +handle(sigval_t v) +{ + time_t t; + char p[32]; + struct itimerspec ts; + + time(&t); + strftime(p, sizeof(p), "%T", localtime(&t)); + printf("%s thread %d, val = %d, signal captured.\n", + p, (int)pthread_self(), v.sival_int); + count += 1; + + /* this should disable the timer, and hence make 'count' no more than 1 */ + ts.it_value.tv_sec = 0; + ts.it_value.tv_nsec = 0; + ts.it_interval.tv_sec = 1; + ts.it_interval.tv_nsec = 0; + timer_settime(tid, TIMER_ABSTIME, &ts, NULL); + + return; +} + +int +create(int seconds, int id) +{ + struct sigevent se; + struct itimerspec ts, ots; + + memset(&se, 0, sizeof (se)); + se.sigev_notify = SIGEV_THREAD; + se.sigev_notify_function = handle; + se.sigev_value.sival_int = id; + + if (timer_create (CLOCK_REALTIME, &se, &tid) < 0) + { + perror ("timer_creat"); + return -1; + } + puts ("timer_create successfully."); + ts.it_value.tv_sec = 0; + ts.it_value.tv_nsec = 1; + ts.it_interval.tv_sec = seconds; + ts.it_interval.tv_nsec = 0; + if (timer_settime (tid, TIMER_ABSTIME, &ts, &ots) < 0) + { + perror ("timer_settime"); + return -1; + } + return 0; +} + +int +main (void) +{ + if (create (1, 1) < 0) return 1; + sleep (4); + + if (count == 1) { + printf("OK\n"); + return 0; + } else { + printf("KO (count=%d)\n", count); + return 1; + } +} diff --git a/tests/bionic/libc/other/test_vfprintf_leak.c b/tests/bionic/libc/other/test_vfprintf_leak.c new file mode 100644 index 00000000..4e94c51b --- /dev/null +++ b/tests/bionic/libc/other/test_vfprintf_leak.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* this test is used to check that a memory-leak in vfprintf was fixed. + * the initial code leaked heap memory each time a formatted double was printed + */ +#include <stdio.h> + +extern size_t dlmalloc_footprint(); + +int main(void) +{ + size_t initial = dlmalloc_footprint(); + size_t final; + char temp[64]; + int n; + + for (n = 0; n < 10000; n++) + snprintf( temp, sizeof(temp), "%g", n*0.647287623 ); + + final = dlmalloc_footprint(); + /* vfprintf uses temporary heap blocks to do the formatting, so */ + /* it's OK to have one page in there */ + if (final <= 4096) { + printf( "OK: initial = %ld, final == %ld\n", (long)initial, (long)final ); + return 0; + } else { + fprintf(stderr, "KO: initial == %ld, final == %ld\n", (long)initial, (long)final ); + return 1; + } +} diff --git a/tests/bionic/libc/other/test_zlib.c b/tests/bionic/libc/other/test_zlib.c new file mode 100644 index 00000000..3eae8279 --- /dev/null +++ b/tests/bionic/libc/other/test_zlib.c @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* this small program is used to measure the performance of zlib's inflate + * algorithm... + */ + +/* most code lifted from the public-domain http://www.zlib.net/zpipe.c */ + +#include <zlib.h> +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <sys/time.h> + +#define CHUNK 32768 + +int def(FILE *source, FILE *dest, int level) +{ + int ret, flush; + unsigned have; + z_stream strm; + unsigned char in[CHUNK]; + unsigned char out[CHUNK]; + + /* allocate deflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = deflateInit(&strm, level); + if (ret != Z_OK) + return ret; + + /* compress until end of file */ + do { + strm.avail_in = fread(in, 1, CHUNK, source); + if (ferror(source)) { + (void)deflateEnd(&strm); + return Z_ERRNO; + } + flush = feof(source) ? Z_FINISH : Z_NO_FLUSH; + strm.next_in = in; + + /* run deflate() on input until output buffer not full, finish + compression if all of source has been read in */ + do { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = deflate(&strm, flush); /* no bad return value */ + have = CHUNK - strm.avail_out; + if (fwrite(out, 1, have, dest) != have || ferror(dest)) { + (void)deflateEnd(&strm); + return Z_ERRNO; + } + } while (strm.avail_out == 0); + + /* done when last data in file processed */ + } while (flush != Z_FINISH); + + /* clean up and return */ + (void)deflateEnd(&strm); + return Z_OK; +} + + +int inf(FILE *source) +{ + int ret; + unsigned have; + z_stream strm; + static unsigned char in[CHUNK]; + static unsigned char out[CHUNK]; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); + if (ret != Z_OK) + return ret; + + /* decompress until deflate stream ends or end of file */ + do { + strm.avail_in = fread(in, 1, CHUNK, source); + if (ferror(source)) { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + if (strm.avail_in == 0) + break; + strm.next_in = in; + + /* run inflate() on input until output buffer not full */ + do { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return ret; + } + } while (strm.avail_out == 0); + + /* done when inflate() says it's done */ + } while (ret != Z_STREAM_END); + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + +#define DEFAULT_REPEAT 10 +#define DEFAULT_LEVEL 9 + +static void usage(void) +{ + fprintf(stderr, "usage: test_zlib [options] filename [filename2 ...]\n" ); + fprintf(stderr, "options: -r NN repeat count (default %d)\n", DEFAULT_REPEAT ); + fprintf(stderr, " -N set compression level (default %d)\n", DEFAULT_LEVEL ); + exit(1); +} + +static double +get_time_usec( void ) +{ +#ifdef HAVE_ANDROID_OS + struct timespec ts; + + if ( clock_gettime( CLOCK_MONOTONIC, &ts ) < 0 ) + fprintf(stderr, "clock_gettime: %s\n", strerror(errno) ); + + return ts.tv_sec*1e6 + ts.tv_nsec*1e-3; +#else + struct timeval tv; + if (gettimeofday( &tv, NULL ) < 0) + fprintf(stderr, "gettimeofday: %s\n", strerror(errno) ); + + return tv.tv_sec*1000000. + tv.tv_usec*1.0; +#endif +} + +int main( int argc, char** argv ) +{ + FILE* f; + char tempfile[256]; + int repeat_count = DEFAULT_REPEAT; + int compression_level = DEFAULT_LEVEL; + double usec0, usec1; + + if (argc < 2) + usage(); + + for ( ; argc > 1 && argv[1][0] == '-'; argc--, argv++) { + const char* arg = &argv[1][1]; + switch (arg[0]) { + case 'r': + if (arg[1] == 0) { + if (argc < 3) + usage(); + arg = argv[2]; + argc--; + argv++; + } else + arg += 1; + + repeat_count = strtol(arg, NULL, 10); + + if (repeat_count <= 0) + repeat_count = 1; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + compression_level = arg[0] - '0'; + break; + + default: + usage(); + } + } + + sprintf(tempfile, "/tmp/ztest.%d", getpid() ); + + for ( ; argc > 1; argc--, argv++ ) + { + /* first, compress the file into a temporary storage */ + FILE* f = fopen(argv[1], "rb"); + FILE* out = NULL; + long fsize; + int ret, rr; + + if (f == NULL) { + fprintf(stderr, "could not open '%s': %s\n", argv[1], strerror(errno) ); + continue; + } + + printf( "testing %s\n", argv[1] ); + fseek( f, 0, SEEK_END ); + fsize = ftell(f); + fseek( f, 0, SEEK_SET ); + + out = fopen( tempfile, "wb" ); + if (out == NULL) { + fprintf(stderr, "could not create '%s': %s\n", tempfile, strerror(errno)); + fclose(f); + continue; + } + + usec0 = get_time_usec(); + + ret = def( f, out, compression_level ); + + usec1 = get_time_usec() - usec0; + printf( "compression took: %10.3f ms (%.2f KB/s)\n", usec1/1e3, fsize*(1e6/1024)/usec1 ); + + fclose( out ); + fclose(f); + + usec0 = get_time_usec(); + f = fopen( tempfile, "rb" ); + + for ( rr = repeat_count; rr > 0; rr -- ) + { + fseek( f, 0, SEEK_SET ); + inf(f); + } + fclose( f ); + usec1 = get_time_usec() - usec0; + printf( "decompression took: %10.3f ms (%.2f KB/s, %d passes)\n", usec1/1e3, fsize*(1e6/1024)*repeat_count/usec1, repeat_count ); + } + + unlink(tempfile); + return 0; +} diff --git a/tests/cpueater/Android.mk b/tests/cpueater/Android.mk new file mode 100644 index 00000000..29a524e1 --- /dev/null +++ b/tests/cpueater/Android.mk @@ -0,0 +1,32 @@ +# 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) + +include $(CLEAR_VARS) +LOCAL_MODULE := daemonize +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) +LOCAL_MODULE_TAGS := tests eng +LOCAL_SRC_FILES := daemonize.c +LOCAL_SHARED_LIBRARIES := libhardware_legacy +include $(BUILD_EXECUTABLE) + diff --git a/tests/cpueater/cpueater.c b/tests/cpueater/cpueater.c new file mode 100644 index 00000000..c7911392 --- /dev/null +++ b/tests/cpueater/cpueater.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Simple cpu eater busy loop. Runs as a daemon. prints the child PID to + * std so you can easily kill it later. + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> + + +int main(int argc, char *argv[]) +{ + pid_t pid; + int life_universe_and_everything; + int fd; + + switch(fork()) { + case -1: + perror(argv[0]); + exit(1); + break; + case 0: /* child */ + chdir("/"); + umask(0); + setpgrp(); + setsid(); + /* fork again to fully detach from controlling terminal. */ + switch(pid = fork()) { + case -1: + break; + case 0: /* second child */ + /* redirect to /dev/null */ + close(0); + open("/dev/null", 0); + close(1); + if(open("/dev/null", O_WRONLY) < 0) { + perror("/dev/null"); + exit(1); + } + fflush(stdout); + close(2); + dup(1); + for (fd = 3; fd < 256; fd++) { + close(fd); + } + /* busy looper */ + while (1) { + life_universe_and_everything = 42 * 2; + } + default: + /* so caller can easily kill it later. */ + printf("%d\n", pid); + exit(0); + break; + } + break; + default: + exit(0); + break; + } + return 0; +} + + +/* vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab */ + diff --git a/tests/cpueater/daemonize.c b/tests/cpueater/daemonize.c new file mode 100644 index 00000000..3839cdcf --- /dev/null +++ b/tests/cpueater/daemonize.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/wait.h> + + +#include "hardware_legacy/power.h" + + +main(int argc, char **argv) +{ + int pid, fd, mode; + unsigned int delay = 0; + int status = 0; + char *file = 0; + char lockid[32]; + + if (argc < 2) { + printf("Usage: %s [-f logfile] [-a] [-d delay] <program>\n", argv[0]); + exit(1); + } + close(0); open("/dev/null", 0); + close(1); + + mode = O_TRUNC; + + while(**++argv == '-') { + while(*++*argv) { + switch(**argv) { + case 'f': + if(*++*argv) + file = *argv; + else + file = *++argv; + goto next_arg; + case 'd': + if(*++*argv) + delay = atoi(*argv); + else + delay = atoi(*++argv); + goto next_arg; + case 'a': + mode = O_APPEND; + break; + } + } +next_arg: ; + } + + if (file) { + if(open(file, O_WRONLY|mode|O_CREAT, 0666) < 0) { + perror(file); + exit(1); + } + } + else { + if(open("/dev/null", O_WRONLY) < 0) { + perror("/dev/null"); + exit(1); + } + } + + switch(pid = fork()) { + case -1: + perror(argv[0]); + exit(1); + break; + case 0: + fflush(stdout); + close(2); dup(1); /* join stdout and stderr */ + chdir("/"); + umask(0); + setpgrp(); + setsid(); + for (fd = 3; fd < 256; fd++) { + close(fd); + } + if(delay) { + snprintf(lockid, 32, "daemonize%d", (int) getpid()); + acquire_wake_lock(PARTIAL_WAKE_LOCK, lockid); + } + + switch(pid = fork()) { + case -1: + break; + case 0: + if(delay) { + sleep(delay); + } + execv(argv[0], argv); + execvp(argv[0], argv); + perror(argv[0]); + break; + default: + if(delay) { + waitpid(pid, &status, 0); + release_wake_lock(lockid); + } + _exit(0); + } + _exit(1); + break; + default: + exit(0); + break; + } +} + +/* vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab */ diff --git a/tests/framebuffer/Android.mk b/tests/framebuffer/Android.mk new file mode 100644 index 00000000..d6a8537d --- /dev/null +++ b/tests/framebuffer/Android.mk @@ -0,0 +1,33 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + refresh.c + +LOCAL_SHARED_LIBRARIES := \ + libcutils + +LOCAL_MODULE:= test-fb-refresh + +LOCAL_MODULE_TAGS := tests + +ifeq ($(TARGET_SIMULATOR),true) + ifeq ($(HOST_OS),linux) + # need this for clock_gettime() + LOCAL_LDLIBS += -lrt + endif +endif + +include $(BUILD_EXECUTABLE) + +## + +ifneq ($(TARGET_SIMULATOR),true) +include $(CLEAR_VARS) +LOCAL_SRC_FILES := fb_test.c +LOCAL_MODULE = test-fb-simple +LOCAL_MODULE_TAGS := tests +LOCAL_FORCE_STATIC_EXECUTABLE := true +LOCAL_STATIC_LIBRARIES := libc +include $(BUILD_EXECUTABLE) +endif # sim diff --git a/tests/framebuffer/fb_test.c b/tests/framebuffer/fb_test.c new file mode 100644 index 00000000..6fdbf3b3 --- /dev/null +++ b/tests/framebuffer/fb_test.c @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <unistd.h> + +#include <fcntl.h> +#include <stdio.h> + +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <time.h> + +#include <linux/fb.h> +#include <linux/kd.h> + +#include <pixelflinger/pixelflinger.h> + +#include "minui.h" + +typedef struct { + GGLSurface texture; + unsigned cwidth; + unsigned cheight; + unsigned ascent; +} GRFont; + +static GGLContext *gr_context = 0; +static GGLSurface gr_framebuffer[2]; +static unsigned gr_active_fb = 0; + +static int gr_fb_fd = -1; +static int gr_vt_fd = -1; + +static struct fb_var_screeninfo vi; +struct fb_fix_screeninfo fi; +struct timespec tv, tv2; + +static void dumpinfo(struct fb_fix_screeninfo *fi, + struct fb_var_screeninfo *vi); + +static int get_framebuffer(GGLSurface *fb) +{ + int fd; + void *bits; + + fd = open("/dev/graphics/fb0", O_RDWR); + if(fd < 0) { + perror("cannot open fb0"); + return -1; + } + + if(ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) { + perror("failed to get fb0 info"); + return -1; + } + + if(ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) { + perror("failed to get fb0 info"); + return -1; + } + + dumpinfo(&fi, &vi); + + bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if(bits == MAP_FAILED) { + perror("failed to mmap framebuffer"); + return -1; + } + + fb->version = sizeof(*fb); + fb->width = vi.xres; + fb->height = vi.yres; + fb->stride = fi.line_length / (vi.bits_per_pixel >> 3); + fb->data = bits; + fb->format = GGL_PIXEL_FORMAT_RGB_565; + + fb++; + + fb->version = sizeof(*fb); + fb->width = vi.xres; + fb->height = vi.yres; + fb->stride = fi.line_length / (vi.bits_per_pixel >> 3); + fb->data = (void*) (((unsigned) bits) + vi.yres * vi.xres * 2); + fb->format = GGL_PIXEL_FORMAT_RGB_565; + + return fd; +} + +static void set_active_framebuffer(unsigned n) +{ + if(n > 1) return; + vi.yres_virtual = vi.yres * 2; + vi.yoffset = n * vi.yres; + if(ioctl(gr_fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) { + fprintf(stderr,"active fb swap failed!\n"); + } +} + +static void dumpinfo(struct fb_fix_screeninfo *fi, struct fb_var_screeninfo *vi) +{ + fprintf(stderr,"vi.xres = %d\n", vi->xres); + fprintf(stderr,"vi.yres = %d\n", vi->yres); + fprintf(stderr,"vi.xresv = %d\n", vi->xres_virtual); + fprintf(stderr,"vi.yresv = %d\n", vi->yres_virtual); + fprintf(stderr,"vi.xoff = %d\n", vi->xoffset); + fprintf(stderr,"vi.yoff = %d\n", vi->yoffset); + fprintf(stderr, "vi.bits_per_pixel = %d\n", vi->bits_per_pixel); + + fprintf(stderr, "fi.line_length = %d\n", fi->line_length); + +} + +int gr_init(void) +{ + int fd; + + + fd = open("/dev/tty0", O_RDWR | O_SYNC); + if(fd < 0) return -1; + + if(ioctl(fd, KDSETMODE, (void*) KD_GRAPHICS)) { + close(fd); + return -1; + } + + gr_fb_fd = get_framebuffer(gr_framebuffer); + + if(gr_fb_fd < 0) { + ioctl(fd, KDSETMODE, (void*) KD_TEXT); + close(fd); + return -1; + } + + gr_vt_fd = fd; + + /* start with 0 as front (displayed) and 1 as back (drawing) */ + gr_active_fb = 0; + set_active_framebuffer(0); + + return 0; +} + +void gr_exit(void) +{ + close(gr_fb_fd); + gr_fb_fd = -1; + + ioctl(gr_vt_fd, KDSETMODE, (void*) KD_TEXT); + close(gr_vt_fd); + gr_vt_fd = -1; +} + +int gr_fb_width(void) +{ + return gr_framebuffer[0].width; +} + +int gr_fb_height(void) +{ + return gr_framebuffer[0].height; +} + +uint16_t red = 0xf800; +uint16_t green = 0x07e0; +uint16_t blue = 0x001f; + +void draw_grid(int w, int h, uint16_t* loc) { + int i, j; + int v; + int stride = fi.line_length / (vi.bits_per_pixel >> 3); + + for (j = 0; j < h/2; j++) { + for (i = 0; i < w/2; i++) + loc[i + j*(stride)] = red; + for (; i < w; i++) + loc[i + j*(stride)] = green; + } + for (; j < h; j++) { + for (i = 0; i < w/2; i++) + loc[i + j*(stride)] = blue; + for (; i < w; i++) + loc[i + j*(stride)] = 0xffff; + } + +} + +void clear_screen(int w, int h, uint16_t* loc) +{ + int i,j; + int stride = fi.line_length / (vi.bits_per_pixel >> 3); + + for (j = 0; j < h; j++) + for (i = 0; i < w; i++) + loc[i + j*(stride)] = 0x0000; +} + + +int main(int argc, char **argv) { + int w; + int h; + gr_init(); + w = vi.xres; + h = vi.yres; + clear_screen(w, h, (uint16_t *)gr_framebuffer[0].data); + + if (argc > 2) { + w = atoi(argv[1]); + h = atoi(argv[2]); + } + + draw_grid(w, h, (uint16_t *)gr_framebuffer[0].data); + printf("%lld\n", (tv2.tv_sec*1000000000LL + tv2.tv_nsec) - (tv.tv_sec*1000000000LL + tv.tv_nsec)); + set_active_framebuffer(1); + set_active_framebuffer(0); + + return 0; +} diff --git a/tests/framebuffer/minui.h b/tests/framebuffer/minui.h new file mode 100644 index 00000000..4efc9719 --- /dev/null +++ b/tests/framebuffer/minui.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MINUI_H_ +#define _MINUI_H_ + +int gr_init(void); +void gr_exit(void); + +int gr_fb_width(void); +int gr_fb_height(void); +void gr_flip(void); + +void gr_color(unsigned char r, unsigned char g, unsigned char b); +void gr_fill(int x, int y, int w, int h); +int gr_text(int x, int y, const char *s); +int gr_measure(const char *s); + + +typedef struct event event; + +struct event +{ + unsigned type; + unsigned code; + unsigned value; +}; + +int ev_init(void); +void ev_exit(void); + +int ev_get(event *ev, unsigned dont_wait); + +#define TYPE_KEY 1 + +#define KEY_UP 103 +#define KEY_DOWN 108 +#define KEY_LEFT 105 +#define KEY_RIGHT 106 +#define KEY_CENTER 232 +#define KEY_ENTER 28 + +#endif diff --git a/tests/framebuffer/refresh.c b/tests/framebuffer/refresh.c new file mode 100644 index 00000000..43dc7cff --- /dev/null +++ b/tests/framebuffer/refresh.c @@ -0,0 +1,169 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <sys/types.h> + +#include <unistd.h> +#include <fcntl.h> +#include <math.h> +#include <time.h> +#include <errno.h> + +#include <sys/resource.h> +#include <sys/syscall.h> +#include <sys/mman.h> + +#include <linux/fb.h> + +int64_t systemTime() +{ + struct timespec t; + t.tv_sec = t.tv_nsec = 0; + clock_gettime(CLOCK_MONOTONIC, &t); + return (int64_t)(t.tv_sec)*1000000000LL + t.tv_nsec; +} + +int main(int argc, char** argv) +{ + char const * const device_template[] = { + "/dev/graphics/fb%u", + "/dev/fb%u", + 0 }; + int fd = -1; + int i=0; + int j=0; + char name[64]; + while ((fd==-1) && device_template[i]) { + snprintf(name, 64, device_template[i], 0); + fd = open(name, O_RDWR, 0); + i++; + } + if (fd < 0) + return -errno; + + struct fb_fix_screeninfo finfo; + if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) + return -errno; + + struct fb_var_screeninfo info; + if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) + return -errno; + + info.reserved[0] = 0; + info.reserved[1] = 0; + info.reserved[2] = 0; + info.xoffset = 0; + info.yoffset = 0; + info.bits_per_pixel = 16; + info.activate = FB_ACTIVATE_NOW; + + if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) { + printf("FBIOPUT_VSCREENINFO failed (%d x %d)\n", + info.xres_virtual, info.yres_virtual); + return 0; + } + + if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) + return -errno; + + int refreshRate = 1000000000000000LLU / + ( + (uint64_t)( info.upper_margin + info.lower_margin + info.yres ) + * ( info.left_margin + info.right_margin + info.xres ) + * info.pixclock + ); + + float xdpi = (info.xres * 25.4f) / info.width; + float ydpi = (info.yres * 25.4f) / info.height; + float fps = refreshRate / 1000.0f; + + printf( "using (fd=%d)\n" + "id = %s\n" + "xres = %d px\n" + "yres = %d px\n" + "xres_virtual = %d px\n" + "yres_virtual = %d px\n" + "bpp = %d\n" + "r = %2u:%u\n" + "g = %2u:%u\n" + "b = %2u:%u\n", + fd, + finfo.id, + info.xres, + info.yres, + info.xres_virtual, + info.yres_virtual, + info.bits_per_pixel, + info.red.offset, info.red.length, + info.green.offset, info.green.length, + info.blue.offset, info.blue.length + ); + + printf( "width = %d mm (%f dpi)\n" + "height = %d mm (%f dpi)\n" + "refresh rate = %.2f Hz\n", + info.width, xdpi, + info.height, ydpi, + fps + ); + + printf("upper_margin=%d, lower_margin=%d, left_margin=%d, right_margin=%d, pixclock=%d, finfo.smem_len=%d\n", + info.upper_margin, info.lower_margin, info.left_margin, info.right_margin, info.pixclock, finfo.smem_len); + + if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) + return -errno; + + if (finfo.smem_len <= 0) + return -errno; + + /* + * Open and map the display. + */ + + uint16_t* buffer = (uint16_t*) mmap( + 0, finfo.smem_len, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, 0); + + if (buffer == MAP_FAILED) + return -errno; + + // at least for now, always clear the fb + memset(buffer, 0, finfo.smem_len); + memset(buffer, 0xff, 320*(info.yres_virtual/2)*2); + + int l,t,w,h; + l=0; + t=0; + w=320; + h=480; + info.reserved[0] = 0x54445055; // "UPDT"; + info.reserved[1] = (uint16_t)l | ((uint32_t)t << 16); + info.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16); + + int err; + int c = 0; + int64_t time = systemTime(); + while (1) { + + info.activate = FB_ACTIVATE_VBL; + info.yoffset = 0; + ioctl(fd, FBIOPUT_VSCREENINFO, &info); + + info.activate = FB_ACTIVATE_VBL; + info.yoffset = info.yres_virtual/2; + err = ioctl(fd, FBIOPUT_VSCREENINFO, &info); + + c+=2; + if (c==60*2) { + int64_t now = systemTime(); + time = now - time; + printf("refresh rate = %f Hz\n", (c*1000000000.0 / (double)time)); + c = 0; + time = now; + } + } + return 0; +} diff --git a/tests/fstest/Android.mk b/tests/fstest/Android.mk new file mode 100644 index 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..86d2cdce --- /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)) { + return 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..fe253d7b --- /dev/null +++ b/tests/fstest/perm_checker.conf @@ -0,0 +1,165 @@ +/ 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/app-private/ 700 771 system system system system +/data/dalvik-cache/ 750 771 root system root system +/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/local/ 771 771 shell shell shell shell +/data/local/tmp/ 771 1771 shell shell shell shell +/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/dhcp/ 700 770 root dhcp dhcp dhcp +/data/misc/dhcp/... 000 660 root dhcp dhcp dhcp +/data/misc/hcid/ 700 770 root bluetooth bluetooth bluetooth +/data/misc/hcid/... 600 770 root bluetooth bluetooth bluetooth +/data/misc/wifi/ 000 1771 system wifi system wifi +/data/misc/wifi/... 000 770 root wifi root wifi +/data/property/ 700 770 root root root root +/data/property/... 600 660 root root root root +/data/system/ 000 775 system system system system +/data/system/... 000 774 system system system system +/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 +/dev/ 755 755 root root root root +/dev/alarm 600 664 root radio root radio +/dev/ashmem 666 666 root root root root +/dev/android_adb 600 660 root adb root adb +/dev/android_adb_enable 600 660 root adb root adb +/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_ctl 660 660 system system audio 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 660 660 system system graphics graphics +/dev/pmem_adsp 660 660 system system audio audio +/dev/pmem_camera 600 660 root system root camera +/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 shell root shell +/dev/mtd/ 750 775 root root root root +/dev/mtd/mtd0 460 460 radio radio diag diag +/dev/mtd/* 600 600 root root root root +/dev/socket/ 750 755 root system root system +/dev/socket/bluetooth 600 660 root bluetooth bluetooth bluetooth +/dev/socket/dbus 660 660 root bluetooth bluetooth bluetooth +/dev/socket/dbus_bluetooth 600 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 root radio +/dev/socket/rild-debug 660 660 root radio root radio +/dev/socket/usbd 660 660 root mount mount mount +/dev/socket/wpa_* 600 660 root wifi wifi wifi +/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 shell root shell +/system/bin/netcfg 000 2750 root root inet inet +/system/bin/ping 000 2755 root root net_raw net_raw +/system/etc/ 755 755 root root root root +/system/etc/... 000 664 root bluetooth root audio +/system/etc/firmware/ 700 755 root root root root +/system/etc/init.goldfish.sh 500 550 root root root shell +/system/etc/init.gprs-pppd 500 550 root root root shell +/system/etc/init.testmenu 500 550 root root root root +/system/etc/perm_checker.conf 000 777 root shell root shell +/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..36f233c7 --- /dev/null +++ b/tests/memtest/Android.mk @@ -0,0 +1,19 @@ +# 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 + +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/tests/schedtest/Android.mk b/tests/schedtest/Android.mk new file mode 100644 index 00000000..58e8d62b --- /dev/null +++ b/tests/schedtest/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + schedtest.c + +LOCAL_MODULE := schedtest + +include $(BUILD_EXECUTABLE) diff --git a/tests/schedtest/schedtest.c b/tests/schedtest/schedtest.c new file mode 100644 index 00000000..f15b66b3 --- /dev/null +++ b/tests/schedtest/schedtest.c @@ -0,0 +1,48 @@ +/* +** Copyright 2008 The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <sys/uio.h> +#include <unistd.h> + +int main(int argc, char **argv) { + int i; + + struct timeval tv1; + struct timeval tv2; + long max = 0; + long avg = 0; + + for(i = 1; ; i++) { + gettimeofday(&tv1, NULL); + usleep(1000); + gettimeofday(&tv2, NULL); + + long usec = (tv2.tv_sec - tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec; + avg += usec; + + if (usec > max) max = usec; + if (!(i % 1000)) { + avg /= 1000; + printf("max %ld\tavg %ld\n", max, avg); + max = 0; + avg = 0; + } + } + return 0; +} diff --git a/timeinfo/Android.mk b/timeinfo/Android.mk new file mode 100644 index 00000000..5c4672ea --- /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_legacy +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 */ |