t_debug_allocs.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : test_debug_allocs                                                 *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *  Purpose:                                                                   *
00007 *                                                                             *
00008 *    Tests the allocation support that the program is built with, not just in *
00009 *  debug builds.  But this is most useful for a debug build in order to test  *
00010 *  whether the debug heap problems are win32's or someone else's.             *
00011 *                                                                             *
00012 *******************************************************************************
00013 * Copyright (c) 2001-$now By Author.  This program is free software; you can  *
00014 * redistribute it and/or modify it under the terms of the GNU General Public  *
00015 * License as published by the Free Software Foundation; either version 2 of   *
00016 * the License or (at your option) any later version.  This is online at:      *
00017 *     http://www.fsf.org/copyleft/gpl.html                                    *
00018 * Please send any updates to: fred@gruntose.com                               *
00019 \*****************************************************************************/
00020 
00021 #include <basis/chaos.h>
00022 #include <basis/guards.h>
00023 #include <basis/istring.h>
00024 #include <data_struct/amorph.cpp>
00025 #include <mechanisms/ithread.h>
00026 #include <mechanisms/time_stamp.h>
00027 #include <loggers/file_logger.h>
00028 #include <opsystem/path_configuration.h>
00029 #include <data_struct/static_memory_gremlin.h>
00030 
00031 HOOPLE_STARTUP_CODE;
00032 
00033 const int DEFAULT_FISH_LOW = 50;
00034 const int DEFAULT_FISH_HIGH = 200;
00035   // the range of the number of threads used in the test.
00036 
00037 const int DEFAULT_RUN_TIME = 5 * MINUTE_ms;
00038 //const int DEFAULT_RUN_TIME = 20 * MINUTE_ms;
00039 //const int DEFAULT_RUN_TIME = 5 * DAY_ms;
00040   // the length of time to run the program.
00041 
00042 const int SLEEP_LOW = 28;
00043 const int SLEEP_HIGH = 114;
00044   // if the thread chooses to sleep, these are the boundaries for how long.
00045 
00046 const istring LOGFILE_NAME = path_configuration::make_logfile_name
00047     ("t_debug_allocs.log");
00048   // where our debugging output goes by default.
00049 
00050 const int MAX_ALLOCS_PER_THREAD = 30;
00051   // the most allocations that a thread can have at a time.
00052 
00053 const int MAX_ALLOC = 20000;
00054   // the largest allocation we attempt at a time.
00055 
00056 #define LOG(to_print) log.log(timestamp(true) + istring(to_print))
00057   // our macro for logging with a timestamp.
00058 
00059 chaos rando;
00060 
00061 class memory_abuser : public ithread
00062 {
00063 public:
00064   memory_abuser() : ithread(0) {}
00065 
00066   virtual ~memory_abuser() {
00067     for (int i = 0; i < _allocations.length(); i++)
00068       WHACK(_allocations[i]);
00069   }
00070 
00071   enum test_actions {
00072     FIRST_TEST,
00073     ALLOCATE = FIRST_TEST,
00074     DEALLOCATE,
00075     NOTHING,
00076     ALLOC_DEALLOC,
00077     DEALLOC_ALLOC,
00078     LAST_TEST = DEALLOC_ALLOC
00079   };
00080 
00081   void perform_activity(void *formal(data)) {
00082     while (!should_stop()) {
00083       int action = rando.inclusive(FIRST_TEST, LAST_TEST);
00084       switch (action) {
00085          case ALLOCATE: {
00086            if (_allocations.length() > MAX_ALLOCS_PER_THREAD)
00087              break;
00088            int size = rando.inclusive(1, MAX_ALLOC);
00089            byte *alloc = new byte[size];
00090            _allocations += alloc;
00091            break;
00092          }
00093          case DEALLOCATE: {
00094            if (!_allocations.length()) break;
00095            int posn = rando.inclusive(0, _allocations.length() - 1);
00096            WHACK(_allocations[posn]);
00097            _allocations.zap(posn, posn);
00098            break;
00099          }
00100          case NOTHING:
00101            // done!
00102            break;
00103          case ALLOC_DEALLOC: {
00104            int size = rando.inclusive(1, MAX_ALLOC);
00105            byte *alloc = new byte[size];
00106            _allocations += alloc;
00107            int posn = rando.inclusive(0, _allocations.length() - 1);
00108            WHACK(_allocations[posn]);
00109            _allocations.zap(posn, posn);
00110            break;
00111          }
00112          case DEALLOC_ALLOC: {
00113            if (!_allocations.length()) break;
00114            int posn = rando.inclusive(0, _allocations.length() - 1);
00115            WHACK(_allocations[posn]);
00116            _allocations.zap(posn, posn);
00117            int size = rando.inclusive(1, MAX_ALLOC);
00118            byte *alloc = new byte[size];
00119            _allocations += alloc;
00120            break;
00121          }
00122 //add other tests.
00123       }
00124       int might_sleep = rando.inclusive(1, 100);
00125       // sometimes we will sleep.
00126       if (might_sleep >= 98) {
00127         int sleepy = rando.inclusive(SLEEP_LOW, SLEEP_HIGH);
00128         portable::sleep_ms(sleepy);
00129       }
00130     }
00131   }
00132 
00133 private:
00134   array<byte *> _allocations;
00135 };
00136 
00137 #define static_class_name() "t_debug_alloc"
00138 
00139 #ifdef __WIN32__
00140 int WINAPI WinMain(application_instance instance,
00141     application_instance prev_instance, LPSTR lpCmdLine, int nCmdShow)
00142 #else
00143 int main(int formal(argc), char *formal(argv)[])
00144 #endif
00145 {
00146   FUNCDEF("main");
00147   file_logger log(LOGFILE_NAME);
00148 
00149   amorph<ithread> thread_list;
00150 
00151   int fishies = rando.inclusive(DEFAULT_FISH_LOW, DEFAULT_FISH_HIGH);
00152   LOG(istring(istring::SPRINTF, "using %d fish in test.", fishies));
00153 
00154   for (int i = 0; i < fishies; i++) {
00155     ithread *t = new memory_abuser;
00156     thread_list.append(t);
00157     ithread *q = thread_list[thread_list.elements() - 1];
00158     if (q != t)
00159       deadly_error(static_class_name(), func, "amorph has incorrect pointer!");
00160     // start the thread we added.
00161     thread_list[thread_list.elements() - 1]->start(NIL);
00162   }
00163 
00164   time_stamp when_to_leave(DEFAULT_RUN_TIME);
00165   while (when_to_leave > time_stamp())
00166     portable::sleep_ms(rando.inclusive(12, 200));
00167 
00168   LOG("now exiting from all threads....");
00169 
00170   // stop all the threads.  if we just reset the amorph, bad things happen,
00171   // possibly because a destructor can't manage threads in this way?  or
00172   // because the thread is using a mutex inside a destructor???
00173   for (int j = 0; j < thread_list.elements(); j++) thread_list[j]->stop();
00174 
00175   thread_list.reset();  // should whack all threads.
00176 
00177   LOG("done exiting from all threads....");
00178 
00179   guards::alert_message("OS allocations:: works for all functions tested.");
00180   return 0;
00181 }
00182 
00183 #undef static_class_name
00184 

Generated on Fri Nov 21 04:30:09 2008 for HOOPLE Libraries by  doxygen 1.5.1