Hi, all.
I'm pinging this patch: https://gcc.gnu.org/ml/gcc-patches/2015-08/msg00030.html

And adding some more changes to it (they are not complete yet - so they are more
like an RFC).
In this patch I also try to make obstacks use the same block pool as object
pools. This seems rather easy to implement because obstacks already have
obstack_chunk_alloc/obstack_chunk_free callbacks, and they are easily replaced.
I also change the default chunk size to memory_block_pool::block_size. This
still works for object sizes greater than memory_block_pool::block_size: in this
case I simply call xmalloc to allocate the requested chunk, and the deallocation
function uses obstack chunk header to determine chunk's size (and depending on
it calls either free or memory_block_pool::remove).
The result is visible on the profile. For example, for tramp3d build
_obstack_begin is the top caller of xmalloc (it constitutes 107 ms into xmalloc
self time, which is 375 ms - according to one of my runs). After applying the
patch it is gone from profile.
This patch adds new files virtual-memory.h and virtual-memory.cc, which
currently contain memory_block_pool class and related obstack functions (I plan
to factor out part of ggc-page.c into this file in order to use
mmap/VirtualAlloc directly, hence the name "virtual-memory"). Currently this
file is linked into libcommon, and this seems somewhat wrong to me, because the
driver and other command line tools don't use all memory management machinery of
the compiler proper. But obstacks are used by diagnostics.c and this file is
already in libcommon, so there is probably no easy way to make it use xmalloc
instead of memory_block_pool::allocate. A possible solution is to create an
additional file with definitions of mempool_obstack_chunk_alloc/free and use it
for generators and drivers (or somehow make mempool_obstack_chunk_alloc alias to
malloc). Do you have any suggestions, how this could be done in a better way?
Another problem is headers. I included "virtual-memory.h" into coretypes.h,
because it defines a macro gcc_obstack_init, which now uses functions from
virtual-memory.h. Alternatively I could just declare those functions in
coretypes.h. Would that be better?

-- 
Regards,
    Mikhail Maltsev
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index c1cb4ce..1b4198d 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1516,7 +1516,7 @@ OBJS = \
 # Objects in libcommon.a, potentially used by all host binaries and with
 # no target dependencies.
 OBJS-libcommon = diagnostic.o diagnostic-color.o pretty-print.o intl.o \
-	vec.o input.o version.o hash-table.o ggc-none.o
+	vec.o input.o version.o hash-table.o ggc-none.o virtual-memory.o
 
 # Objects in libcommon-target.a, used by drivers and by the core
 # compiler and containing target-dependent code.
diff --git a/gcc/alloc-pool.c b/gcc/alloc-pool.c
index f8c1351..7e25915 100644
--- a/gcc/alloc-pool.c
+++ b/gcc/alloc-pool.c
@@ -35,25 +35,3 @@ dump_alloc_pool_statistics (void)
 
   pool_allocator_usage.dump (ALLOC_POOL_ORIGIN);
 }
-
-/* Global singleton-like instance.  */
-memory_block_pool memory_block_pool::instance;
-
-memory_block_pool::memory_block_pool () : m_blocks (NULL) {}
-
-memory_block_pool::~memory_block_pool ()
-{
-  release ();
-}
-
-/* Free all memory allocated by memory_block_pool.  */
-void
-memory_block_pool::release ()
-{
-  while (m_blocks)
-    {
-      block_list *next = m_blocks->m_next;
-      XDELETEVEC (m_blocks);
-      m_blocks = next;
-    }
-}
diff --git a/gcc/alloc-pool.h b/gcc/alloc-pool.h
index dccc41a..eccdf0d 100644
--- a/gcc/alloc-pool.h
+++ b/gcc/alloc-pool.h
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef ALLOC_POOL_H
 #define ALLOC_POOL_H
 
+#include "virtual-memory.h"
 
 extern void dump_alloc_pool_statistics (void);
 
@@ -95,55 +96,6 @@ struct pool_usage: public mem_usage
 
 extern mem_alloc_description<pool_usage> pool_allocator_usage;
 
