Files
mercury/runtime/mercury_memory_zones.h
Paul Bone a885ef1910 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.
2011-11-23 10:53:01 +00:00

307 lines
9.9 KiB
C

/*
** vim:sw=8 ts=8
*/
/*
** Copyright (C) 1998-2002, 2004-2006, 2011 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** mercury_memory_zones.h
**
** This module defines a generic memory zone handler, which can be used for
** stacks and heaps in the Mercury runtime. It provides functions for
** generating offsets so that different memory zones begin at different
** offsets (improves performance with direct mapped caches). It also
** handles the fake_reg array for holding Mercury virtual registers.
*/
#ifndef MERCURY_MEMORY_ZONES_H
#define MERCURY_MEMORY_ZONES_H
#include "mercury_regs.h" /* for MR_NUM_REAL_R_REGS, etc */
#include <stdio.h> /* for FILE */
#include <stdlib.h> /* for size_t */
#include "mercury_types.h" /* for MR_Word */
#include "mercury_std.h" /* for MR_bool */
#include "mercury_atomic_ops.h" /* for MR_THREADSAFE_VOLATILE */
typedef struct MR_MemoryZone_Struct MR_MemoryZone;
typedef MR_bool MR_ZoneHandler(MR_Word *addr, MR_MemoryZone *zone,
void *context);
/*
** The Mercury runtime uses a number of memory areas or *zones*. These
** hold the detstack, the nondetstack, the heap, and potentially other
** areas such as a trail, a "solutions"-heap, and so on.
** These memory areas are each represented by an MR_MemoryZone structure
** that contains the following fields:
**
** next The memory zones are organized as a linked list of free zones
** and linked list of used zones. The next field, if not NULL,
** points to the next memory zone in the list.
**
** name A string constant used to name the allocated area.
**
** id An integer which together with the name should uniquely
** identify the allocated area.
**
** lru_token This field is filled with a token each time a zone is freed,
** it's used to track the least-recently-used zones in the free
** list so that they can be handed back to the garbage
** collector/OS. Zones with larger tokens have been used more recently
** than zones with smaller tokens.
**
** desired_size The desired size of the zone in kilobytes. The actual size
** may be larger due to roundups.
**
** redzone_size The desired size of the redzone in kilobytes. The actual size
** may be larger due to roundups.
**
** bottom The address of the bottom of the allocated area
** (should be on a page boundary).
**
** top The address one word past the top of the allocated area
** (should be on a page boundary).
**
** min The address of the lowest part of the allocated that
** will be used. This may be different to `bottom'
** so that the use of different memory zones doesn't
** beat the cache.
**
** max The highest address in this memory area that has been
** used so far. This is only computed if MR_LOWLEVEL_DEBUG
** is enabled.
**
** hardmax The address of the bottom of the last page of the allocated
** area. This is one higher than the highest address that
** can be used in this zone. We never unprotect the
** last page of a zone so that we retain protection
** against overrunning the end of the zone. This is
** obviously only available on platforms that have
** mprotect. (Should be on a page boundary.)
**
** redzone The address of the start of the region that has been
** mprotected as a redzone. Redzone is only available on
** platforms where MR_CHECK_OVERFLOW_VIA_MPROTECT is defined.
** (Should be on a page boundary.)
**
** redzone_base The original redzone.
**
** handler The address of a function to handle accesses in the
** redzone of this allocated area. This is only
** available with MR_CHECK_OVERFLOW_VIA_MPROTECT.
**
** gc_threshold This field, which is only used for heap zones, points to
** MR_heap_margin_size bytes before MR_zone_end (which is defined
** as one the fields above by the macros below). It is used to
** decide when to do garbage collection without incurring the
** expense of a subtraction on every allocation.
**
** extend_threshold
** This field, which is only used for stack zones, points to
** MR_stack_margin_size bytes before MR_zone_end.
*/
struct MR_MemoryZone_Struct {
MR_MemoryZone * MR_THREADSAFE_VOLATILE MR_zone_next;
const char *MR_zone_name;
MR_Unsigned MR_zone_id;
#ifndef MR_DO_NOT_CACHE_FREE_MEMORY_ZONES
MR_Unsigned MR_zone_lru_token;
#endif
size_t MR_zone_desired_size;
size_t MR_zone_redzone_size;
MR_Word *MR_zone_bottom;
MR_Word *MR_zone_top;
MR_Word *MR_zone_min;
MR_Word *MR_zone_max;
#ifdef MR_PROTECTPAGE
MR_Word *MR_zone_hardmax;
#endif /* MR_PROTECTPAGE */
#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
MR_Word *MR_zone_redzone_base;
MR_Word *MR_zone_redzone;
MR_ZoneHandler *MR_zone_handler;
#endif /* MR_CHECK_OVERFLOW_VIA_MPROTECT */
#if defined(MR_NATIVE_GC) && defined(MR_HIGHLEVEL_CODE)
char *MR_zone_gc_threshold;
/* == MR_zone_end - MR_heap_margin_size */
#endif
#if defined(MR_STACK_SEGMENTS) && !defined(MR_HIGHLEVEL_CODE)
char *MR_zone_extend_threshold;
/* == MR_zone_end - MR_stack_margin_size */
#endif
};
typedef struct MR_MemoryZones_Struct MR_MemoryZones;
struct MR_MemoryZones_Struct {
MR_MemoryZone *MR_zones_head;
MR_MemoryZones *MR_zones_tail;
};
#ifndef MR_DO_NOT_CACHE_FREE_MEMORY_ZONES
/*
** Free memory zones are arranged in a list of lists, The outer list (below)
** associates a size of the zones in each inner list. It is to be kept in
** sorted order from smallest to largest. So that a traversal of this list
** returns the zones that are the 'best fit' as the 'first fit'. The inner
** lists (using the MR_zone_next field of the zones) contain zones of all the
** same size.
*/
typedef struct MR_MemoryZonesFree_Struct MR_MemoryZonesFree;
struct MR_MemoryZonesFree_Struct {
size_t MR_zonesfree_size;
MR_MemoryZonesFree *MR_zonesfree_major_next;
MR_MemoryZonesFree *MR_zonesfree_major_prev;
MR_MemoryZone *MR_zonesfree_minor_head;
MR_MemoryZone *MR_zonesfree_minor_tail;
};
#endif
/*
** MR_zone_end specifies the end of the area accessible without
** a page fault. It is used by MR_clear_zone_for_GC().
*/
#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
#define MR_zone_end MR_zone_redzone
#elif defined(MR_PROTECTPAGE)
#define MR_zone_end MR_zone_hardmax
#else
#define MR_zone_end MR_zone_top
#endif
/*
** MR_clear_zone_for_GC(MR_MemoryZone *zone, void *start_address):
** Zero out the (hopefully unused) portion of the zone from the specified
** `start_address' to the end of the zone. This is used to avoid unwanted
** memory retention due to false hits in the conservative garbage collector.
*/
#define MR_clear_zone_for_GC(zone, start_address) \
((void) MR_memset((start_address), 0, \
(char*)((zone)->MR_zone_end) - (char *)(start_address)))
/*
** Rather then using mprotect directly, we call MR_protect_pages which
** is OS independent.
*/
#ifdef MR_PROTECTPAGE
#ifdef MR_WIN32
#ifndef PROT_NONE
#define PROT_NONE 0x0000
#endif
#ifndef PROT_READ
#define PROT_READ 0x0001
#endif
#ifndef PROT_WRITE
#define PROT_WRITE 0x0002
#endif
#endif
int MR_protect_pages(void *addr, size_t size, int prot_flags);
#endif
/*
** MR_init_zones() initializes the memory zone pool and the offset
** generator. It should be used before any zones are created or
** offsets requested.
*/
extern void MR_init_zones(void);
/*
** MR_create_zone(Name, Id, Size, Offset, RedZoneSize, FaultHandler)
** allocates a new memory zone with name Name, and number Id, size
** Size (in bytes - which gets rounded up to the nearest multiple of
** the page size), an offset Offset from the page boundary at which
** to start using the memory region (used to help avoid beating the cache),
** the amount Redzone of memory (in bytes) to be protected as a redzone
** (must be less than Size), and the address of a function to handle
** memory references in the redzone.
** If it fails to allocate or protect the zone, then it exits.
** If MR_CHECK_OVERFLOW_VIA_MPROTECT is unavailable, then the last two
** arguments are ignored.
**
** This may re-use previously allocated memory but will re-configure the
** name, redzone and handler.
*/
extern MR_MemoryZone *MR_create_or_reuse_zone(const char *name,
size_t size, size_t offset, size_t redsize,
MR_ZoneHandler *handler);
extern void MR_release_zone(MR_MemoryZone *zone);
/*
** MR_extend_zone(Zone, NewSize) extends Zone to increase its size to NewSize,
** and returns the difference between the new address of the memory area of
** the zone and the old.
*/
extern MR_Integer MR_extend_zone(MR_MemoryZone *zone,
size_t new_size);
/*
** MR_reset_redzone(Zone) resets the redzone on the given MR_MemoryZone to the
** original zone specified in the call to create_or_reuse_zone() if
** MR_CHECK_OVERFLOW_VIA_MPROTECT is defined. Otherwise it does nothing.
*/
extern void MR_reset_redzone(MR_MemoryZone *zone);
/*
** MR_get_used_memory_zones_readonly() returns a pointer to the linked list of
** used memory zones. The list should be considered read only and may not be
** complete. This is suitable for use where locking is impossible but
** incomplete data is okay.
*/
extern MR_MemoryZone *MR_get_used_memory_zones_readonly(void);
/*
** Returns true iff ptr is the given zone.
*/
extern MR_bool MR_in_zone(const MR_Word *ptr,
const MR_MemoryZone *zone);
/*
** MR_debug_memory(fp) prints out debugging information about the current
** memory zones to fp.
*/
extern void MR_debug_memory(FILE *fp);
/*
** MR_debug_memory_zone(fp, zone) prints out debugging information about zone
** to fp.
*/
extern void MR_debug_memory_zone(FILE *fp, MR_MemoryZone *zone);
/*
** MR_next_offset() returns sucessive offsets across the primary cache. Useful
** when calling {create,construct}_zone().
*/
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 */