2008-02-09 15:56:12

by KOSAKI Motohiro

[permalink] [raw]
Subject: [sample] mem_notify v6: usage example

this is usage example of /dev/mem_notify.

Daniel Spang create original version.
kosaki add fasync related code.


Signed-off-by: Daniel Spang <[email protected]>
Signed-off-by: KOSAKI Motohiro <[email protected]>

---
Documentation/mem_notify.c | 120 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 120 insertions(+)

Index: b/Documentation/mem_notify.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ b/Documentation/mem_notify.c 2008-02-10 00:44:00.000000000 +0900
@@ -0,0 +1,120 @@
+/*
+ * Allocate 10 MB each second. Exit on notification.
+ */
+
+#define _GNU_SOURCE
+
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <poll.h>
+#include <pthread.h>
+#include <errno.h>
+#include <signal.h>
+
+int count = 0;
+int size = 10;
+
+void *do_alloc()
+{
+ for(;;) {
+ int *buffer;
+ buffer = mmap(NULL, size*1024*1024,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (buffer == MAP_FAILED) {
+ perror("mmap");
+ exit(EXIT_FAILURE);
+ }
+ memset(buffer, 1 , size*1024*1024);
+
+ printf("-");
+ fflush(stdout);
+
+ count++;
+ sleep(1);
+ }
+}
+
+int wait_for_notification(struct pollfd *pfd)
+{
+ int ret;
+ read(pfd->fd, 0, 0);
+ ret = poll(pfd, 1, -1); /* wake up when low memory */
+ if (ret == -1 && errno != EINTR) {
+ perror("poll");
+ exit(EXIT_FAILURE);
+ }
+ return ret;
+}
+
+void do_free()
+{
+ int fd;
+ struct pollfd pfd;
+
+ fd = open("/dev/mem_notify", O_RDONLY);
+ if (fd == -1) {
+ perror("open");
+ exit(EXIT_FAILURE);
+ }
+
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+ for(;;)
+ if (wait_for_notification(&pfd) > 0) {
+ printf("\nGot notification, allocated %d MB\n",
+ size * count);
+ exit(EXIT_SUCCESS);
+ }
+}
+
+void do_free_signal()
+{
+ int fd;
+ int flags;
+
+ fd = open("/dev/mem_notify", O_RDONLY);
+ if (fd == -1) {
+ perror("open");
+ exit(EXIT_FAILURE);
+ }
+
+ fcntl(fd, F_SETOWN, getpid());
+ fcntl(fd, F_SETSIG, SIGUSR1);
+
+ flags = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, flags|FASYNC); /* when low memory, receive SIGUSR1 */
+
+ for(;;)
+ sleep(1);
+}
+
+
+void daniel_exit(int signo)
+{
+ printf("\nGot notification %d, allocated %d MB\n",
+ signo, size * count);
+ exit(EXIT_SUCCESS);
+
+}
+
+int main(int argc, char *argv[])
+{
+ pthread_t allocator;
+
+ if(argc == 2 && (strcmp(argv[1], "-sig") == 0)) {
+ printf("run signal mode\n");
+ signal(SIGUSR1, daniel_exit);
+ pthread_create(&allocator, NULL, do_alloc, NULL);
+ do_free_signal();
+ } else {
+ printf("run poll mode\n");
+ pthread_create(&allocator, NULL, do_alloc, NULL);
+ do_free();
+ }
+ return 0;
+}


2008-02-09 16:08:31

by Jon Masters

[permalink] [raw]
Subject: Re: [sample] mem_notify v6: usage example

This really needs to be triggered via a generic kernel event in the
final version - I picture glibc having a reservation API and having
generic support for freeing such reservations.

Jon



On Feb 9, 2008, at 10:55, "KOSAKI Motohiro" <[email protected]
> wrote:

