Last active
November 30, 2024 11:06
-
-
Save damian-m-g/736c25fa253c070c551d3d252f108457 to your computer and use it in GitHub Desktop.
Custom Memory Management Library (Course: UNC, FCEFyN, Operative Systems I, Laboratory 3) application. Makes use of the library recurrently, for benchmarking purposes. In comparison with "cmml_app.c", this version ends while the other remains in a loop, being only stopped by a terminating signal.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @file cmml_app_no_loop.c | |
* @brief Main program file. | |
*/ | |
#include "memory.h" | |
//! \brief Lowest array index. | |
#define LOWEST_ARR_INDEX 0 | |
//! \brief Lowest array index. | |
#define BENCHMARK_ITERATIONS 10 | |
//! \brief Amount of allocated blocks per test. | |
#define NUM_OPERATIONS 10000 | |
//! \brief Max amount of block data (in bytes), per block. | |
#define MAX_B_DATA_SIZE 128 | |
//! \brief RNG system fixed seed; the variant is to use `time(NULL)`. | |
#define XORSHIFT_SEED 3370684199 | |
//! \brief Free blocks every next amount of allocated blocks. | |
#define BLOCKS_FREE_EVERY 3 | |
/* PROTOTYPES */ | |
//! \brief Seed setting for an implementation of XorShift PRNG. | |
void xorshift_srand(unsigned int seed); | |
//! \brief Own implementation of XorShift PRNG. | |
unsigned int xorshift_rand(void); | |
//! \brief Test & benchmark for the FIRST_FIT allocation policy. | |
void run_first_fit_policy_batch(void); | |
//! \brief Test & benchmark for the BEST_FIT allocation policy. | |
void run_best_fit_policy_batch(void); | |
//! \brief Test & benchmark for the WORST_FIT allocation policy. | |
void run_worst_fit_policy_batch(void); | |
//! \brief Helper function for benchmarking a policy. | |
void benchmark_policy(int policy); | |
//! \brief Helper function to calculate fragmentation (0~1 * 100 = x%). | |
double calculate_fragmentation(void); | |
//! \brief Cleans the heap. The lone arg shall be an array to pointers pointing to allocated data. | |
void destroy_memory(void** allocated_data); | |
/* Global vars */ | |
static unsigned int xor_state; // Seed | |
/* Helper functions definition */ | |
void xorshift_srand(unsigned int seed) { | |
xor_state = seed; | |
} | |
unsigned int xorshift_rand(void) { | |
xor_state ^= xor_state << 13; | |
xor_state ^= xor_state >> 17; | |
xor_state ^= xor_state << 5; | |
return xor_state; | |
} | |
void run_first_fit_policy_batch(void) { | |
set_method(FIRST_FIT); | |
benchmark_policy(FIRST_FIT); | |
} | |
void run_best_fit_policy_batch(void) { | |
set_method(BEST_FIT); | |
benchmark_policy(BEST_FIT); | |
} | |
void run_worst_fit_policy_batch(void) { | |
set_method(WORST_FIT); | |
benchmark_policy(WORST_FIT); | |
} | |
void benchmark_policy(int policy) { | |
// 0-initialize the elements to allocate pointers to data claimed | |
void* allocated_data[NUM_OPERATIONS] = {0}; | |
// Perform random allocations and deallocations | |
for (int i = LOWEST_ARR_INDEX; i < NUM_OPERATIONS; i++) | |
{ | |
// Data claimed is random | |
size_t size = xorshift_rand() % MAX_B_DATA_SIZE + 1; | |
// malloc() should return a ptr to the data claimed (not to the block which has that data as part of it) | |
allocated_data[i] = malloc(size); | |
if (allocated_data[i] == NULL) | |
{ | |
wstderr("ERROR: malloc() returned NULL on one of its call, aborting this test.\n"); | |
return; | |
} | |
// Free one block every 3 of them | |
if (((i % BLOCKS_FREE_EVERY) == 0) && (allocated_data[i / BLOCKS_FREE_EVERY])) | |
{ | |
free(allocated_data[i / BLOCKS_FREE_EVERY]); | |
// Freed memory can no longer be used | |
allocated_data[i / BLOCKS_FREE_EVERY] = NULL; | |
} | |
} | |
// Report the result & clean the heap | |
destroy_memory(allocated_data); | |
} | |
double calculate_fragmentation(void) | |
{ | |
size_t total_free = 0; | |
size_t largest_free_block = 0; | |
// Iterate over each mem block of the heap | |
for (t_block block = get_heap_base(); block != NULL; block = block->next) | |
{ | |
// Check good allocation | |
if ((block->ptr == block->data) && block->free) | |
{ | |
total_free += block->size; | |
if (block->size > largest_free_block) | |
{ | |
largest_free_block = block->size; | |
} | |
} | |
} | |
if (total_free == 0) | |
{ | |
return 0.0; | |
} | |
// The smaller are the pieces of free memory, the more fragmentation there is | |
return (1.0 - ((double)largest_free_block / (double)total_free)) * 100.0; | |
} | |
void destroy_memory(void** allocated_data) | |
{ | |
for (int i = LOWEST_ARR_INDEX; i < NUM_OPERATIONS; i++) | |
{ | |
if (allocated_data[i] != NULL) | |
{ | |
free(allocated_data[i]); | |
// Once freed, that memory can't be accessed | |
allocated_data[i] = NULL; | |
} | |
} | |
} | |
//! \brief Main function for testing. | |
int main(int argc, char* argv[]) | |
{ | |
(void)argc; | |
(void)argv; | |
// Seed the RNG | |
xorshift_srand(XORSHIFT_SEED); | |
// Loop benchmarking different policies, randomly | |
for (int i = LOWEST_ARR_INDEX; i < BENCHMARK_ITERATIONS; i++) | |
{ | |
switch (xorshift_rand() % 3) | |
{ | |
case 0: | |
run_first_fit_policy_batch(); | |
break; | |
case 1: | |
run_best_fit_policy_batch(); | |
break; | |
default: | |
// case 2 | |
run_worst_fit_policy_batch(); | |
} | |
// sleep a bit | |
sleep(1); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment