rambrain
managedMemory.cpp
Go to the documentation of this file.
1 /* rambrain - a dynamical physical memory extender
2  * Copyright (C) 2015 M. Imgrund, A. Arth
3  * mimgrund (at) mpifr-bonn.mpg.de
4  * arth (at) usm.uni-muenchen.de
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "managedMemory.h"
21 #include "common.h"
22 #include "exceptions.h"
23 #include "dummyManagedMemory.h"
24 #include <sys/signal.h>
25 #include "rambrainconfig.h"
26 #include "rambrain_atomics.h"
27 #include "git_info.h"
28 #include "managedPtr.h"
29 #include <time.h>
30 #include <mm_malloc.h>
31 
32 namespace rambrain
33 {
34 namespace rambrainglobals
35 {
37 }
38 
40 
41 #ifdef SWAPSTATS
42 #ifdef LOGSTATS
43 FILE *managedMemory::logFile = fopen ( "rambrain-swapstats.log", "w" );
44 bool managedMemory::firstLog = true;
45 #endif
46 #endif
47 
49 #ifdef PARENTAL_CONTROL
52 bool managedMemory::threadSynced = false;
53 pthread_mutex_t managedMemory::parentalMutex = PTHREAD_MUTEX_INITIALIZER;
54 pthread_cond_t managedMemory::parentalCond = PTHREAD_COND_INITIALIZER;
55 pthread_t managedMemory::creatingThread = 0;
56 #endif
57 
58 
59 
60 pthread_mutex_t managedMemory::stateChangeMutex = PTHREAD_MUTEX_INITIALIZER;
61 pthread_cond_t managedMemory::swappingCond = PTHREAD_COND_INITIALIZER;
62 pthread_mutex_t rambrainGlobalCriticalSectionControl::mutex = PTHREAD_MUTEX_INITIALIZER;
63 
65 {
66 
67  memory_max = size;
70  defaultManager = this;
71 #ifdef PARENTAL_CONTROL
72  managedMemoryChunk *chunk = mmalloc ( 0 ); //Create root element.
73  chunk->status = MEM_ROOT;
74 #endif
75  this->swap = swap;
76  if ( !swap ) {
77  throw incompleteSetupException ( "no swap manager defined" );
78  }
79 #ifdef SWAPSTATS
80  signal ( SIGUSR1, sigswapstats );
81 
82 #ifdef LOGSTATS
83  if ( ! Timer::isRunning() ) {
84  Timer::startTimer ( 0L, 100000000L );
85  }
86 #endif
87 #endif
88 }
89 
91 {
92 #ifdef SWAPSTATS
93 #ifdef LOGSTATS
94  if ( previousManager == NULL ) {
96 
97  signal ( SIGUSR1, SIG_IGN );
98  }
99 
100 #endif
101 #endif
102 
103  if ( defaultManager == this ) {
104 
106  }
107  if ( swap ) {
109  }
110 #ifdef PARENTAL_CONTROL
111  //Clean up objects:
112  recursiveMfree ( root );
113 #else
114  linearMfree();
115 #endif
116 }
117 
119 {
120  if ( swap ) {
122  swap->close();
123  }
124 }
125 
127 {
128  return memory_used;
129 }
130 
132 {
133  return memory_swapped;
134 }
135 
137 {
138  return swap->getFreeSwap();
139 }
140 
142 {
143  return swap->getSwapSize();
144 }
145 
147 {
148  rambrain_pthread_mutex_lock ( &stateChangeMutex );
149  if ( size > memory_max ) {
150  memory_max = size;
151  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
152  return true;
153  } else {
154  if ( size < memory_used ) {
155 
156  //Try to swap out as much memory as needed:
157  global_bytesize tobefreed = ( memory_used - size );
158  if ( swapOut ( tobefreed ) != ERR_SUCCESS ) {
159  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
160  return false;
161  }
162 
163  memory_max = size;
164  swapOut ( 0 ); // Swap out further to adapt to new memory limits. This must not necessarily succeed.
165  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
166  return true;
167  } else {
168  memory_max = size;
169  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
170  return true;
171  }
172  }
173  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
174  return false; //Resetting this is not implemented yet.
175 }
176 
178 {
179  bool old = outOfSwapIsFatal;
180  outOfSwapIsFatal = fatal;
181  return old;
182 }
183 
184 
186 {
187  bool cacheCleaned = false;
188  while ( sizereq + memory_used > memory_max ) {
189  if ( orisSwappedin && ( orisSwappedin->status & MEM_ALLOCATED || orisSwappedin->status == MEM_SWAPIN ) ) {
190  return true;
191  }
192 
193  if ( sizereq + memory_used - memory_tobefreed > memory_max ) {
195  if ( err != ERR_SUCCESS ) { //Execute swapOut in protected context
196  //We did not manage to swap out our stuff right away.
197  if ( memory_tobefreed == 0 ) { //If other memory is to be freed, perhaps other threads may continue?
198  if ( cacheCleaned ) {
199  if ( outOfSwapIsFatal ) { //throw if user wants us to, otherwise wait indefinitely (ram-deadlock)
200  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
201  switch ( err ) {
203  Throw ( memoryException ( "Could not swap memory: Object size requested is bigger than actual RAM limits" ) );
205  Throw ( memoryException ( "Could not swap memory: Too much used elements to make room" ) );
206  case ERR_SWAPFULL:
207  Throw ( memoryException ( "Could not swap memory: Swap is unrecoverably full" ) );
208  default:
209  Throw ( memoryException ( "Could not swap memory, I don't know why" ) );
210  }
211  } else {
212  swap->cleanupCachedElements();//Can help in multithreaded situation
213  }
214  } else {
215  //Last resort: clean Cache
217  cacheCleaned = true;
218  continue;
219  }
220  }
221  }
222 
223  }
224  if ( sizereq + memory_used > memory_max ) {
225  waitForAIO();
226  }
227  }
228  if ( orisSwappedin && ( orisSwappedin->status & MEM_ALLOCATED || orisSwappedin->status == MEM_SWAPIN ) ) {
229  return true;
230  }
231  return false;
232 }
233 
234 
236 {
237  rambrain_pthread_mutex_lock ( &stateChangeMutex );
238  sizereq += sizereq % memoryAlignment == 0 ? 0 : memoryAlignment - sizereq % memoryAlignment; //f**k memoryAlignment
239  ensureEnoughSpace ( sizereq );
240 
241  memory_used += sizereq;
242 
243  //We are left with enough free space to malloc.
244 #ifdef PARENTAL_CONTROL
246 #else
248 #endif
249  chunk->status = MEM_ALLOCATED;
250  chunk->size = sizereq;
251  chunk->swapBuf = NULL;
252 #ifdef PARENTAL_CONTROL
253  chunk->child = invalid;
254  chunk->parent = parent;
255  if ( chunk->id == root ) { //We're inserting root elem.
256 
257  chunk->next = invalid;
258  chunk->schedBuf = NULL;
259  } else {
260 #endif
261  //Register this chunk in swapping logic:
262  schedulerRegister ( *chunk );
263  touch ( *chunk );
264 #ifdef PARENTAL_CONTROL
265  //fill in tree:
267  if ( pchunk.child == invalid ) {
268  chunk->next = invalid; //Einzelkind
269  pchunk.child = chunk->id;
270  } else {
271  chunk->next = pchunk.child;
272  pchunk.child = chunk->id;
273  }
274 
275  }
276 #endif
277 
278  memChunks.insert ( {chunk->id, chunk} );
279  if ( sizereq != 0 ) {
280  chunk->locPtr = _mm_malloc ( sizereq , memoryAlignment );
281  if ( !chunk->locPtr ) {
282  Throw ( memoryException ( "Malloc failed" ) );
283  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
284  return NULL;
285  }
286  }
287  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
288  return chunk;
289 }
290 
292 {
293  managedMemoryChunk chunk = resolveMemChunk ( id );
294  return swapIn ( chunk );
295 }
296 
297 bool managedMemory::prepareUse ( managedMemoryChunk &chunk, bool acquireLock )
298 {
299  if ( acquireLock ) {
300  rambrain_pthread_mutex_lock ( &stateChangeMutex );
301  }
302  switch ( chunk.status ) {
303  case MEM_SWAPOUT: // Object is about to be swapped out.
304  if ( !waitForSwapout ( chunk, true ) ) {
305  if ( acquireLock ) {
306  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
307  }
308  return true;
309  }
310  case MEM_SWAPPED:
311 #ifdef SWAPSTATS
312  ++swap_misses;
313  --swap_hits;
314 #endif
315  if ( !swapIn ( chunk ) ) {
316  errmsgf ( "Could not swap in chunk %lu", chunk.id );
317  if ( acquireLock ) {
318  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
319  }
320  return false;
321  }
322  default:
323  ;
324  }
325  if ( acquireLock ) {
326  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
327  }
328  return true;
329 
330 }
331 
332 
333 bool managedMemory::setUse ( managedMemoryChunk &chunk, bool writeAccess = false )
334 {
335  rambrain_pthread_mutex_lock ( &stateChangeMutex );
336  //printf("setUse on %d\n",chunk.id);
337  ++chunk.useCnt;//This protects element from being swapped out by somebody else if it was swapped in.
338  switch ( chunk.status ) {
339  case MEM_SWAPOUT: // Object is about to be swapped out.
340 
341  case MEM_SWAPPED:
342  if ( !prepareUse ( chunk, false ) ) {
343  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
344  return false;
345  }
346  case MEM_SWAPIN: // Wait for object to appear
347  if ( !waitForSwapin ( chunk, true ) ) {
348  if ( ! ( chunk.status & MEM_ALLOCATED ) ) {
349  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
350  errmsgf ( "Waited for swapin of chunk %lu and could not make it.", chunk.id );
351  return false;
352  }
353  }
354  case MEM_ALLOCATED:
356  case MEM_ALLOCATED_INUSE:
358  if ( writeAccess ) {
360  swap->invalidateCacheFor ( chunk );
361  }
363 
364 #ifdef SWAPSTATS
365  ++swap_hits;
366 #endif
367  touch ( chunk );
368  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
369  return true;
370  case MEM_ROOT:
371  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
372  return false;
373 
374  }
375  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
376  return false;
377 }
378 
380 {
381 
382  throw unfinishedCodeException ( "TODO: Locking, synchronizing, and everything" );
383  managedMemoryChunk &chunk = resolveMemChunk ( id );
384  if ( !setUse ( chunk ) ) {
385  return false;
386  }
387  rambrain_pthread_mutex_lock ( &stateChangeMutex );
388  void *realloced = realloc ( chunk.locPtr, sizereq );
389  if ( realloced ) {
390  memory_used -= chunk.size - sizereq;
391  chunk.size = sizereq;
392  chunk.locPtr = realloced;
393  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
394  unsetUse ( chunk );
395  return true;
396  } else {
397  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
398  unsetUse ( chunk );
399  return false;
400  }
401 }
402 
403 
405 {
406  managedMemoryChunk chunk = resolveMemChunk ( id );
407  return unsetUse ( chunk );
408 }
409 
410 
412 {
413  managedMemoryChunk chunk = resolveMemChunk ( id );
414  return setUse ( chunk );
415 }
416 
417 bool managedMemory::unsetUse ( managedMemoryChunk &chunk , unsigned int no_unsets )
418 {
419  //printf("unsetUse on %d, %d times\n",chunk.id,no_unsets);
420  rambrain_pthread_mutex_lock ( &stateChangeMutex );
421 
422  if ( no_unsets == 0 ) {
423  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
424 
425  return Throw ( memoryException ( "Cannot unset zero uses" ) );
426  }
427  if ( chunk.useCnt < no_unsets ) {
428  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
429  return Throw ( memoryException ( "Can not unset use of not used memory" ) );
430  }
431 
432  chunk.useCnt -= no_unsets;
433  if ( chunk.status & MEM_ALLOCATED_INUSE_READ ) {
434  chunk.status = ( chunk.useCnt == 0 ? MEM_ALLOCATED : chunk.status );
435 
436  }
437  untouch ( chunk );
438  signalSwappingCond();//Unsetting use may trigger different possible swapouts.
439  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
440  return true;
441 }
442 
444 {
445 
446 #ifdef PARENTAL_CONTROL
447  if ( pthread_mutex_trylock ( &parentalMutex ) == 0 ) {
448  rambrain_pthread_mutex_unlock ( &parentalMutex );
449  } else {
450  if ( pthread_equal ( pthread_self(), creatingThread ) ) {
451  rambrain_pthread_mutex_unlock ( &parentalMutex );
452  }
453  }
454 #endif
455  throw e;
456 }
457 
458 
459 
460 void managedMemory::mfree ( memoryID id, bool inCleanup )
461 {
462  rambrain_pthread_mutex_lock ( &stateChangeMutex );
463  managedMemoryChunk *chunk = memChunks[id];
464  if ( chunk->status & MEM_ALLOCATED_INUSE ) {
465  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
466  Throw ( memoryException ( "Can not free memory which is in use" ) );
467  return;
468  }
469 
470 
471 
472 #ifdef PARENTAL_CONTROL
473  if ( chunk->child != invalid ) {
474  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
475  Throw ( memoryException ( "Can not free memory which has active children" ) );
476  return;
477  }
478  if ( chunk->id != root ) {
479  if ( !inCleanup ) {
480  schedulerDelete ( *chunk );
481  }
482  if ( chunk->status == MEM_ALLOCATED ) {
483  _mm_free ( chunk->locPtr );
484  memory_used -= chunk->size ;
485  }
486  if ( chunk->swapBuf ) {
487  swap->swapDelete ( chunk );
488  }
489  managedMemoryChunk *pchunk = &resolveMemChunk ( chunk->parent );
490  if ( pchunk->child == chunk->id ) {
491  pchunk->child = chunk->next;
492  } else {
493  pchunk = &resolveMemChunk ( pchunk->child );
494  do {
495  if ( pchunk->next == chunk->id ) {
496  pchunk->next = chunk->next;
497  break;
498  };
499  if ( pchunk->next == invalid ) {
500  break;
501  } else {
502  pchunk = &resolveMemChunk ( pchunk->next );
503  }
504  } while ( 1 == 1 );
505  }
506  }
507 #else
508  if ( !inCleanup ) {
509  schedulerDelete ( *chunk );
510  }
511  if ( chunk->status == MEM_ALLOCATED ) {
512  _mm_free ( chunk->locPtr );
513  memory_used -= chunk->size ;
514  }
515  if ( chunk->swapBuf ) {
516  swap->swapDelete ( chunk );
517  }
518 #endif
519  //Delete element itself
520  memChunks.erase ( id );
521  delete ( chunk );
522  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
523 }
524 
525 #ifdef PARENTAL_CONTROL
526 
528 {
529  rambrain_pthread_mutex_lock ( &stateChangeMutex );
530  const managedMemoryChunk &chunk = resolveMemChunk ( id );
531  if ( chunk.child == invalid ) {
532  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
533  return 0;
534  }
535  unsigned int no = 1;
536  const managedMemoryChunk *child = &resolveMemChunk ( chunk.child );
537  while ( child->next != invalid ) {
538  child = &resolveMemChunk ( child->next );
539  no++;
540  }
541  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
542  return no;
543 }
544 
545 
546 void managedMemory::printTree ( managedMemoryChunk *current, unsigned int nspaces )
547 {
548  rambrain_pthread_mutex_lock ( &stateChangeMutex );
549  if ( !current ) {
550  current = &resolveMemChunk ( root );
551  }
552  do {
553  for ( unsigned int n = 0; n < nspaces; n++ ) {
554  printf ( " " );
555  }
556  printf ( "(%d : size %lu Bytes, %s, ", current->id, current->size, current->preemptiveLoaded ? "P" : "" );
557  switch ( current->status ) {
558  case MEM_ROOT:
559  printf ( "Root Element" );
560  break;
561  case MEM_SWAPIN:
562  printf ( "Swapping in" );
563  break;
564  case MEM_SWAPOUT:
565  printf ( "Swapping out" );
566  break;
567  case MEM_SWAPPED:
568  printf ( "Swapped out" );
569  break;
570  case MEM_ALLOCATED:
571  printf ( "Allocated" );
572  break;
573  case MEM_ALLOCATED_INUSE:
574  printf ( "Allocated&inUse" );
575  break;
577  printf ( "Allocated&inUse (writable)" );
578  break;
580  printf ( "Allocated&inUse (readonly)" );
581  break;
582  }
583  printf ( ")\n" );
584  if ( current->child != invalid ) {
585  printTree ( &resolveMemChunk ( current->child ), nspaces + 1 );
586  }
587  if ( current->next != invalid ) {
588  current = &resolveMemChunk ( current->next );
589  } else {
590  break;
591  };
592  } while ( 1 == 1 );
593  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
594 }
595 
598 {
599  managedMemoryChunk *oldchunk = &resolveMemChunk ( id );
600  managedMemoryChunk *next;
601  do {
602  if ( oldchunk->child != invalid ) {
603  recursiveMfree ( oldchunk->child );
604  }
605  if ( oldchunk->next != invalid ) {
606  next = &resolveMemChunk ( oldchunk->next );
607  } else {
608  break;
609  }
610  mfree ( oldchunk->id, true );
611  oldchunk = next;
612  } while ( 1 == 1 );
613  mfree ( oldchunk->id, true );
614 }
615 #else
616 
619 {
620  if ( memChunks.size() == 0 ) {
621  return;
622  }
623  auto it = memChunks.begin();
624  memoryID old;
625  while ( it != memChunks.end() ) {
626  old = it->first;
627  ++it;
628  mfree ( old , true );
629  }
630 }
631 
632 #endif
634 {
635  return *memChunks[id];
636 }
637 
638 #ifdef SWAPSTATS
640 {
641  infomsgf ( "A total of %lu swapouts occured, writing out %lu bytes (%.3e Bytes/avg)\
642  \n\tA total of %lu swapins occured, reading in %lu bytes (%.3e Bytes/avg)\
643  \n\twe used already loaded elements %lu times, %lu had to be fetched\
644  \n\tthus, the hits over misses rate was %.5f\
645  \n\tfraction of swapped out ram (currently) %.2e\n\t %lu scheduled out bytes and %lu scheduled in bytes saved by caching.", n_swap_out, swap_out_bytes, \
646  ( ( float ) swap_out_bytes ) / n_swap_out, n_swap_in, swap_in_bytes, ( ( float ) swap_in_bytes ) / n_swap_in, \
647  swap_hits, swap_misses, ( ( float ) swap_hits / swap_misses ), ( ( float ) memory_swapped ) / ( memory_used + memory_swapped ),
648  swap_out_scheduled_bytes - swap_out_bytes, swap_in_scheduled_bytes - swap_in_bytes );
649 }
650 
652 {
654 }
655 
656 #define SAFESWAP(func) (defaultManager->swap != NULL ? defaultManager->swap->func : 0lu)
657 
659 {
660  if ( defaultManager == NULL ) {
661  return;
662  }
663 
664  global_bytesize usedSwap = SAFESWAP ( getUsedSwap() );
665  global_bytesize totalSwap = SAFESWAP ( getSwapSize() );
666 
667 #ifdef LOGSTATS
668  if ( firstLog ) {
669  fprintf ( managedMemory::logFile, "#Time [ms]\tPrep for swap out [B] \tSwapped out [B]\tSwapped out last [B]\tPrep for swap in [B] \tSwapped in [B]\tSwapped in last [B]\tHits / Miss\tMemory Used [B]\t\
670  Memory Used\tSwap Used [B]\tSwap Used\n" );
671  firstLog = false;
672  }
673  int64_t now = std::chrono::duration_cast<std::chrono::milliseconds> ( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
674  fprintf ( logFile, "%ld\t%lu\t%lu\t%lu\t%lu\t%lu\t%lu\t%e\t%lu\t%e\t%lu\t%e\n",
675  now,
685  usedSwap,
686  ( double ) usedSwap / totalSwap );
687  fflush ( logFile );
688 #else
689  printf ( "%lu\t%lu\t%lu\t%lu\t%lu\t%lu\t%e\t%lu\t%e\t%lu\t%e\n",
699  usedSwap,
700  ( double ) usedSwap / totalSwap );
701 #endif
704 #ifdef LOGSTATS
706 #endif
707 }
709 {
710  return ( ( double ) swap_hits ) / swap_misses;
711 }
712 
713 
714 #endif
715 
717 {
718 
719 #ifdef SWAPSTATS
720  const char *swapstats = "with swapstats";
721 #else
722  const char *swapstats = "without swapstats";
723 #endif
724 #ifdef LOGSTATS
725  const char *logstats = "with logstats";
726 #else
727  const char *logstats = "Without logstats";
728 #endif
729 #ifdef PARENTAL_CONTROL
730  const char *parentalcontrol = "with parental control";
731 #else
732  const char *parentalcontrol = "without parental_control";
733 #endif
734 
735  infomsgf ( "compiled from %s\n\ton %s at %s\n\
736  \t%s , %s , %s\n\
737  \n \t git diff\n%s\n", gitCommit, __DATE__, __TIME__, swapstats, logstats, parentalcontrol, gitDiff );
738 
739 
740 }
741 
743 {
744  pthread_cond_broadcast ( &swappingCond );
745 }
746 
748 {
749  if ( swap->checkForAIO() ) { //Some AIO has arrived...
750  return;
751  }
752  //Some other thread waits for us, we just linger around to see the result:
753  pthread_cond_wait ( &swappingCond, &stateChangeMutex );
754 }
755 
756 
757 bool managedMemory::waitForSwapin ( managedMemoryChunk &chunk, bool keepSwapLock )
758 {
759  if ( chunk.status == MEM_SWAPOUT || chunk.status == MEM_SWAPPED ) { //Chunk is about to be swapped out...
760  if ( !keepSwapLock ) {
761  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
762  }
763  return false;
764  }
765  while ( chunk.status == MEM_SWAPIN ) {
766  waitForAIO();
767  }
768  if ( !keepSwapLock ) {
769  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
770  }
771  if ( chunk.status & MEM_ALLOCATED ) {
772  return true;
773  } else {
774  return false;
775  }
776 }
777 
778 
779 bool managedMemory::waitForSwapout ( managedMemoryChunk &chunk, bool keepSwapLock )
780 {
781  if ( ( chunk.status == MEM_SWAPIN ) | ( chunk.status & MEM_ALLOCATED ) ) { //We would wait indefinitely, as the chunk is not about to appear
782  if ( !keepSwapLock ) {
783  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
784  }
785  return false;
786  }
787  while ( chunk.status == MEM_SWAPOUT ) {
788  waitForAIO();
789  }
790 
791  if ( !keepSwapLock ) {
792  rambrain_pthread_mutex_unlock ( &stateChangeMutex );
793  }
794  if ( chunk.status == MEM_SWAPPED ) {
795  return true;
796  } else {
797  return false;
798  }
799 }
800 
801 
802 }
803 
804 void rambrain::managedMemory::claimUsageof ( rambrain::global_bytesize bytes, bool rambytes, bool used )
805 {
806  if ( rambytes ) {
807  memory_used += used ? bytes : - bytes ;
808  } else {
809  memory_swapped += used ? bytes : -bytes ;
810  }
811 
812 }
813 
815 {
816  memory_tobefreed += tobefreed ? bytes : -bytes;
817 }
818 
819 
820 
821 
virtual bool swapIn(memoryID id)
Convenience function for swapIn ( managedMemoryChunk &chunk )
virtual bool checkForAIO()
Definition: managedSwap.h:122
Exception for errors with the memory.
Definition: exceptions.h:87
global_bytesize swap_misses
virtual swapErrorCode swapOut(global_bytesize min_size)=0
swaps out at least min_size bytes
static bool isRunning()
Simple getter.
Definition: timer.h:54
bool setOutOfSwapIsFatal(bool fatal=true)
set policy what to do when out of memory in both ram and swap
An exception class for when code is used which is not fully finished developping. ...
Definition: exceptions.h:151
global_bytesize getSwappedMemory() const
returns current swap usage
Swapping action was successful.
memoryID id
an ID to identify the object in scheduler or elsewhere
bool waitForSwapout(managedMemoryChunk &chunk, bool keepSwapLock=false)
Waits until a certain chunk is swapped out.
static void stopTimer()
Stop the timer.
Definition: timer.cpp:56
static void sigswapstats(int sig)
static binding that will print out some stats. Compile with cmake -DSWAPSTATS=on and send process SIG...
static void signalSwappingCond()
signals that a swapping action has completed and memory limits have changed
void recursiveMfree(memoryID id)
recursively deletes the objects in memory, first children, then parents.
Exception class for cases of an incomplete setup.
Definition: exceptions.h:54
void * locPtr
pointer to the actual data in RAM
bool setUse(memoryID id)
Convenience interface for setUse( managedMemoryChunk &chunk, bool writeAccess )
global_bytesize getTotalSwapMemory() const
return current swap capacity
static bool Throw(memoryException e)
Custom throw function, as we need to prevent throwing exceptions in construtors.
bool mrealloc(memoryID id, global_bytesize sizereq)
this function is a stub. In the future it should be capable of resizing an existing allocation ...
size_t getMemoryAlignment() const
Returns possible memory alignment restrictions.
Definition: managedSwap.h:107
virtual void untouch(managedMemoryChunk &chunk)=0
marks chunk as recently not needed any more
global_bytesize getUsedMemory() const
returns current ram usage
uint64_t memoryID
static void versionInfo()
prints out a GIT version info and a diff on this version at compile time
void * swapBuf
a place to store additional swapping information
static pthread_cond_t swappingCond
Class that serves as a backend to managedMemory to actual write/read managedMemoryChunks to/from hard...
Definition: managedSwap.h:35
bool prepareUse(rambrain::managedMemoryChunk &chunk, bool acquireLock=true)
Triggers swapin of chunk.
global_bytesize swap_out_scheduled_bytes
void * schedBuf
a place to store additional scheduling information
virtual global_bytesize getSwapSize() const
Simple getter.
Definition: managedSwap.h:82
global_bytesize memory_tobefreed
global_bytesize n_swap_out
static managedMemory * defaultManager
static memoryID parent
global_bytesize swap_in_bytes_last
memoryID child
first child element if creating a class hierarchy
void claimTobefreed(global_bytesize bytes, bool tobefreed)
account for future availability of bytes
uint64_t global_bytesize
Definition: common.h:65
virtual void close()=0
Close the swap if not already closed.
void resetSwapstats()
reset statistic about the number, size and efficiency of swapping actions
virtual void schedulerRegister(managedMemoryChunk &chunk)=0
gives scheduler code the opportunity to register its own datastructures associated with a chunk ...
static const memoryID root
memoryID next
next element
virtual global_bytesize getFreeSwap() const
Simple getter.
Definition: managedSwap.h:90
const unsigned char gitCommit[]
Definition: git_info.h:1
const unsigned char gitDiff[]
Definition: git_info.h:5
global_bytesize n_swap_in
global_bytesize swap_in_scheduled_bytes
void mfree(rambrain::memoryID id, bool inCleanup=false)
this function unregisters and deallocates a chunk
global_bytesize swap_hits
Main class for handling configuration throughout the library and for the user.
managedMemory * previousManager
static pthread_mutex_t stateChangeMutex
global_bytesize getFreeSwapMemory() const
return current swap free capacity
void linearMfree()
linearly deletes all objects in memory
rambrainConfig config
You will find the object in managedMemory.cpp as we have to define it in some 'used' file in the link...
bool ensureEnoughSpace(global_bytesize sizereq, managedMemoryChunk *orIsSwappedin=NULL)
This function ensures that there is sizereq space left in ram.
manages all managed Chunks of raw memory
void closeSwap()
powers down the swap class, ergo a cleanup
managedMemoryChunk * mmalloc(global_bytesize sizereq)
allocates and registers a new raw memory chunk of size sizereq to be filled in by managedPtr ...
global_bytesize memory_used
virtual bool touch(managedMemoryChunk &chunk)=0
marks chunk as recently active as a hint for scheduling
void waitForAIO()
wait for some asynchronous action to occur
void waitForCleanExit()
Function waits for all asynchronous IO to complete. The wait is implemented non-performant as a norma...
Definition: managedSwap.cpp:46
std::map< memoryID, managedMemoryChunk * > memChunks
virtual bool cleanupCachedElements(rambrain::global_bytesize minimum_size=0)
throws out cached elements still in ram but also resident on disk. This makes space in situations of ...
Definition: managedSwap.h:137
The element/size requested does not fit in RAM as a whole.
void printSwapstats() const
print statistic about the number, size and efficiency of swapping actions
void claimUsageof(global_bytesize bytes, bool rambytes, bool used)
account for memory usage change
We lack reasonable candidates for swapout (too much elements in use?)
global_bytesize swap_in_bytes
static void startTimer(long seconds, long nanoseconds)
Start the timer.
Definition: timer.cpp:36
memoryID parent
parent element if created in class hierarchy
bool waitForSwapin(managedMemoryChunk &chunk, bool keepSwapLock=false)
Waits until a certain chunk is present.
virtual void schedulerDelete(managedMemoryChunk &chunk)=0
signals deletion of chunk to scheduler code
unsigned int getNumberOfChildren(const memoryID &id)
conveniently returns number of children of the memoryChunk with id id
global_bytesize memory_max
bool setMemoryLimit(global_bytesize size)
dynamically adjusts allowed ram usage
virtual void invalidateCacheFor(managedMemoryChunk &chunk)
tells managedFileSwap that the chunk under consideration might have been changed by user and needs to...
Definition: managedSwap.h:143
global_bytesize memory_swapped
global_bytesize size
Size of actual object in bytes.
static pthread_t creatingThread
static const memoryID invalid
unsigned short useCnt
Number of using adhereTos or a possible location for locking the object to changes.
swapErrorCode
Error codes for swapOut requests.
virtual void swapDelete(managedMemoryChunk *chunk)=0
Mark chunk as deleted.
static pthread_cond_t parentalCond
static pthread_mutex_t parentalMutex
global_bytesize swap_out_bytes
managedMemoryChunk & resolveMemChunk(const memoryID &id)
returns a reference to the memoryChunk indexed by id id
double getHitsOverMisses()
returns current hits over misses rate for accessing elements.
void printTree(managedMemoryChunk *current=NULL, unsigned int nspaces=0)
prints the tree of managed objects for further inspection
global_bytesize swap_out_bytes_last
Backend class to handle raw memory and interaction/storage with managedSwap.
Definition: managedMemory.h:68
bool unsetUse(memoryID id)
Convenience interface for unsetUse ( managedMemoryChunk &chunk, bool writeAccess ) ...
managedMemory(managedSwap *swap, global_bytesize size=gig)
Standard constructor.