diff options
Diffstat (limited to 'ashmemtest-expanded/ashmemtest-expanded.l')
-rw-r--r-- | ashmemtest-expanded/ashmemtest-expanded.l | 261 |
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; +} |