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))
This commit is contained in:
+7
-24
@@ -57,10 +57,6 @@ create(const Vec8_t* input)
|
|||||||
{
|
{
|
||||||
vec.size = input->size + 1;
|
vec.size = input->size + 1;
|
||||||
}
|
}
|
||||||
if (input->capacity >= vec.capacity)
|
|
||||||
{
|
|
||||||
vec.capacity = 2 * input->capacity;
|
|
||||||
}
|
|
||||||
vec.arr = calloc(vec.capacity, sizeof(char));
|
vec.arr = calloc(vec.capacity, sizeof(char));
|
||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
@@ -149,30 +145,17 @@ back(const Vec8_t* vec)
|
|||||||
Vec8_t
|
Vec8_t
|
||||||
add_back(Vec8_t* vec, const char val)
|
add_back(Vec8_t* vec, const char val)
|
||||||
{
|
{
|
||||||
Vec8_t ret = { .arr = nullptr, .capacity = 0, .size = 0 };
|
if (vec->size >= vec->capacity)
|
||||||
if (vec->size < vec->capacity)
|
|
||||||
{
|
{
|
||||||
|
vec->capacity *= 2;
|
||||||
|
char* nvec = reallocf(vec->arr, vec->capacity * sizeof(char));
|
||||||
|
if(nvec == NULL) {
|
||||||
|
return *vec;
|
||||||
|
}
|
||||||
|
}
|
||||||
vec->arr[vec->size] = val;
|
vec->arr[vec->size] = val;
|
||||||
vec->size++;
|
vec->size++;
|
||||||
return *vec;
|
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");
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,107 @@
|
|||||||
|
#include <mach/mach.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,198 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,108 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <mach/mach.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,181 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user