> this is usage example of /dev/mem_notify.
>
> Daniel Spang create original version.
> kosaki add fasync related code.
>
>
> Signed-off-by: Daniel Spang <[email protected]>
> Signed-off-by: KOSAKI Motohiro <[email protected]>
>
> ---
> Documentation/mem_notify.c | 120 +++++++++++++++++++++++++++++++++++
> ++++++++++
> 1 file changed, 120 insertions(+)
>
> Index: b/Documentation/mem_notify.c
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ b/Documentation/mem_notify.c 2008-02-10 00:44:00.000000000
> +0900
> @@ -0,0 +1,120 @@
> +/*
> + * Allocate 10 MB each second. Exit on notification.
> + */
> +
> +#define _GNU_SOURCE
> +
> +#include <sys/mman.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <poll.h>
> +#include <pthread.h>
> +#include <errno.h>
> +#include <signal.h>
> +
> +int count = 0;
> +int size = 10;
> +
> +void *do_alloc()
> +{
> + for(;;) {
> + int *buffer;
> + buffer = mmap(NULL, size*1024*1024,
> + PROT_READ | PROT_WRITE,
> + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> + if (buffer == MAP_FAILED) {
> + perror("mmap");
> + exit(EXIT_FAILURE);
> + }
> + memset(buffer, 1 , size*1024*1024);
> +
> + printf("-");
> + fflush(stdout);
> +
> + count++;
> + sleep(1);
> + }
> +}
> +
> +int wait_for_notification(struct pollfd *pfd)
> +{
> + int ret;
> + read(pfd->fd, 0, 0);
> + ret = poll(pfd, 1, -1); /* wake up when low
> memory */
> + if (ret == -1 && errno != EINTR) {
> + perror("poll");
> + exit(EXIT_FAILURE);
> + }
> + return ret;
> +}
> +
> +void do_free()
> +{
> + int fd;
> + struct pollfd pfd;
> +
> + fd = open("/dev/mem_notify", O_RDONLY);
> + if (fd == -1) {
> + perror("open");
> + exit(EXIT_FAILURE);
> + }
> +
> + pfd.fd = fd;
> + pfd.events = POLLIN;
> + for(;;)
> + if (wait_for_notification(&pfd) > 0) {
> + printf("\nGot notification, allocated %d MB
> \n",
> + size * count);
> + exit(EXIT_SUCCESS);
> + }
> +}
> +
> +void do_free_signal()
> +{
> + int fd;
> + int flags;
> +
> + fd = open("/dev/mem_notify", O_RDONLY);
> + if (fd == -1) {
> + perror("open");
> + exit(EXIT_FAILURE);
> + }
> +
> + fcntl(fd, F_SETOWN, getpid());
> + fcntl(fd, F_SETSIG, SIGUSR1);
> +
> + flags = fcntl(fd, F_GETFL);
> + fcntl(fd, F_SETFL, flags|FASYNC); /* when low memory, receive
> SIGUSR1 */
> +
> + for(;;)
> + sleep(1);
> +}
> +
> +
> +void daniel_exit(int signo)
> +{
> + printf("\nGot notification %d, allocated %d MB\n",
> + signo, size * count);
> + exit(EXIT_SUCCESS);
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + pthread_t allocator;
> +
> + if(argc == 2 && (strcmp(argv[1], "-sig") == 0)) {
> + printf("run signal mode\n");
> + signal(SIGUSR1, daniel_exit);
> + pthread_create(&allocator, NULL, do_alloc, NULL);
> + do_free_signal();
> + } else {
> + printf("run poll mode\n");
> + pthread_create(&allocator, NULL, do_alloc, NULL);
> + do_free();
> + }
> + return 0;
> +}
>

2008-02-09 16:46:27

by KOSAKI Motohiro

[permalink] [raw]
Subject: Re: [sample] mem_notify v6: usage example

Hi Jon

> This really needs to be triggered via a generic kernel event in the
> final version - I picture glibc having a reservation API and having
> generic support for freeing such reservations.

to be honest, I doubt idea of generic reservation framework.

end up, we hope drop the application cache, not also dataless memory.
but, automatically drop mechanism only able to drop dataless memory.

and, many application have own memory management subsystem.
I afraid to nobody use too complex framework.

What do you think it?
I hope see your API. please post it.

Thanks!

2008-02-10 01:31:11

by Pavel Machek

[permalink] [raw]
Subject: Re: [sample] mem_notify v6: usage example

On Sat 2008-02-09 11:07:09, Jon Masters wrote:
> This really needs to be triggered via a generic kernel
> event in the final version - I picture glibc having a
> reservation API and having generic support for freeing
> such reservations.

Not sure what you are talking about. This seems very right to me.

We want memory-low notification, not yet another generic communication
mechanism.

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2008-02-11 18:15:48

by Andreas Dilger

[permalink] [raw]
Subject: Re: [sample] mem_notify v6: usage example

On Feb 10, 2008 01:46 +0900, KOSAKI Motohiro wrote:
> > This really needs to be triggered via a generic kernel event in the
> > final version - I picture glibc having a reservation API and having
> > generic support for freeing such reservations.
>
> to be honest, I doubt idea of generic reservation framework.
>
> end up, we hope drop the application cache, not also dataless memory.
> but, automatically drop mechanism only able to drop dataless memory.
>
> and, many application have own memory management subsystem.
> I afraid to nobody use too complex framework.

Having such notification handled by glibc to free up unused malloc (or
any heap allocations) would be very useful, because even if a program
does "free" there is no guarantee the memory is returned to the kernel.

I think that having a generic reservation framework is too complex, but
hiding the details of /dev/mem_notify from applications is desirable.
A simple wrapper (possibly part of glibc) to return the poll fd, or set
up the signal is enough.

Cheers, Andreas
--
Andreas Dilger
Sr. Staff Engineer, Lustre Group
Sun Microsystems of Canada, Inc.

2008-02-11 18:37:36

by KOSAKI Motohiro

[permalink] [raw]
Subject: Re: [sample] mem_notify v6: usage example

Hi Andreas,

Thank you very good comment.

> Having such notification handled by glibc to free up unused malloc (or
> any heap allocations) would be very useful, because even if a program
> does "free" there is no guarantee the memory is returned to the kernel.

Yes, no guarantee.
but current glibc-malloc very frequently return memory to kernel.

glibc default behavior

1. over 1M memory: return memory just free(3) called.
(you can change threshold by MALLOC_MMAP_MAX_ environment)
2. more lower: return memory when exist continuous 128k at heap tail.
(you can change threashold by MALLOC_TRIM_THRESHOLD_ environment)

if you know very memory consumption by already freed memory situation,
please tell me situation detail and consumption memory size.

> I think that having a generic reservation framework is too complex, but
> hiding the details of /dev/mem_notify from applications is desirable.
> A simple wrapper (possibly part of glibc) to return the poll fd, or set
> up the signal is enough.

Agreed.
if large consumption situation exist, I'm behind you.


Thanks!