[m-rev.] diff: Add profiling for memory zone usage.

Paul Bone pbone at csse.unimelb.edu.au
Wed Nov 23 21:57:21 AEDT 2011


Add support for tracking the number, and amount of memory consumed by memory
zones.  The current and maximum values are tracked.  This support is only
compiled in if the MR_PROFILE_ZONES C macro is defined when building the
runtime system.

runtime/mercury_memory_zones.[ch]:
    As above.

runtime/mercury_wrapper.c:
    Print out the zone profiling data as the runtime is exiting.

util/mkinit.c:
    Add support for measuring the top of heap before and after executing
    mercury_main and writing out this difference.  This support is only enabled
    if the MR_PROFILE_SBRK macro is defined when compiling an application.

Index: runtime/mercury_memory_zones.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_memory_zones.c,v
retrieving revision 1.43
diff -u -p -b -r1.43 mercury_memory_zones.c
--- runtime/mercury_memory_zones.c	23 Nov 2011 10:39:38 -0000	1.43
+++ runtime/mercury_memory_zones.c	23 Nov 2011 10:46:37 -0000
@@ -76,6 +76,33 @@
   #include "mercury_windows.h"
 #endif
 
+/*
+** This macro can be used to update a high water mark of a statistic.
+*/
+#define MR_UPDATE_HIGHWATER(max, cur)                                       \
+    do {                                                                    \
+        if ((max) < (cur)) {                                                \
+            (max) = (cur);                                                  \
+        }                                                                   \
+    } while (0);
+
+#ifdef MR_PROFILE_ZONES
+/*
+** These values track the number of zones and the total size.
+*/
+#ifdef MR_THREAD_SAFE
+static  MercuryLock memory_zones_stats_lock;
+#endif
+
+static  MR_Integer  MR_num_zones = 0;
+static  MR_Integer  MR_total_zone_size_net = 0;
+static  MR_Integer  MR_total_zone_size_gross = 0;
+
+static  MR_Integer  MR_max_num_zones = 0;
+static  MR_Integer  MR_max_total_zone_size_net = 0;
+static  MR_Integer  MR_max_total_zone_size_gross = 0;
+#endif
+
 static  void    MR_setup_redzones(MR_MemoryZone *zone);
 
 static  void    *MR_alloc_zone_memory(size_t size);
@@ -433,6 +460,9 @@ MR_init_zones()
 {
 #ifdef  MR_THREAD_SAFE
     pthread_mutex_init(&memory_zones_lock, MR_MUTEX_ATTR);
+#ifdef MR_PROFILE_ZONES
+    pthread_mutex_init(&memory_zones_stats_lock, MR_MUTEX_ATTR);
+#endif
 #if ! defined(MR_LL_PARALLEL_CONJ)
     pthread_mutex_init(&zone_id_counter_lock, MR_MUTEX_ATTR);
 #endif
@@ -493,6 +523,15 @@ MR_free_zone(MR_MemoryZone *zone)
     }
 #endif
 
+#ifdef MR_PROFILE_ZONES
+    MR_LOCK(&memory_zones_stats_lock, "MR_free_zone");
+    MR_num_zones--;
+    MR_total_zone_size_net -= zone->MR_zone_desired_size;
+    MR_total_zone_size_gross -=
+        (MR_Integer)zone->MR_zone_top - (MR_Integer)zone->MR_zone_bottom;
+    MR_UNLOCK(&memory_zones_stats_lock, "MR_free_zone");
+#endif
+
     MR_dealloc_zone_memory(zone->MR_zone_bottom,
         ((char *) zone->MR_zone_top) - ((char *) zone->MR_zone_bottom));
 }