-/* Shared pool which allows other memory pools to reuse each others' allocated
-   memory blocks instead of calling free/malloc again.  */
-class memory_block_pool
-{
-public:
-  /* Blocks have fixed size.  This is necessary for sharing.  */
-  static const size_t block_size = 64 * 1024;
-
-  memory_block_pool ();
-  ~memory_block_pool ();
-
-  static inline void *allocate () ATTRIBUTE_MALLOC;
-  static inline void remove (void *);
-  void release ();
-
-private:
-  /* memory_block_pool singleton instance, defined in alloc-pool.c.  */
-  static memory_block_pool instance;
-
-  struct block_list
-  {
-    block_list *m_next;
-  };
-
-  /* Free list.  */
-  block_list *m_blocks;
-};
-
-/* Allocate single block.  Reuse previously returned block, if possible.  */
-inline void *
-memory_block_pool::allocate ()
-{
-  if (instance.m_blocks == NULL)
-    return XNEWVEC (char, block_size);
-
-  void *result = instance.m_blocks;
-  instance.m_blocks = instance.m_blocks->m_next;
-  return result;
-}
-
-/* Return UNCAST_BLOCK to pool.  */
-inline void
-memory_block_pool::remove (void *uncast_block)
-{
-  block_list *block = reinterpret_cast<block_list *> (uncast_block);
-  block->m_next = instance.m_blocks;
-  instance.m_blocks = block;
-}
-
 #if 0
 /* If a pool with custom block size is needed, one might use the following
    template.  An instance of this template can be used as a parameter for
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 17e2b40..b7b7402 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -225,12 +225,19 @@ struct basic_block_def;
 typedef struct basic_block_def *basic_block;
 typedef const struct basic_block_def *const_basic_block;
 
-#define obstack_chunk_alloc	xmalloc
-#define obstack_chunk_free	free
-#define OBSTACK_CHUNK_SIZE	0
+#if !defined (GENERATOR_FILE)
+# define OBSTACK_CHUNK_SIZE     memory_block_pool::block_size
+# define obstack_chunk_alloc    mempool_obstack_chunk_alloc
+# define obstack_chunk_free     mempool_obstack_chunk_free
+#else
+# define OBSTACK_CHUNK_SIZE     0
+# define obstack_chunk_alloc    xmalloc
+# define obstack_chunk_free     free
+#endif
+
 #define gcc_obstack_init(OBSTACK)				\
   obstack_specify_allocation ((OBSTACK), OBSTACK_CHUNK_SIZE, 0,	\
-			      obstack_chunk_alloc,		\
+			      obstack_chunk_alloc,              \
 			      obstack_chunk_free)
 
 /* enum reg_class is target specific, so it should not appear in
@@ -328,6 +335,7 @@ typedef unsigned char uchar;
 #include "hash-set.h"
 #include "input.h"
 #include "is-a.h"
+#include "virtual-memory.h"
 #endif /* GENERATOR_FILE && !USED_FOR_TARGET */
 
 #endif /* coretypes.h */
diff --git a/gcc/virtual-memory.cc b/gcc/virtual-memory.cc
new file mode 100644
index 0000000..69bda37
--- /dev/null
+++ b/gcc/virtual-memory.cc
@@ -0,0 +1,66 @@
+/* 
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "virtual-memory.h"
+#include "obstack.h"
+
+/* Global singleton-like instance.  */
+memory_block_pool memory_block_pool::instance;
+
+memory_block_pool::memory_block_pool () : m_blocks (NULL) {}
+
+memory_block_pool::~memory_block_pool ()
+{
+  release ();
+}
+
+/* Free all memory allocated by memory_block_pool.  */
+void
+memory_block_pool::release ()
+{
+  while (m_blocks)
+    {
+      block_list *next = m_blocks->m_next;
+      XDELETEVEC (m_blocks);
+      m_blocks = next;
+    }
+}
+
+void *
+mempool_obstack_chunk_alloc (size_t size)
+{
+  if (size == memory_block_pool::block_size)
+    return memory_block_pool::allocate ();
+  else
+    return XNEWVEC (char, size);
+}
+
+void
+mempool_obstack_chunk_free (void *chunk)
+{
+  size_t size = reinterpret_cast<_obstack_chunk *> (chunk)->limit -
+                reinterpret_cast<char *>(chunk);
+  if (size == memory_block_pool::block_size)
+    memory_block_pool::remove (chunk);
+  else
+    XDELETEVEC (chunk);
+}
diff --git a/gcc/virtual-memory.h b/gcc/virtual-memory.h
new file mode 100644
index 0000000..1d8f0bd
--- /dev/null
+++ b/gcc/virtual-memory.h
@@ -0,0 +1,76 @@
+/* 
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+
+#ifndef VIRTUAL_MEMORY_H
+#define	VIRTUAL_MEMORY_H
+
+/* Shared pool which allows other memory pools to reuse each others' allocated
+   memory blocks instead of calling free/malloc again.  */
+class memory_block_pool
+{
+public:
+  /* Blocks have fixed size.  This is necessary for sharing.  */
+  static const size_t block_size = 8 * 1024;
+
+  memory_block_pool ();
+  ~memory_block_pool ();
+
+  static inline void *allocate () ATTRIBUTE_MALLOC;
+  static inline void remove (void *);
+  void release ();
+
+private:
+  /* memory_block_pool singleton instance, defined in virtual-memory.cc.  */
+  static memory_block_pool instance;
+
+  struct block_list
+  {
+    block_list *m_next;
+  };
+
+  /* Free list.  */
+  block_list *m_blocks;
+};
+
+/* Allocate single block.  Reuse previously returned block, if possible.  */
+inline void *
+memory_block_pool::allocate ()
+{
+  if (instance.m_blocks == NULL)
+    return XNEWVEC (char, block_size);
+
+  void *result = instance.m_blocks;
+  instance.m_blocks = instance.m_blocks->m_next;
+  return result;
+}
+
+/* Return UNCAST_BLOCK to pool.  */
+inline void
+memory_block_pool::remove (void *uncast_block)
+{
+  block_list *block = reinterpret_cast<block_list *> (uncast_block);
+  block->m_next = instance.m_blocks;
+  instance.m_blocks = block;
+}
+
+extern void *mempool_obstack_chunk_alloc(size_t) ATTRIBUTE_MALLOC;
+extern void mempool_obstack_chunk_free(void *);
+
+#endif	/* VIRTUAL_MEMORY_H */

Reply via email to