blob: 1ba571137a6014c9681538a08403cbc48da1a324 [file] [log] [blame]
/* Alloc.c -- Memory allocation functions
2008-09-24
Igor Pavlov
Public domain */
#include <stdio.h>
#include <stdlib.h>
#ifdef _7ZIP_LARGE_PAGES
#ifdef __linux__
#ifndef _7ZIP_ST
#include <pthread.h>
#endif
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#define PROTECTION (PROT_READ | PROT_WRITE)
#ifndef MAP_HUGETLB
#error 1
#define MAP_HUGETLB 0x40
#endif
/* Only ia64 requires this */
#ifdef __ia64__
#define ADDR (void *)(0x8000000000000000UL)
#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_FIXED)
#else
#define ADDR (void *)(0x0UL)
#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
#endif
#endif /* __linux__ */
#endif /* _7ZIP_LARGE_PAGES */
#include "Alloc.h"
/* #define _SZ_ALLOC_DEBUG */
/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
#ifdef _SZ_ALLOC_DEBUG
#include <stdio.h>
int g_allocCount = 0;
int g_allocCountMid = 0;
int g_allocCountBig = 0;
#endif
void *MyAlloc(size_t size)
{
if (size == 0)
return 0;
#ifdef _SZ_ALLOC_DEBUG
{
void *p = malloc(size);
fprintf(stderr, "\nAlloc %10d bytes, count = %10d, addr = %8X", size, g_allocCount++, (unsigned)p);
return p;
}
#else
return malloc(size);
#endif
}
void MyFree(void *address)
{
#ifdef _SZ_ALLOC_DEBUG
if (address != 0)
fprintf(stderr, "\nFree; count = %10d, addr = %8X", --g_allocCount, (unsigned)address);
#endif
free(address);
}
#ifdef __linux__
#define _7ZIP_MAX_HUGE_ALLOCS 64
static void *g_HugePageAddr[_7ZIP_MAX_HUGE_ALLOCS] = { NULL };
static size_t g_HugePageLen[_7ZIP_MAX_HUGE_ALLOCS];
#endif
static void *VirtualAlloc(void *address, size_t size, int AllocLargePages)
{
#ifdef _7ZIP_LARGE_PAGES
if (AllocLargePages)
{
#ifdef __linux__
/* huge pages support for Linux; added by Joachim Henke */
#ifndef _7ZIP_ST
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
int i;
address = NULL;
#ifndef _7ZIP_ST
pthread_mutex_lock(&mutex);
#endif
for (i = 0; i < _7ZIP_MAX_HUGE_ALLOCS; ++i)
{
if (g_HugePageAddr[i] == NULL)
{
address = mmap(ADDR, size, PROTECTION, FLAGS, 0, 0);
if (address == MAP_FAILED)
{
address = NULL;
break;
}
g_HugePageLen[i] = size;
g_HugePageAddr[i] = address;
printf("HUGE[%d]=%ld %p\n",i,(long)size,address);
break;
}
}
#ifndef _7ZIP_ST
pthread_mutex_unlock(&mutex);
#endif
return address;
#endif
}
#endif
return malloc(size);
}
static int VirtualFree(void *address)
{
#ifdef _7ZIP_LARGE_PAGES
#ifdef __linux__
int i;
for (i = 0; i < _7ZIP_MAX_HUGE_ALLOCS; ++i)
{
if (g_HugePageAddr[i] == address)
{
munmap(address, g_HugePageLen[i]);
g_HugePageAddr[i] = NULL;
return 1;
}
}
#endif
#endif
free(address);
return 1;
}
void *MidAlloc(size_t size)
{
if (size == 0)
return 0;
#ifdef _SZ_ALLOC_DEBUG
fprintf(stderr, "\nAlloc_Mid %10d bytes; count = %10d", size, g_allocCountMid++);
#endif
return VirtualAlloc(0, size, 0);
}
void MidFree(void *address)
{
#ifdef _SZ_ALLOC_DEBUG
if (address != 0)
fprintf(stderr, "\nFree_Mid; count = %10d", --g_allocCountMid);
#endif
if (address == 0)
return;
VirtualFree(address);
}
#ifdef _7ZIP_LARGE_PAGES
size_t g_LargePageSize = 0;
#endif
void SetLargePageSize()
{
printf("SetLargePageSize : <>\n");
#ifdef _7ZIP_LARGE_PAGES
size_t size = 0;
#if defined(__linux__)
size = sysconf(_SC_PAGESIZE);
printf("SetLargePageSize : size=%ld\n",(long)size);
if (size == -1) size = 0;
#endif
if (size == 0 || (size & (size - 1)) != 0)
return;
g_LargePageSize = size;
printf("SetLargePageSize : %ld\n",(long)g_LargePageSize);
#endif
}
void *BigAlloc(size_t size)
{
if (size == 0)
return 0;
#ifdef _SZ_ALLOC_DEBUG
fprintf(stderr, "\nAlloc_Big %10d bytes; count = %10d", size, g_allocCountBig++);
#endif
#ifdef _7ZIP_LARGE_PAGES
if (g_LargePageSize != 0 && g_LargePageSize <= (1 << 30) && size >= (1 << 18))
{
void *res = VirtualAlloc(0, (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)),1);
printf("BigAlloc : %ld %ld => %p\n",(long)g_LargePageSize,(long)size,res);
if (res != 0)
return res;
}
#endif
return VirtualAlloc(0, size, 0);
}
void BigFree(void *address)
{
#ifdef _SZ_ALLOC_DEBUG
if (address != 0)
fprintf(stderr, "\nFree_Big; count = %10d", --g_allocCountBig);
#endif
if (address == 0)
return;
VirtualFree(address);
}