00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <basis/array.cpp>
00019 #include <basis/byte_array.h>
00020 #include <basis/chaos.h>
00021 #include <basis/function.h>
00022 #include <basis/guards.h>
00023 #include <basis/istring.h>
00024 #include <mechanisms/time_stamp.h>
00025 #include <opsystem/application_shell.h>
00026 #include <loggers/file_logger.h>
00027 #include <data_struct/static_memory_gremlin.h>
00028 #include <textual/string_manipulation.h>
00029
00030 #define LOG(s) EMERGENCY_LOG(program_wide_logger(), s)
00031
00032
00033
00034
00035
00036 const int MAX_TEST_CYCLES = 1000;
00037
00038 const int MAX_SIMULTANEOUS_OBJECTS = 100;
00039 const int MIN_BLOCK = -20;
00040 const int MAX_BLOCK = 100;
00041 const int MIN_OBJECT = 10;
00042 const int MAX_OBJECT = 1200 - MAX_BLOCK;
00043
00044
00045 class test_object_allocator;
00046
00047 test_object_allocator *_rooty = NIL;
00048
00049 class test_object_allocator : public application_shell
00050 {
00051 public:
00052 test_object_allocator() : application_shell(class_name()) { _rooty = this; }
00053
00054 IMPLEMENT_CLASS_NAME("test_object_allocator");
00055
00056 virtual int execute();
00057 };
00058
00059 HOOPLE_MAIN(test_object_allocator, )
00060
00061 test_object_allocator &root_object() { return *_rooty; }
00062
00064
00065 class floopo
00066 {
00067 public:
00068 byte _init;
00069 istring _dreck;
00070
00071 floopo(byte init = 0)
00072 : _init(init), _dreck(string_manipulation::make_random_name(1, 10)) {}
00073
00074 bool operator == (const floopo &a) const { return (_init == a._init); }
00075 bool operator != (const floopo &a) const { return (_init != a._init); }
00076
00077 operator byte() const { return _init; }
00078 };
00079
00081
00082 template <class contents>
00083 class bug_finder : public array<contents>, public virtual object_base
00084 {
00085 public:
00086 IMPLEMENT_CLASS_NAME("allocator_bug_finder");
00087
00088 bug_finder(int length, u_short flags)
00089 : array<contents>(length, NIL, flags) {}
00090
00091 bug_finder(const bug_finder ©_from)
00092 : object_base(), array<contents>(copy_from) {}
00093
00094 virtual ~bug_finder() {}
00095
00096 bool operator == (const bug_finder &compare) const {
00097 if (this->length() != compare.length()) return false;
00098 return !memcmp(this->observe(), compare.observe(), this->length());
00099 }
00100 inline bool operator != (const bug_finder &compare) const
00101 { return !this->operator ==(compare); }
00102
00103 bug_finder sub_bug(int start, int end) {
00104 if (end < start)
00105 return bug_finder(0, this->flags());
00106 bounds_return(start, 0, this->length() - 1,
00107 bug_finder(0, this->flags()));
00108 bounds_return(end, 0, this->length() - 1,
00109 bug_finder(0, this->flags()));
00110 bug_finder to_return(end - start + 1, this->flags());
00111 for (int i = start; i <= end; i++)
00112 to_return[i - start] = this->access()[i];
00113 return to_return;
00114 }
00115
00116 bug_finder operator + (const bug_finder &a2) const {
00117 bug_finder to_return(this->length() + a2.length(), this->flags());
00118 for (int j = 0; j < this->length(); j++) to_return[j] = (*this)[j];
00119 for (int i = this->length(); i < to_return.length(); i++)
00120 to_return[i] = a2[i - this->length()];
00121 return to_return;
00122 }
00123
00124 contents &operator [] (int index)
00125 { return *(contents *)&(this->access()[index]); }
00126 const contents &operator [] (int index) const
00127 { return *(contents *)&(this->observe()[index]); }
00128
00129 #define use operator[]
00130 #define get operator[]
00131
00132 void retrain(int new_size, const contents *to_copy)
00133 { array<contents>::retrain(new_size, (contents *)to_copy); }
00134
00135 void test_allocation();
00136 };
00137
00139
00140 template <class contents>
00141 void bug_finder<contents>::test_allocation()
00142 {
00143 int outcome_size = sizeof(outcome);
00144 if (outcome_size != sizeof(int))
00145 deadly_error(class_name(), "outcome size check", "outcomes are larger than ints");
00146
00147
00148 contents *junk_space = new contents[MAX_OBJECT];
00149 for (int i = 0; i < MAX_OBJECT - 1; i++)
00150 junk_space[i] = contents(root_object().randomizer().inclusive('a', 'z'));
00151 junk_space[MAX_OBJECT - 1] = contents('\0');
00152
00153 bug_finder<contents> *testers[MAX_SIMULTANEOUS_OBJECTS];
00154 for (int c = 0; c < MAX_SIMULTANEOUS_OBJECTS; c++) {
00155
00156 testers[c] = new bug_finder<contents>(root_object().randomizer().inclusive(MIN_OBJECT,
00157 MAX_OBJECT), this->flags());
00158 if (this->flags() & byte_array::SIMPLE_COPY) {
00159
00160 memory_assign(testers[c]->access(), junk_space, testers[c]->length());
00161 }
00162 }
00163
00164 enum actions { do_train, do_size, do_assign, do_access,
00165 do_zap, do_resizer, do_observe, do_swap, do_shrink, do_shift };
00166
00167 time_stamp next_dump;
00168
00169 for (int iterations = 0; iterations < MAX_TEST_CYCLES; iterations++) {
00170 #ifdef DUMP_SIZES
00171 if (time_stamp() >= next_dump) {
00172 for (int i = 0; i < MAX_SIMULTANEOUS_OBJECTS; i++) {
00173 printf("%d ", testers[i]->internal_real_length());
00174 }
00175 printf("\n\n");
00176 next_dump = time_stamp(14 * SECOND_ms);
00177 }
00178 #endif
00179 int index = root_object().randomizer().inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
00180 int choice = root_object().randomizer().inclusive(do_train, do_observe);
00181 switch (choice) {
00182 case do_train: {
00183 testers[index]->retrain(root_object().randomizer().inclusive(MIN_OBJECT, MAX_OBJECT),
00184 junk_space);
00185
00186 break;
00187 }
00188 case do_size: {
00189 bug_finder<contents> old_version = *testers[index];
00190 bool at_front = bool(root_object().randomizer().inclusive(0, 1));
00191 int new_size = root_object().randomizer().inclusive(MIN_OBJECT, MAX_OBJECT);
00192 bool smaller = new_size < old_version.length();
00193 int difference = absolute_value(new_size - old_version.length());
00194 testers[index]->resize(new_size,
00195 at_front? common::NEW_AT_BEGINNING : common::NEW_AT_END);
00196 if (!smaller && difference) {
00197
00198
00199
00200 if (at_front) {
00201 if (this->flags() & byte_array::SIMPLE_COPY)
00202 memset(testers[index]->access(), 'Q', difference);
00203 else
00204 for (int i = 0; i < difference; i++)
00205 testers[index]->use(i) = contents('Q');
00206 } else {
00207 if (this->flags() & byte_array::SIMPLE_COPY)
00208 memset(testers[index]->access() + old_version.length(), 'Q',
00209 difference);
00210 else
00211 for (int i = old_version.length();
00212 i < old_version.length() + difference; i++)
00213 testers[index]->use(i) = contents('Q');
00214 }
00215 }
00216
00217 bug_finder<contents> equivalent(0, old_version.flags());
00218 if (at_front) {
00219 if (smaller) {
00220 equivalent = old_version.sub_bug(difference,
00221 old_version.length() - 1);
00222 } else {
00223 bug_finder<contents> blank(difference, old_version.flags());
00224 if (this->flags() & byte_array::SIMPLE_COPY)
00225 memset(blank.access(), 'Q', blank.length());
00226 else
00227 for (int i = 0; i < blank.length(); i++)
00228 blank.use(i) = contents('Q');
00229 equivalent = blank + old_version;
00230 }
00231 } else {
00232 if (smaller) {
00233 equivalent = old_version.sub_bug(0, old_version.length()
00234 - difference - 1);
00235 } else {
00236 bug_finder<contents> blank(difference, old_version.flags());
00237 if (this->flags() & byte_array::SIMPLE_COPY)
00238 memset(blank.access(), 'Q', blank.length());
00239 else
00240 for (int i = 0; i < blank.length(); i++)
00241 blank.use(i) = contents('Q');
00242 equivalent = old_version + blank;
00243 }
00244 }
00245 if (equivalent.length() != testers[index]->length())
00246 deadly_error(class_name(), __WHERE__, "the resized form had "
00247 "erroneous length");
00248 if (this->flags() & byte_array::SIMPLE_COPY) {
00249 if (memcmp(testers[index]->access(), equivalent.observe(),
00250 equivalent.length()))
00251 deadly_error(class_name(), __WHERE__, "the resized form had "
00252 "erroneous contents");
00253 } else {
00254 for (int i = 0; i < equivalent.length(); i++)
00255 if (testers[index]->use(i) != equivalent[i])
00256 deadly_error(class_name(), __WHERE__, "the resized form had "
00257 "erroneous contents");
00258 }
00259 break;
00260 }
00261 case do_assign: {
00262 int to_assign = root_object().randomizer().inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
00263 *testers[index] = *testers[to_assign];
00264 break;
00265 }
00266 case do_access: {
00267 int start = root_object().randomizer().inclusive(0, testers[index]->length());
00268 int end = root_object().randomizer().inclusive(0, testers[index]->length());
00269 flip_increasing(start, end);
00270 for (int i = start; i < end; i++)
00271 testers[index]->access()[i] = contents(root_object().randomizer().inclusive(1, 255));
00272 break;
00273 }
00274 case do_observe: {
00275 int start = root_object().randomizer().inclusive(0, testers[index]->length());
00276 int end = root_object().randomizer().inclusive(0, testers[index]->length());
00277 flip_increasing(start, end);
00278 int total = 0;
00279 for (int i = start; i < end; i++)
00280 total += testers[index]->observe()[i];
00281 if (total < 20) start = total;
00282 break;
00283 }
00284 case do_resizer: {
00285
00286 bug_finder<contents> &arrh = *testers[index];
00287
00288 int i;
00289 for (i = 0; i < arrh.length(); i++)
00290 arrh[i] = contents((i + 23) % 256);
00291
00292 const contents *start = (contents *)arrh.internal_block_start();
00293 int zap_amount = root_object().randomizer().inclusive(1, arrh.length() - 1);
00294
00295 arrh.zap(0, zap_amount - 1);
00296
00297 for (i = 0; i < arrh.length(); i++)
00298 if (arrh[i] != contents((i + 23 + zap_amount) % 256))
00299 deadly_error(class_name(), __WHERE__, "the resized form "
00300 "had different contents");
00301
00302 arrh.resize(arrh.length() + zap_amount, common::NEW_AT_END);
00303
00304 if (start != (contents *)arrh.internal_block_start())
00305 deadly_error(class_name(), __WHERE__, "the resized form had "
00306 "a different start address");
00307
00308
00309
00310 for (i = 0; i < arrh.length() - zap_amount; i++)
00311 if (arrh[i] != contents((i + 23 + zap_amount) % 256))
00312 deadly_error(class_name(), __WHERE__, "the resized form "
00313 "had different contents");
00314
00315 arrh.zap(0, zap_amount - 1);
00316 for (i = 0; i < zap_amount; i++) {
00317 arrh.resize(arrh.length() + 1, common::NEW_AT_END);
00318 if (start != (contents *)arrh.internal_block_start())
00319 deadly_error(class_name(), __WHERE__, "the slowly resized "
00320 "form had a different start address");
00321 }
00322
00323
00324
00325 for (i = 0; i < arrh.length() - 2 * zap_amount; i++)
00326 if (arrh[i] != contents((i + 23 + 2 * zap_amount) % 256))
00327 deadly_error(class_name(), __WHERE__, "the slowly resized "
00328 "form had different contents");
00329
00330
00331
00332
00333
00334 for (i = 0; i < arrh.length(); i++)
00335 arrh[i] = contents((i + 23) % 256);
00336
00337 start = (contents *)arrh.internal_block_start();
00338 zap_amount = root_object().randomizer().inclusive(1, arrh.length() - 1);
00339
00340 arrh.zap(0, zap_amount - 1);
00341
00342 for (i = 0; i < arrh.length(); i++)
00343 if (arrh[i] != contents((i + 23 + zap_amount) % 256))
00344 deadly_error(class_name(), __WHERE__, "the resized form "
00345 "had different contents");
00346
00347 arrh.resize(arrh.length() + zap_amount, common::NEW_AT_BEGINNING);
00348
00349 if (start != (contents *)arrh.internal_block_start())
00350 deadly_error(class_name(), __WHERE__, "the resized form had "
00351 "a different start address");
00352
00353
00354
00355 for (i = zap_amount; i < arrh.length(); i++)
00356 if (arrh[i] != contents((i + 23) % 256))
00357 deadly_error(class_name(), __WHERE__, "the resized form "
00358 "had different contents");
00359
00360 arrh.zap(0, zap_amount - 1);
00361 for (i = 0; i < zap_amount; i++) {
00362 arrh.resize(arrh.length() + 1, common::NEW_AT_BEGINNING);
00363 if (start != (contents *)arrh.internal_block_start())
00364 deadly_error(class_name(), __WHERE__, "the slowly resized "
00365 "form had a different start address");
00366 }
00367
00368
00369
00370 for (i = zap_amount; i < arrh.length(); i++)
00371 if (arrh[i] != contents((i + 23) % 256))
00372 deadly_error(class_name(), __WHERE__, "the slowly resized "
00373 "form had different contents");
00374 }
00375 case do_zap: {
00376 int start;
00377 int end;
00378 bool erroneous = false;
00379 int chose = root_object().randomizer().inclusive(1, 100);
00380 if (chose <= 90) {
00381
00382 start = root_object().randomizer().inclusive(0, testers[index]->length() - 1);
00383 end = root_object().randomizer().inclusive(0, testers[index]->length() - 1);
00384 } else if (chose <= 95) {
00385
00386
00387 start = 0;
00388 end = root_object().randomizer().inclusive(0, testers[index]->length() - 1);
00389 } else {
00390
00391
00392 erroneous = true;
00393 start = root_object().randomizer().inclusive(-2, testers[index]->length() + 3);
00394 end = root_object().randomizer().inclusive(-2, testers[index]->length() + 3);
00395 }
00396 flip_increasing(start, end);
00397 bug_finder<contents> old_version = *testers[index];
00398 testers[index]->zap(start, end);
00399 if (!erroneous) {
00400 bug_finder<contents> old_head = old_version.sub_bug(0, start - 1);
00401 bug_finder<contents> old_tail = old_version.sub_bug(end + 1,
00402 old_version.length() - 1);
00403 bug_finder<contents> equivalent = old_head + old_tail;
00404 if (equivalent.length() != testers[index]->length())
00405 deadly_error(class_name(), __WHERE__, "the zapped form had "
00406 "erroneous length");
00407 if (this->flags() & byte_array::SIMPLE_COPY) {
00408 if (memcmp(testers[index]->access(), equivalent.observe(),
00409 equivalent.length()))
00410 deadly_error(class_name(), __WHERE__, "the zapped form had "
00411 "erroneous contents");
00412 } else {
00413 for (int i = 0; i < equivalent.length(); i++)
00414 if (testers[index]->get(i) != equivalent.get(i))
00415 deadly_error(class_name(), __WHERE__, "the zapped form had "
00416 "erroneous contents");
00417 }
00418 }
00419 break;
00420 }
00421 case do_swap: {
00422 int first = root_object().randomizer().inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
00423 int second = first;
00424 while (first == second)
00425 second = root_object().randomizer().inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
00426 bug_finder<contents> old_first = *testers[first];
00427 bug_finder<contents> old_second = *testers[second];
00428 testers[first]->swap_contents(*testers[second]);
00429 if (*testers[first] != old_second)
00430 deadly_error(class_name(), __WHERE__, "the old second entry was different "
00431 "from the new first");
00432 if (*testers[second] != old_first)
00433 deadly_error(class_name(), __WHERE__, "the old first entry was different "
00434 "from the new second");
00435 break;
00436 }
00437 case do_shrink: {
00438 int shrinker = root_object().randomizer().inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
00439 bug_finder<contents> old = *testers[shrinker];
00440 testers[shrinker]->shrink();
00441 if (old != *testers[shrinker])
00442 deadly_error(class_name(), __WHERE__, "contents were wrong after shrink");
00443 if (testers[shrinker]->internal_real_length() > old.length() + 1)
00444 deadly_error(class_name(), __WHERE__, "size was too large after shrink");
00445 break;
00446 }
00447 case do_shift: {
00448 int shifty = root_object().randomizer().inclusive(0, MAX_SIMULTANEOUS_OBJECTS - 1);
00449 bug_finder<contents> old = *testers[shifty];
00450 testers[shifty]->shift_data(bug_finder<contents>::TO_LEFT);
00451 if (testers[shifty]->internal_offset() != 0)
00452 deadly_error(class_name(), __WHERE__, "offset is wrong after shift to left");
00453 if (*testers[shifty] != old)
00454 deadly_error(class_name(), __WHERE__, "contents wrong after shift to left");
00455 testers[shifty]->shift_data(bug_finder<contents>::TO_RIGHT);
00456 if (testers[shifty]->internal_offset()
00457 != testers[shifty]->internal_real_length()
00458 - testers[shifty]->length())
00459 deadly_error(class_name(), __WHERE__, "offset is wrong after shift to right");
00460 if (*testers[shifty] != old)
00461 deadly_error(class_name(), __WHERE__, "contents wrong after shift to right");
00462 break;
00463 }
00464 default: {
00465 deadly_error(class_name(), "action choice", "invalid choice!");
00466 break;
00467 }
00468 }
00469 }
00470
00471
00472 delete [] junk_space;
00473 for (int d = 0; d < MAX_SIMULTANEOUS_OBJECTS; d++) delete testers[d];
00474 }
00475
00477
00478 int test_object_allocator::execute() {
00479 LOG("doing test on non-simple object.\n");
00480 bug_finder<floopo> complex_tester(0, bug_finder<floopo>::EXPONE
00481 | bug_finder<floopo>::FLUSH_INVISIBLE);
00482 complex_tester.test_allocation();
00483 LOG("finished test on non-simple object.\n");
00484
00485 LOG("doing test on simple object.\n");
00486 bug_finder<char> simple_tester(0, bug_finder<floopo>::SIMPLE_COPY
00487 | bug_finder<floopo>::EXPONE);
00488 simple_tester.test_allocation();
00489 LOG("finished test on simple object.\n");
00490
00491 guards::alert_message("object_allocator:: works for those "
00492 "functions tested.");
00493 return 0;
00494 }
00495
00496