33#ifndef TH_HAVE_THREAD
44#define __thread
55#endif
6+
7+ #if defined(TH_DISABLE_HEAP_TRACKING )
8+ #elif (defined(__unix ) || defined(_WIN32 ))
9+ #include <malloc.h>
10+ #elif defined(__APPLE__ )
11+ #include <malloc/malloc.h>
12+ #endif
13+
614/* Torch Error Handling */
715static void defaultTorchErrorHandlerFunction (const char * msg , void * data )
816{
@@ -13,9 +21,6 @@ static void defaultTorchErrorHandlerFunction(const char *msg, void *data)
1321static __thread void (* torchErrorHandlerFunction )(const char * msg , void * data ) = defaultTorchErrorHandlerFunction ;
1422static __thread void * torchErrorHandlerData ;
1523
16- static __thread void (* torchGCFunction )(void * data ) = NULL ;
17- static __thread void * torchGCData ;
18-
1924void _THError (const char * file , const int line , const char * fmt , ...)
2025{
2126 char msg [2048 ];
@@ -94,13 +99,62 @@ void THSetArgErrorHandler( void (*torchArgErrorHandlerFunction_)(int argNumber,
9499 torchArgErrorHandlerData = data ;
95100}
96101
102+ static __thread void (* torchGCFunction )(void * data ) = NULL ;
103+ static __thread void * torchGCData ;
104+ static __thread long torchHeapSize = 0 ;
105+ static __thread long torchHeapSizeSoftMax = 300000000 ; // 300MB, adjusted upward dynamically
106+
107+ /* Optional hook for integrating with a garbage-collected frontend.
108+ *
109+ * If torch is running with a garbage-collected frontend (e.g. Lua),
110+ * the GC isn't aware of TH-allocated memory so may not know when it
111+ * needs to run. These hooks trigger the GC to run in two cases:
112+ *
113+ * (1) When a memory allocation (malloc, realloc, ...) fails
114+ * (2) When the total TH-allocated memory hits a dynamically-adjusted
115+ * soft maximum.
116+ */
97117void THSetGCHandler ( void (* torchGCFunction_ )(void * data ), void * data )
98118{
99119 torchGCFunction = torchGCFunction_ ;
100120 torchGCData = data ;
101121}
102122
103- void * THAllocInternal (long size )
123+ static long getAllocSize (void * ptr ) {
124+ #if defined(TH_DISABLE_HEAP_TRACKING )
125+ return 0 ;
126+ #elif defined(__unix )
127+ return malloc_usable_size (ptr );
128+ #elif defined(__APPLE__ )
129+ return malloc_size (ptr );
130+ #elif defined(_WIN32 )
131+ return _msize (ptr );
132+ #else
133+ return 0 ;
134+ #endif
135+ }
136+
137+ /* (1) if the torch-allocated heap size exceeds the soft max, run GC
138+ * (2) if post-GC heap size exceeds 80% of the soft max, increase the
139+ * soft max by 40%
140+ */
141+ static void maybeTriggerGC () {
142+ if (torchGCFunction && torchHeapSize > torchHeapSizeSoftMax ) {
143+ torchGCFunction (torchGCData );
144+ if (torchHeapSize > torchHeapSizeSoftMax * 0.8 ) {
145+ torchHeapSizeSoftMax = torchHeapSizeSoftMax * 1.4 ;
146+ }
147+ }
148+ }
149+
150+ // hooks into the TH heap tracking
151+ void THHeapUpdate (long size ) {
152+ torchHeapSize += size ;
153+ if (size > 0 )
154+ maybeTriggerGC ();
155+ }
156+
157+ static void * THAllocInternal (long size )
104158{
105159 void * ptr ;
106160
@@ -119,6 +173,8 @@ void* THAllocInternal(long size)
119173 {
120174 ptr = malloc (size );
121175 }
176+
177+ THHeapUpdate (getAllocSize (ptr ));
122178 return ptr ;
123179}
124180
@@ -159,12 +215,14 @@ void* THRealloc(void *ptr, long size)
159215 if (size < 0 )
160216 THError ("$ Torch: invalid memory size -- maybe an overflow?" );
161217
218+ THHeapUpdate (- getAllocSize (ptr ));
162219 void * newptr = realloc (ptr , size );
163220
164221 if (!newptr && torchGCFunction ) {
165222 torchGCFunction (torchGCData );
166223 newptr = realloc (ptr , size );
167224 }
225+ THHeapUpdate (getAllocSize (newptr ? newptr : ptr ));
168226
169227 if (!newptr )
170228 THError ("$ Torch: not enough memory: you tried to reallocate %dGB. Buy new RAM!" , size /1073741824 );
@@ -174,6 +232,7 @@ void* THRealloc(void *ptr, long size)
174232
175233void THFree (void * ptr )
176234{
235+ THHeapUpdate (- getAllocSize (ptr ));
177236 free (ptr );
178237}
179238
0 commit comments