@@ -531,6 +570,10 @@ MR_remove_zone_from_used_list(MR_MemoryZ
 static size_t
 get_zone_alloc_size(MR_MemoryZone *zone)
 {
+    /*
+    ** XXX: Check this, it seems at odds with the description with the
+    ** MR_zone_top and MR_zone_bottom fields.
+    */
 #ifdef  MR_PROTECTPAGE
     return (size_t)((char *)zone->MR_zone_hardmax - (char *)zone->MR_zone_min);
 #else
@@ -660,6 +703,17 @@ MR_create_new_zone(size_t desired_size, 
     */
     total_size = MR_round_up(total_size, MR_page_size);
 
+#ifdef MR_PROFILE_ZONES
+    MR_LOCK(&memory_zones_stats_lock, "MR_create_new_zone");
+    MR_num_zones++;
+    MR_total_zone_size_net += desired_size;
+    MR_total_zone_size_gross += total_size;
+    MR_UPDATE_HIGHWATER(MR_max_num_zones, MR_num_zones);
+    MR_UPDATE_HIGHWATER(MR_max_total_zone_size_net, MR_total_zone_size_net);
+    MR_UPDATE_HIGHWATER(MR_max_total_zone_size_gross, MR_total_zone_size_gross);
+    MR_UNLOCK(&memory_zones_stats_lock, "MR_create_new_zone");
+#endif
+
     base = (MR_Word *) MR_alloc_zone_memory(total_size);
     if (base == NULL) {
         MR_fatal_error("Unable to allocate memory for zone");
@@ -710,6 +764,9 @@ MR_extend_zone(MR_MemoryZone *zone, size
     size_t          new_total_size;
     MR_Integer      base_incr;
     int             res;
+#ifdef MR_PROFILE_ZONES
+    size_t          size_delta;
+#endif
 
     if (zone == NULL) {
         MR_fatal_error("MR_extend_zone called with NULL pointer");
@@ -730,6 +787,14 @@ MR_extend_zone(MR_MemoryZone *zone, size
     copy_size = zone->MR_zone_end - zone->MR_zone_bottom;
     offset = zone->MR_zone_min - zone->MR_zone_bottom;
 
+#ifdef MR_PROFILE_ZONES
+    MR_LOCK(&memory_zones_stats_lock, "MR_extend_zone");
+    MR_total_zone_size_net += new_size - zone->MR_zone_desired_size;
+    MR_total_zone_size_gross += new_total_size -
+        ((MR_Integer)zone->MR_zone_top - (MR_Integer)zone->MR_zone_bottom);
+    MR_UNLOCK(&memory_zones_stats_lock, "MR_extend_zone");
+#endif
+
 #ifdef  MR_CHECK_OVERFLOW_VIA_MPROTECT
     /* unprotect the entire zone area */
     res = MR_protect_pages((char *) zone->MR_zone_bottom,
@@ -1393,3 +1458,18 @@ MR_debug_memory_zone(FILE *fp, MR_Memory
         get_zone_alloc_size(zone));
     fprintf(fp, "\n");
 }
+
+#ifdef MR_PROFILE_ZONES
+void MR_print_zone_stats(void) {
+    MR_LOCK(&memory_zones_stats_lock, "MR_print_zone_stats");
+    printf("Number of zones allocated: %d\n", MR_num_zones);
+    printf("Maximum number of zones allocated: %d\n", MR_max_num_zones);
+    printf("Allocated space within zones (KB) Net: %d Gross: %d\n",
+        MR_total_zone_size_net / 1024, MR_total_zone_size_gross / 1024);
+    printf("Maximum allocated space within zones (KB) Net: %d Gross: %d\n",
+        MR_max_total_zone_size_net / 1024,
+        MR_max_total_zone_size_gross / 1024);
+    MR_UNLOCK(&memory_zones_stats_lock, "MR_print_zone_stats");
+}
+#endif
+
Index: runtime/mercury_memory_zones.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_memory_zones.h,v
retrieving revision 1.21
diff -u -p -b -r1.21 mercury_memory_zones.h
--- runtime/mercury_memory_zones.h	5 Apr 2011 10:27:26 -0000	1.21
+++ runtime/mercury_memory_zones.h	23 Nov 2011 10:46:37 -0000
@@ -296,4 +296,11 @@ extern	void		MR_debug_memory_zone(FILE *
 
 extern	size_t		MR_next_offset(void);
 
+/*
+** MR_print_zone_stats() print statistics about memory zone allocation.
+*/
+#ifdef MR_PROFILE_ZONES
+extern  void            MR_print_zone_stats(void);
+#endif
+
 #endif /* not MERCURY_MEMORY_ZONES_H */
Index: runtime/mercury_wrapper.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.226
diff -u -p -b -r1.226 mercury_wrapper.c
--- runtime/mercury_wrapper.c	13 Oct 2011 02:42:21 -0000	1.226
+++ runtime/mercury_wrapper.c	23 Nov 2011 10:46:37 -0000
@@ -2629,6 +2629,10 @@ mercury_runtime_main(void)
     MR_print_stack_frame_stats();
 #endif  /* MR_STACK_FRAME_STATS */
 
+#ifdef MR_PROFILE_ZONES
+    MR_print_zone_stats();
+#endif
+
     /*
     ** Save the Mercury registers and restore the C callee-save registers
     ** before returning, since they may be used by the C code that called us.
Index: util/mkinit.c
===================================================================
RCS file: /home/mercury1/repository/mercury/util/mkinit.c,v
retrieving revision 1.124
diff -u -p -b -r1.124 mkinit.c
--- util/mkinit.c	8 Jun 2011 04:19:58 -0000	1.124
+++ util/mkinit.c	23 Nov 2011 10:47:39 -0000
@@ -320,8 +320,11 @@ static const char header1[] =
 
 static const char header2[] =
     "*/\n"
-    "\n"
+    "#define _BSD_SOURCE\n"
     "#include <stddef.h>\n"
+    "#ifdef MR_PROFILE_SBRK\n"
+    "#include <unistd.h>\n"
+    "#endif\n"
     "#include \"mercury_init.h\"\n"
     "#include \"mercury_grade.h\"\n"
     "\n"
@@ -541,7 +544,21 @@ static const char main_func[] =
     "int\n"
     "main(int argc, char **argv)\n"
     "{\n"
-    "   return mercury_main(argc, argv);\n"
+    "#ifdef MR_PROFILE_SBRK\n"
+    "   void* old_break;\n"
+    "   void* new_break;\n"
+    "#endif\n"
+    "   int result;\n"
+    "#ifdef MR_PROFILE_SBRK\n"
+    "   old_break = sbrk(0);\n"
+    "#endif\n"
+    "   result = mercury_main(argc, argv);\n"
+    "#ifdef MR_PROFILE_SBRK\n"
+    "   new_break = sbrk(0);\n"
+    "   printf(\"sbrk delta: %d\\n\",\n"
+    "       (MR_Integer)new_break - (MR_Integer)old_break);\n"
+    "#endif\n"
+    "   return result;\n"
     "}\n"
     ;
 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 489 bytes
Desc: Digital signature
URL: <http://lists.mercurylang.org/archives/reviews/attachments/20111123/329b6bb6/attachment.sig>


More information about the reviews mailing list