/* Alloc.c -- Memory allocation functions 2008-09-24 Igor Pavlov Public domain */ #include #include #ifdef _7ZIP_LARGE_PAGES #ifdef __linux__ #ifndef _7ZIP_ST #include #endif #include #include #include #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 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); }