summaryrefslogtreecommitdiff
path: root/ashmemtest-expanded/ashmemtest-expanded.l
diff options
context:
space:
mode:
Diffstat (limited to 'ashmemtest-expanded/ashmemtest-expanded.l')
-rw-r--r--ashmemtest-expanded/ashmemtest-expanded.l261
1 files changed, 261 insertions, 0 deletions
diff --git a/ashmemtest-expanded/ashmemtest-expanded.l b/ashmemtest-expanded/ashmemtest-expanded.l
new file mode 100644
index 0000000..f13c7a5
--- /dev/null
+++ b/ashmemtest-expanded/ashmemtest-expanded.l
@@ -0,0 +1,261 @@
+/* Expanded ashmem test -- flex input, but mostly -*-C-*- really */
+
+%option noyywrap yylineno
+
+%{
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/sysinfo.h>
+
+#ifdef ANDROID
+#include <utils/ashmem.h>
+#else
+#include "ashmem.h"
+#endif
+
+#ifndef _LINUX_ASHMEM_H
+struct ashmem_pin {
+ uint32_t offset;
+ uint32_t len;
+};
+#endif
+
+typedef struct {
+ int beg;
+ int end;
+} range_t;
+
+int ashmemfd = -1;
+void *pages;
+int nrpages;
+int pagesize;
+
+int parse_number (char *);
+range_t * parse_range (char *);
+void getpages (int);
+void pinpages (range_t *);
+void unpinpages (range_t *);
+void shrink (void);
+void purgepages (void);
+void fatal (int, const char *, ...);
+
+%}
+
+%%
+
+getpages[ \t]+[0-9]+ { getpages (parse_number (yytext + 8)); }
+
+pin[ \t]+[0-9]+[ \t]+[0-9]+ { pinpages (parse_range (yytext + 3)); }
+
+unpin[ \t]+[0-9]+[ \t]+[0-9]+ { unpinpages (parse_range (yytext + 5)); }
+
+shrink { shrink (); }
+
+purge { purgepages (); }
+
+[ \t\n]+ /* spaces */
+
+[ \t]*#.* /* comment starts from '#' */
+
+. { fprintf (stderr, "Unrecognized input '%s' at line %d\n",
+ yytext, yylineno);
+ exit (1); }
+
+%%
+
+void fatal (int error, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ if (error)
+ fprintf (stderr, " (error %d [%s])", error, strerror (error));
+ va_end (ap);
+ fprintf (stderr, "\n");
+ exit (error ? error : 1);
+}
+
+int
+parse_number (char *buf)
+{
+ while (isspace (*buf))
+ buf++;
+ return atoi (buf);
+}
+
+range_t *
+parse_range (char *buf)
+{
+ char *p, *q;
+ range_t *range;
+
+ if (ashmemfd == -1)
+ fatal (0, "pages not allocated (use getpages X first)");
+
+ range = (range_t *) malloc (sizeof (range_t));
+ if (!range)
+ fatal (0, "cannot allocate memory");
+ for (p = buf; isspace (*p); p++);
+ if (!isdigit (*p))
+ fatal (0, "unexpected parse error");
+ range->beg = strtol (p, &q, 10);
+ for (; isspace (*q); q++);
+ range->end = strtol (q, NULL, 10);
+
+ if (range->beg > nrpages)
+ fatal (0, "range begin %d is outside of allocated pages", range->beg);
+ if (range->end > nrpages)
+ fatal (0, "range end %d is outside of allocated pages", range->beg);
+ if (range->end == range->beg)
+ fatal (0, "zero-sized range at line %d", yylineno);
+ return range;
+}
+
+void
+getpages (int npages)
+{
+ size_t size = npages * pagesize;
+
+ if (ashmemfd != -1)
+ fatal (0, "pages already allocated");
+ if (npages < 1)
+ fatal (0, "should allocate at least one page");
+
+ ashmemfd = open ("/dev/ashmem", O_RDWR);
+ if (ashmemfd < 0)
+ fatal (errno, "can't open /dev/ashmem");
+ if (ioctl (ashmemfd, ASHMEM_SET_SIZE, size) < 0)
+ fatal (errno, "can't set size");
+ pages = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemfd, 0);
+ if (pages == MAP_FAILED)
+ fatal (errno, "can't map pages");
+ nrpages = npages;
+ printf ("-> got %d pages\n", npages);
+}
+
+void
+pinpages (range_t *range)
+{
+ struct ashmem_pin pin;
+ int ret;
+
+ if (ashmemfd == -1)
+ fatal (0, "pages not allocated (use getpages X first)");
+
+ if (range->end > range->beg)
+ {
+ /* Normal order, pin all at once. */
+ pin.offset = range->beg * pagesize;
+ pin.len = (range->end - range->beg) * pagesize;
+ ret = ioctl (ashmemfd, ASHMEM_PIN, &pin);
+ if (ret < 0)
+ fatal (errno, "can't pin %d..%d", range->beg, range->end);
+ printf ("-> pin %d..%d OK ret %d\n", range->beg, range->end, ret);
+ }
+ else
+ {
+ /* Reverse order, pin page-by-page from higher to lower. */
+ int pgno;
+
+ for (pgno = range->beg - 1; pgno >= range->end; pgno--)
+ {
+ pin.offset = pgno * pagesize;
+ pin.len = pagesize;
+ ret = ioctl (ashmemfd, ASHMEM_PIN, &pin);
+ if (ret < 0)
+ fatal (errno, "can't pin page %d", pgno);
+ }
+ printf ("-> pin backward %d..%d OK\n", range->beg, range->end);
+ }
+}
+
+void
+unpinpages (range_t *range)
+{
+ struct ashmem_pin pin;
+ int ret;
+
+ if (ashmemfd == -1)
+ fatal (0, "pages not allocated (use getpages X first)");
+
+ if (range->end > range->beg)
+ {
+ /* Normal order, unpin all at once. */
+ pin.offset = range->beg * pagesize;
+ pin.len = (range->end - range->beg) * pagesize;
+ ret = ioctl (ashmemfd, ASHMEM_UNPIN, &pin);
+ if (ret < 0)
+ fatal (errno, "can't unpin %d..%d", range->beg, range->end);
+ printf ("-> unpin %d..%d OK ret %d\n", range->beg, range->end, ret);
+ }
+ else
+ {
+ /* Reverse order, unpin page-by-page from higher to lower. */
+ int pgno;
+
+ for (pgno = range->beg - 1; pgno >= range->end; pgno--)
+ {
+ pin.offset = pgno * pagesize;
+ pin.len = pagesize;
+ ret = ioctl (ashmemfd, ASHMEM_UNPIN, &pin);
+ if (ret < 0)
+ fatal (errno, "can't unpin page %d", pgno);
+ }
+ printf ("-> unpin backward %d..%d OK\n", range->beg, range->end);
+ }
+}
+
+/* Enforce the kernel to run cache shrinker */
+
+void
+shrink (void)
+{
+ int fd;
+ char cmd[2];
+
+ fd = open ("/proc/sys/vm/drop_caches", O_WRONLY);
+ if (fd < 0)
+ fatal (errno, "can't open /proc/sys/vm/drop_caches (is /proc mounted?)");
+ cmd[0] = '3';
+ cmd[1] = '\n';
+ if (write (fd, cmd, sizeof cmd) != sizeof cmd)
+ fatal (errno, "can't write to /proc/sys/vm/drop_caches");
+}
+
+void
+purgepages (void)
+{
+ int ret;
+
+ if (ashmemfd == -1)
+ fatal (0, "pages not allocated (use getpages X first)");
+ ret = ioctl (ashmemfd, ASHMEM_PURGE_ALL_CACHES);
+ if (ret < 0)
+ fatal (errno, "can't purge caches");
+ printf ("-> purge return %d pages OK\n", ret);
+}
+
+int main (int argc, char *argv[])
+{
+ pagesize = getpagesize ();
+
+ if (argc == 2)
+ {
+ yyin = fopen (argv[1], "r");
+ if (!yyin)
+ fatal (errno, "can't open '%s'", argv[1]);
+ }
+ else
+ yyin = stdin;
+
+ yylex ();
+ return 0;
+}