From b77f260a2c4ae1fb806db90a54d02892d4e2c754 Mon Sep 17 00:00:00 2001 From: Andrew Haynes Date: Fri, 17 Apr 2026 14:15:24 -0400 Subject: [PATCH] a much more simplified version of push_back with reallocf instead of memcpy as it is faster (no copying just resizing the vector (entire point of vector)) --- src/main.c | 31 ++---- tests/crash_9b_test | Bin 0 -> 33888 bytes tests/crash_9b_test.c | 107 ++++++++++++++++++++ tests/crash_memory_test | Bin 0 -> 33888 bytes tests/crash_memory_test.c | 198 ++++++++++++++++++++++++++++++++++++++ tests/leak_check | Bin 0 -> 33880 bytes tests/leak_check.c | 108 +++++++++++++++++++++ tests/stress_full_test | Bin 0 -> 33936 bytes tests/stress_full_test.c | 181 ++++++++++++++++++++++++++++++++++ 9 files changed, 601 insertions(+), 24 deletions(-) create mode 100755 tests/crash_9b_test create mode 100644 tests/crash_9b_test.c create mode 100755 tests/crash_memory_test create mode 100644 tests/crash_memory_test.c create mode 100755 tests/leak_check create mode 100644 tests/leak_check.c create mode 100755 tests/stress_full_test create mode 100644 tests/stress_full_test.c diff --git a/src/main.c b/src/main.c index 1fca08b..565669d 100644 --- a/src/main.c +++ b/src/main.c @@ -57,10 +57,6 @@ create(const Vec8_t* input) { vec.size = input->size + 1; } - if (input->capacity >= vec.capacity) - { - vec.capacity = 2 * input->capacity; - } vec.arr = calloc(vec.capacity, sizeof(char)); return vec; } @@ -149,30 +145,17 @@ back(const Vec8_t* vec) Vec8_t add_back(Vec8_t* vec, const char val) { - Vec8_t ret = { .arr = nullptr, .capacity = 0, .size = 0 }; - if (vec->size < vec->capacity) - { - vec->arr[vec->size] = val; - vec->size++; - return *vec; - } - if (vec->size >= vec->capacity) { - Vec8_t nvec = create(vec); - if(nvec.arr == nullptr) { - printf("Malloc failed and returned nullptr: Returning old vector"); + vec->capacity *= 2; + char* nvec = reallocf(vec->arr, vec->capacity * sizeof(char)); + if(nvec == NULL) { return *vec; } - memcpy(&nvec.arr[0], &vec->arr[0], vec->size * sizeof(char)); - if (nvec.arr && (nvec.size > 0 || nvec.size > vec->size)) - { - nvec.arr[vec->size] = val; - } - free(vec->arr); - return nvec; - } - return ret; + } + vec->arr[vec->size] = val; + vec->size++; + return *vec; } int diff --git a/tests/crash_9b_test b/tests/crash_9b_test new file mode 100755 index 0000000000000000000000000000000000000000..fe8ae2a029820c6b3a5b28aa016c3b78e2ad25d7 GIT binary patch literal 33888 zcmeI5e{56N701uBo!}TKE(Ah>kr!H4+A&Bw{-9m6*>O^WN=RgTCF{^`9LGsq@@uiP z5zHDFR+M$xl&3{gg{l@!RX0ajl}<$)LR8t1rfr=x(N45lr7o<~){OR#Zj>fbjQ2h7 zy%5`!_K)_zog**fv{~?tp*pRt%`M3Dv=y)OI&X%jyJK)ipLCC*v^mVw&Q`JDN05AdJ{_t7RQ^l z<2Bpw_U}1JNit!a6NXF zS@HVqAZ!=Mu)EBH*Yzo=Qg!~YUj>@>hpg50S#b!ZDMcmEnU&Yd3stJKZ;9H?g)DeSrM;(!G43y(u#e;!hL4HX%X$h2+ohkO``acZBN2x zM$BeCblc-ZD^XS-BN|1y9NG-cm&F{hZ?gt}9tFqOF)!YlciA@cV)-1D z`=`L|l$9hm-&C$Ny`0IWv`jWY#($meal{;TU#c`no2qGbq-)$|zPT0lM5gD((`wK`}noAPI_H2wDHQ%-fUFfNS~`Q}Ze(iDO^fY2kBW4=$MoN8i zYrD4X=92RpL4Ik6HHQ(8HHU1f7WeRHt{ymV=9qJ87qTg5CVQTY1}z|GQ@Xd4rSo! zFaUj&9=P4Wdtq!nrC-Hv8GR(68*5M|wp1A#SEYk%Q9u3676bdO{E8yX6Jy+4423af zP8CHtMUhj;%87lZ1GNkEM&vQ~zyI~Brgc6;?#O1=X(wf;oomM%*~htVya8opCB5HT zLg53c!?Wv`kui(=O*_|&*P(B5Ex(NVRdC;ge9NJ^QhI;x#Iq+Wu-16a%DL~&M|bTW zD<$J;#Q3Un(`Da$F8r*c;&LFD3x7C2{2JfylCxqQ&-z&UTJH2k=z`Yn0&)p_-GdG!re9kFi|m(}!+`C`B`d8cKcI$=GOzS>o0 zL;5FASsj-?u-*`VJc%VB^3>GS=;8WMSl`-yzrOXzpdRav^~8FU2^~Ei3IzS3hWa`^ zk}T+~@=)k&fk1sIR5)n69*y)zqVePqyL+fH*3&mI1fL!EcIb_@9(pj|8|l`2ikmr$ z=3vvFAR_L4xZcd@e*K<@^e=uzzo*(R?6T2nw2Nx1thLfLr{mwZ&kPXKoBg2>l1Fr& zD-*%`nUY`fdy#){_)xO)Zv_^gd0o0N;uYjV3=8@QLN4I7`hZ4G#CD;dJ6zaD_Npw6 zm6{L`0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{As_^VfDjM@LO=)z0U;m+ zgn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnVOl5%8w1ul&6DG?m4hwmt*& zrmYXqylLxWKX2Op#yV}f$wdeV0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf z5D)@FKnMr{As_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf z5D)@FKnMr{As_^VfDri12vh!94btkdLr>&s=|4`Wi8c7pLM%c znwRfv@>z#+6+rDaPeCWrZJW>kWqvp_+U&>K-lkn`+Y`23YukLzI{V|iYc9EJ3a}N} z4;R^;MK;dtF7O{LvWJUo{vQWkYn(4l9w?tz&u6?Zw!2X;?n4vlq&@;kzG03co&`^2NuI&?vxJnw?J7itz%QV!lZE@ax}G+PvJ~r{U zmER7}?;L&6)A%EG>zl8{Q!DN~{hLo4|C7eoE&qn&Pv^e--iI$9TY0wZ_g!bo|MJ#P TN1K0qaev1*&whP$)`IpwD}e;& literal 0 HcmV?d00001 diff --git a/tests/crash_9b_test.c b/tests/crash_9b_test.c new file mode 100644 index 0000000..943eab4 --- /dev/null +++ b/tests/crash_9b_test.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include + +typedef struct +{ + char* arr; + size_t size; + size_t capacity; +} Vec8_t; + +#define CAPACITY 1024 + +Vec8_t +create(const Vec8_t* input) +{ + Vec8_t vec = { .arr = NULL, .size = 0, .capacity = CAPACITY }; + if (input == NULL) + { + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; + } + if (input->size > 0) + { + vec.size = input->size + 1; + } + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; +} + +void +delete(Vec8_t* vec) +{ + if (vec->arr != NULL) + { + free(vec->arr); + vec->arr = NULL; + } + vec->size = 0; + vec->capacity = 0; +} + +Vec8_t +add_back(Vec8_t* vec, const char val) +{ + if (vec->size >= vec->capacity) + { + vec->capacity = 2 * vec->capacity; + char* new_arr = + reallocf(vec->arr, vec->capacity * sizeof(char)); + if (new_arr == NULL) + { + return *vec; + } + vec->arr = new_arr; + } + vec->arr[vec->size] = val; + vec->size++; + return *vec; +} + +vm_size_t +get_physical_mem() +{ + struct task_basic_info info; + mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT; + task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, + &count); + return info.resident_size; +} + +int +main() +{ + printf("=== PROGRESSIVE TEST: 1K -> 10K -> 100K -> 1M -> 10M -> 100M -> 1B ===\n\n"); + + size_t targets[] = {1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; + int num_tests = 7; + + for (int t = 0; t < num_tests; t++) { + size_t target = targets[t]; + printf("\n=== TEST %d: %zu elements ===\n", t+1, target); + + Vec8_t vec = create(NULL); + size_t start_cap = vec.capacity; + + for (size_t i = 0; i < target; i++) { + vec = add_back(&vec, 'x'); + + if (vec.arr == NULL) { + printf("CRASHED at %zu elements!\n", i); + return 1; + } + } + + printf("SUCCESS: %zu elements, capacity %zu\n", vec.size, vec.capacity); + printf("Memory: %.2f MB\n", get_physical_mem() / 1024.0 / 1024.0); + + delete(&vec); + } + + printf("\n=== ALL TESTS PASSED ===\n"); + printf("Final memory: %.2f MB\n", get_physical_mem() / 1024.0 / 1024.0); + + return 0; +} \ No newline at end of file diff --git a/tests/crash_memory_test b/tests/crash_memory_test new file mode 100755 index 0000000000000000000000000000000000000000..63332b9a9c44a1fc1e64a70496c0c7aecf74a4ec GIT binary patch literal 33888 zcmeI5e{fXQ702)HCgf!Wjj)gasXP^ID98_q76X9|o2?*$#Lc3Bj4zwyC0R%|X?7z7 z&@3t)@WsNp8MWQHX+vO zw14!EduQ&xd+v{O&;6Y9?%S71azE(%{>QP5Ss0QP`AX!P1jcqU870OhBQHl*l!BaF z-0R(*e5xIu_~7AHmq?`N6LeG*uY0X`crzdG9A3u^IT6)nrXGqCQn!Stq^FVkT3|cr zdn;LQCz;kYm=aicu#AGD1VeSj!NIDL`a+lM`iKD~lH>JBhCVRlNl{9w1HmB!N9t=e z^rad7Nwyi~(Js&z4AuGrd;&CPx9+tWJSr%@#ZM5{MCiJcb!I1;mXs9E3KI_&6R?zDCN~d)P7pu zJoM$sIh@-VR8lt6P~7INSiRDnyF#~$k@tti8)QmFh!aZG#@o5XSSCi0eKd~NxxkS3 zLf!?L*pM&h?O<#iUGLNDFGINiIX)#ppd4>!d^;~=yctXJZRA!NncC*o1#9P4`itk5 z)>oE7rZg3q?C5!D<_j;5&1`w7pxU|Nx}_i9fI1mjU(*!E5~lDnk2$F;;a6zm>%)~& z2G&P<_Kz@<=3R(PZF)T9;kL94*#dhC>w_V+YR))0W>CS)iV5?2} zX!v|A%9u0egia6oHjL=oSN@ksuVRUuzr%|0HrSaE>9<+5ZX1h|trMG_k)u|rW0{3{ zcUhe=i~q)jyZ-2mkbS#gpC5LFt@=9BVOz{*i5|7G&fcWQ_9es42Vo=GfBXF1``T=i zqGa>+umjuEg62aYV9^%9|8;g zRz%RI_i-g1KYQ(@svoLTVNV+Dnhg7y4g*EcB!>V0Cx&2xj zx3L4|w#`E}O5DZ@ZX=JKmlkPf;%xoe)Z?{kRL;aYDOQN}3COhmS5H5ABJ1InuBDm6?>$Oj!??Pm3DUP%xrtME+o#900ea1Su17YsnvN3aE z;~1t*Li;oDZ%H}LJz?JJ>Y||b= z*|cj1wHtmi?c)AP%;x@aAeI`77ikpB+f5x?Y#No*zI?#LkS(^b#}By&J{nxp!fdSu zb>=+fD33bNQ~ErlzZ89vS@=W~e8FwFTHjyVlET?NsVs)A(b0ICMS2b_i_FBmyA+I@ z;a>^!pPkBLi`Pg^X3V$^dnQAl133)VZAq=!;rqjjpMZXRO>rDC;^92}_c+>bM$GiU zk4tT79j!kMAZ}7SzWR}_tg{cXa;C50{voH_)ap2H-x<8?Z;$$xB z)+0_n<#94GIs@_r^zXJ!iGBkgn@p}jy~$+ceazSYsm_M`68CdD`X3zQj19)X*dbPGQCh+nETJOBaJR#OxOZ&~yjSG5%#Y}6kIy#zh4>WHK_7)8c9Kt@`7=ta24|JV;I%G+Ip3olgjy_*>BF3cM6ZSlgIvUf2 zefVYE^F7dsJ)u*!G4E09qz>1>0Isa_9QOFP;n&mf>jv)Ebne%~&^L7d>wEhV)D^<7 z7mdCBMabuE>F{f6^bA;@14Hs}2z@A?51>8c#GVrs%7HHF{ZG53+xogP8l)!a%C~>N zd-8oJ&aQo>EBTe^zi7f(lfTI*X7b#=RC^Nbuf@gEp1A%LOPBcT zl+MxJBhd$Ze?hG%+e zRI#OZ6yY8iilg1*1E zuuO}F2L|R2d-}I+!1MV|Jg3*=dA$zL?X{5~s_%%Lz4rF10ap@#uFu20nu6~t%sTBO zUdCQBSjP8}!SdyCI*A&WhEt>ROe_ z@{Fx@vRbKDsew>jx4NKOYG-zrC#P_^J6HCFhV`?vDz&P*wqB-ggSzd^R~Axh_=j!vyCG{nh>adyg8myHUNarOs4|Va?@JX*78Xaqh^9Q*=X?ylPFJcSS*-TfW`x^5%OA^1rm+yj&9(SS9p%8j2RnjcOca@dZB{JUZ z)gZaewA-L*7>=U9b9bB+01A0h7;A=7#EIOCTk zBioVb+ri?;c8KkWkv=xK4G74>l)7JfM(*94w119p+_r=&&5P2Gc$;g2^ zioyq(6;7~nmu*Blp`?VR-q$Ky`7-sIfBTvImeFh}sr3abC|q$2s1j0xA+{&8zT>I( zaXX}$r##P|%l$n6&9Z4L{Z&sCz5GHnowdJLe=hy~uL5K4-}-XrtMjT)?SAY`@~g)R zt*4GH`9pd4*Z02lr-tYMytew-*|OGzkB=YUWX)fjII#WD_N_ZVd;Ov1yJsKxx%PY2 zYaVoe;qae16Z2lYC1cei-~8_Gm%h00+~;4Pdw9ZaP2d0A`2V*3@VGa3HvGME)`nls eKYHx>(%G-2Py6=xuTOrSP`YHr^zRBzGxjgBAOyq! literal 0 HcmV?d00001 diff --git a/tests/crash_memory_test.c b/tests/crash_memory_test.c new file mode 100644 index 0000000..9718b06 --- /dev/null +++ b/tests/crash_memory_test.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include + +typedef struct { + char* arr; + size_t size; + size_t capacity; +} Vec8_t; + +Vec8_t create(const Vec8_t* input) { + Vec8_t vec = { .arr = NULL, .size = 0, .capacity = 4 }; + if (input == NULL) { + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; + } + if (input->size > 0) { + vec.size = input->size + 1; + } + if (input->capacity >= vec.capacity) { + vec.capacity = 2 * input->capacity; + } + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; +} + +void delete(Vec8_t* vec) { + if (vec->arr != NULL) { + free(vec->arr); + } + vec->arr = NULL; +} + +Vec8_t add_back(Vec8_t* vec, const char val) { + if (vec->size < vec->capacity) { + vec->arr[vec->size] = val; + vec->size++; + return *vec; + } + if (vec->size >= vec->capacity) { + Vec8_t nvec = create(vec); + if (nvec.arr == NULL) { + return *vec; + } + memcpy(&nvec.arr[0], &vec->arr[0], vec->size * sizeof(char)); + if (nvec.arr && (nvec.size > 0 || nvec.size > vec->size)) { + nvec.arr[vec->size] = val; + } + free(vec->arr); + return nvec; + } + Vec8_t ret = { .arr = NULL, .capacity = 0, .size = 0 }; + return ret; +} + +void print_rusage(const char* label) { + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + printf("%s: %.2f MB maxRSS\n", label, ru.ru_maxrss / 1024.0); +} + +void force_rusage_reset() { + struct rusage start; + getrusage(RUSAGE_SELF, &start); +} + +int main() { + printf("=== MEMORY CRASH + LEAK TEST ===\n\n"); + + printf("Initial memory:\n"); + print_rusage("before"); + + printf("\n=== TEST 1: PUSH UNTIL CRASH ===\n\n"); + + Vec8_t vec = create(NULL); + size_t crashed_at = 0; + + for (size_t i = 0; ; i++) { + vec = add_back(&vec, (char)(i % 256)); + + if (vec.arr == NULL) { + crashed_at = i; + break; + } + + if (i % 50000000 == 0 && i > 0) { + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + printf(" %zu elements: %.2f MB used\n", i, ru.ru_maxrss / 1024.0); + } + + if (i >= 4000000000UL) { + crashed_at = i; + printf(" STOPPED at 4 billion\n"); + break; + } + } + + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + + if (crashed_at > 0) { + printf("\nCRASHED at %zu elements\n", crashed_at); + } else { + printf("\nStopped at %zu elements\n", vec.size); + printf("capacity: %zu\n", vec.capacity); + } + + printf("memory used: %.2f MB\n", ru.ru_maxrss / 1024.0); + + delete(&vec); + + printf("\nAfter delete:\n"); + print_rusage("after delete"); + + printf("\n=== TEST 2: MULTIPLE VECTORS (LEAK CHECK) ===\n\n"); + + size_t num_vectors = 10000; + Vec8_t* vectors = calloc(num_vectors, sizeof(Vec8_t)); + + printf("Creating %zu vectors...\n", num_vectors); + print_rusage("before vectors"); + + for (size_t i = 0; i < num_vectors; i++) { + vectors[i] = create(NULL); + for (size_t j = 0; j < 10000; j++) { + vectors[i] = add_back(&vectors[i], (char)(j % 256)); + } + } + + print_rusage("with vectors"); + printf("Each vector has %zu elements\n", vectors[0].size); + + printf("\nFreeing vectors...\n"); + for (size_t i = 0; i < num_vectors; i++) { + delete(&vectors[i]); + } + free(vectors); + + print_rusage("after free"); + + printf("\n=== TEST 3: CREATE/DELETE CYCLES ===\n\n"); + + size_t cycles = 100000; + printf("Running %zu create/delete cycles...\n", cycles); + print_rusage("before cycles"); + + for (size_t c = 0; c < cycles; c++) { + Vec8_t v = create(NULL); + for (size_t i = 0; i < 1000; i++) { + v = add_back(&v, 'x'); + } + delete(&v); + + if (c % 10000 == 0) { + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + printf(" cycle %zu: %.2f MB\n", c, ru.ru_maxrss / 1024.0); + } + } + + print_rusage("after cycles"); + + printf("\n=== TEST 4: REALLOC STRESS ===\n\n"); + + Vec8_t big = create(NULL); + printf("Single vec realloc stress...\n"); + + size_t prev_cap = 0; + for (size_t i = 0; i < 100000000; i++) { + big = add_back(&big, 'x'); + + if (big.capacity != prev_cap) { + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + printf(" cap %zu -> %.2f MB\n", big.capacity, ru.ru_maxrss / 1024.0); + prev_cap = big.capacity; + } + } + + print_rusage("final big vec"); + printf("size: %zu, capacity: %zu\n", big.size, big.capacity); + + delete(&big); + + printf("\nAfter cleanup:\n"); + print_rusage("cleanup done"); + + printf("\n=== RESULT ===\n"); + + struct rusage final; + getrusage(RUSAGE_SELF, &final); + printf("Peak memory: %.2f MB\n", final.ru_maxrss / 1024.0); + + return 0; +} \ No newline at end of file diff --git a/tests/leak_check b/tests/leak_check new file mode 100755 index 0000000000000000000000000000000000000000..501fdae8fded733e455de8ad9585e650e649ce05 GIT binary patch literal 33880 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 literal 0 HcmV?d00001 diff --git a/tests/leak_check.c b/tests/leak_check.c new file mode 100644 index 0000000..90e508f --- /dev/null +++ b/tests/leak_check.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include + +typedef struct { + char* arr; + size_t size; + size_t capacity; +} Vec8_t; + +Vec8_t create(const Vec8_t* input) { + Vec8_t vec = { .arr = NULL, .size = 0, .capacity = 4 }; + if (input == NULL) { + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; + } + if (input->size > 0) { + vec.size = input->size + 1; + } + if (input->capacity >= vec.capacity) { + vec.capacity = 2 * input->capacity; + } + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; +} + +void delete(Vec8_t* vec) { + if (vec->arr != NULL) { + free(vec->arr); + vec->arr = NULL; + } + vec->size = 0; + vec->capacity = 0; +} + +Vec8_t add_back(Vec8_t* vec, const char val) { + if (vec->size < vec->capacity) { + vec->arr[vec->size] = val; + vec->size++; + return *vec; + } + if (vec->size >= vec->capacity) { + Vec8_t nvec = create(vec); + if (nvec.arr == NULL) { + return *vec; + } + memcpy(&nvec.arr[0], &vec->arr[0], vec->size * sizeof(char)); + if (nvec.arr && (nvec.size > 0 || nvec.size > vec->size)) { + nvec.arr[vec->size] = val; + } + free(vec->arr); + return nvec; + } + Vec8_t ret = { .arr = NULL, .capacity = 0, .size = 0 }; + return ret; +} + +vm_size_t get_physical_mem() { + struct task_basic_info info; + mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT; + task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count); + return info.resident_size; +} + +int main() { + printf("=== PHYSICAL MEMORY LEAK TEST ===\n\n"); + + printf("Initial physical: %.2f MB\n", get_physical_mem() / 1024.0 / 1024.0); + + printf("\n--- Creating large vector ---\n"); + Vec8_t big = create(NULL); + + printf("Adding elements...\n"); + for (size_t i = 0; i < 100000000; i++) { + big = add_back(&big, 'x'); + if (i % 10000000 == 0) { + printf(" %zu elements: %.2f MB\n", i+1, get_physical_mem() / 1024.0 / 1024.0); + } + } + + printf(" Final: %zu elements, %.2f MB\n", big.size, get_physical_mem() / 1024.0 / 1024.0); + + printf("\n--- BEFORE delete: %.2f MB ---\n", get_physical_mem() / 1024.0 / 1024.0); + + delete(&big); + + printf("--- AFTER delete: %.2f MB ---\n", get_physical_mem() / 1024.0 / 1024.0); + + printf("\n--- Create 1000 vectors then delete ---\n"); + printf("Before: %.2f MB\n", get_physical_mem() / 1024.0 / 1024.0); + + for (int c = 0; c < 1000; c++) { + Vec8_t v = create(NULL); + for (int i = 0; i < 100000; i++) { + v = add_back(&v, 'x'); + } + delete(&v); + } + + printf("After cycles: %.2f MB\n", get_physical_mem() / 1024.0 / 1024.0); + + printf("\n--- RESULT ---\n"); + printf("Physical memory used: %.2f MB\n", get_physical_mem() / 1024.0 / 1024.0); + + return 0; +} \ No newline at end of file diff --git a/tests/stress_full_test b/tests/stress_full_test new file mode 100755 index 0000000000000000000000000000000000000000..2f69d4aa6c15db25337a93f72984c4458905a98d GIT binary patch literal 33936 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 z +#include +#include +#include +#include + +typedef struct { + char* arr; + size_t size; + size_t capacity; +} Vec8_t; + +Vec8_t create(const Vec8_t* input) { + Vec8_t vec = { .arr = NULL, .size = 0, .capacity = 4 }; + if (input == NULL) { + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; + } + if (input->size > 0) { + vec.size = input->size + 1; + } + if (input->capacity >= vec.capacity) { + vec.capacity = 2 * input->capacity; + } + vec.arr = calloc(vec.capacity, sizeof(char)); + return vec; +} + +void delete(Vec8_t* vec) { + if (vec->arr != NULL) { + free(vec->arr); + } + vec->arr = NULL; +} + +Vec8_t add_back(Vec8_t* vec, const char val) { + Vec8_t ret = { .arr = NULL, .capacity = 0, .size = 0 }; + if (vec->size < vec->capacity) { + vec->arr[vec->size] = val; + vec->size++; + return *vec; + } + if (vec->size >= vec->capacity) { + Vec8_t nvec = create(vec); + if (nvec.arr == NULL) { + return *vec; + } + memcpy(&nvec.arr[0], &vec->arr[0], vec->size * sizeof(char)); + if (nvec.arr && (nvec.size > 0 || nvec.size > vec->size)) { + nvec.arr[vec->size] = val; + } + free(vec->arr); + return nvec; + } + return ret; +} + +double time_diff(struct timespec start, struct timespec end_t) { + return (end_t.tv_sec - start.tv_sec) + (end_t.tv_nsec - start.tv_nsec) / 1e9; +} + +void get_memory_usage(size_t* used, size_t* peak) { + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + *used = ru.ru_maxrss * 1024; + *peak = ru.ru_maxrss * 1024; +} + +int main() { + printf("=== FULL STRESS TEST: add_back only ===\n\n"); + + struct timespec start, end_t; + Vec8_t vec; + size_t max_elements = 0; + int crashed = 0; + + printf("=== TEST 1: MAX ELEMENTS BEFORE CRASH ===\n\n"); + + vec = create(NULL); + clock_gettime(CLOCK_MONOTONIC, &start); + + for (size_t i = 0; i < SIZE_MAX; i++) { + vec = add_back(&vec, (char)(i % 256)); + + if (vec.arr == NULL) { + max_elements = i; + crashed = 1; + break; + } + + if (i % 100000000 == 0) { + printf(" %zu elements: capacity %zu (%.2f GB)\n", + i + 1, vec.capacity, (double)(vec.capacity * sizeof(char)) / 1024 / 1024 / 1024); + } + + if (i >= 1000000000) { + printf(" stopping at 1 billion elements\n"); + max_elements = 1000000000; + break; + } + } + clock_gettime(CLOCK_MONOTONIC, &end_t); + + if (!crashed && vec.arr != NULL) { + max_elements = vec.size; + } + + printf("\nRESULT: %zu elements\n", max_elements); + printf("capacity: %zu\n", vec.capacity); + printf("memory: %.2f GB\n", (double)(vec.capacity * sizeof(char)) / 1024 / 1024 / 1024); + printf("time: %.2f sec\n", time_diff(start, end_t)); + + delete(&vec); + + printf("\n=== TEST 2: DIRECT MALLOCATION LIMIT ===\n\n"); + + const size_t test_sizes[] = {1000000, 10000000, 100000000, 500000000, 1000000000}; + int num_tests = 5; + + for (int t = 0; t < num_tests; t++) { + size_t n = test_sizes[t]; + printf("Testing %zu elements (%.2f GB)...\n", + n, (double)(n * sizeof(char)) / 1024 / 1024 / 1024); + + char* test_arr = calloc(n, sizeof(char)); + if (test_arr == NULL) { + printf(" FAILED at %zu\n", n); + break; + } + printf(" SUCCESS\n"); + free(test_arr); + } + + printf("\n=== TEST 3: SINGLE VECTOR ALLOCATION ===\n\n"); + + size_t single_max = 0; + for (size_t n = 1000000; n <= 5000000000UL; n *= 2) { + printf("Trying %.2f GB allocation...\n", (double)(n * sizeof(char)) / 1024 / 1024 / 1024); + + Vec8_t test_vec = create(NULL); + Vec8_t* vp = calloc(1, sizeof(Vec8_t)); + + vp->arr = calloc(n, sizeof(char)); + if (vp->arr == NULL) { + printf(" FAILED at %.2f GB\n", (double)(n * sizeof(char)) / 1024 / 1024 / 1024); + single_max = n / 2; + free(vp); + break; + } + + printf(" SUCCESS: %.2f GB\n", (double)(n * sizeof(char)) / 1024 / 1024 / 1024); + free(vp->arr); + free(vp); + delete(&test_vec); + single_max = n; + } + + printf("\n=== TEST 4: SPEED AT SCALE ===\n\n"); + + vec = create(NULL); + clock_gettime(CLOCK_MONOTONIC, &start); + for (size_t i = 0; i < 10000000; i++) { + vec = add_back(&vec, (char)(i % 256)); + } + clock_gettime(CLOCK_MONOTONIC, &end_t); + double t10m = time_diff(start, end_t); + + printf("10M elements:\n"); + printf(" time: %.2f sec\n", t10m); + printf(" rate: %.0f/sec\n", 10000000.0 / t10m); + printf(" memory: %.2f MB\n", (vec.capacity * sizeof(char)) / 1024.0 / 1024.0); + + delete(&vec); + + printf("\n=== SUMMARY ===\n\n"); + printf("Max elements (vector): %zu\n", max_elements); + printf("Single allocation max: %zu (%.2f GB)\n", + single_max, (double)(single_max * sizeof(char)) / 1024 / 1024 / 1024); + + return 0; +} \ No newline at end of file