Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmad-masud committed Aug 7, 2024
0 parents commit 85b7753
Show file tree
Hide file tree
Showing 9 changed files with 425 additions and 0 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: CI

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
build-and-test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y valgrind make gcc

- name: Build project
run: make

- name: Run valgrind tests
run: valgrind ./myalloc
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"files.associations": {
"myalloc.h": "c"
}
}
17 changes: 17 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
TARGET = myalloc
OBJS = main.o myalloc.o

CXXFLAGS = -Wall -g -std=c++11
CXX = g++

all: clean $(TARGET)

%.o: %.cpp
$(CXX) -c $(CXXFLAGS) $<

$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $(OBJS) -o $@

clean:
rm -f $(TARGET)
rm -f $(OBJS)
41 changes: 41 additions & 0 deletions main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include <iostream>
#include <vector>
#include "myalloc.hpp"

int main(int argc, char* argv[]) {
MyAllocator allocator(100, FIRST_FIT);
std::cout << "Using first fit algorithm on memory size 100" << std::endl;

std::vector<int*> p(50, nullptr);
for(int i = 0; i < 10; ++i) {
p[i] = static_cast<int*>(allocator.allocate(sizeof(int)));
if(p[i] == nullptr) {
std::cout << "Allocation failed" << std::endl;
continue;
}
*(p[i]) = i;
std::cout << "p[" << i << "] = " << p[i] << " ; *p[" << i << "] = " << *(p[i]) << std::endl;
}

allocator.printStatistics();

for(int i = 0; i < 10; ++i) {
if(i % 2 == 0) {
continue;
}
std::cout << "Freeing p[" << i << "]" << std::endl;
allocator.deallocate(p[i]);
p[i] = nullptr;
}

std::cout << "available_memory " << allocator.availableMemory() << std::endl;

std::vector<void*> before(100, nullptr);
std::vector<void*> after(100, nullptr);
allocator.compactAllocation(before, after);

allocator.printStatistics();

// allocator's destructor will automatically free allocated memory
return 0;
}
Binary file added main.o
Binary file not shown.
Binary file added myalloc
Binary file not shown.
294 changes: 294 additions & 0 deletions myalloc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "myalloc.hpp"

MyAllocator::MyAllocator(int size, AllocationAlgorithm algorithm) {
initialize(size, algorithm);
}

MyAllocator::~MyAllocator() {
destroy();
}

void MyAllocator::initialize(int size, AllocationAlgorithm algorithm) {
assert(size > 0);

// Align size to 64 bytes
size = (size + 63) & ~63;

algorithm_ = algorithm;
size_ = size;
memory_ = malloc(static_cast<size_t>(size_));

if (!memory_) {
fprintf(stderr, "Failed to allocate memory\n");
exit(EXIT_FAILURE);
}

memset(memory_, 0, static_cast<size_t>(size_));

Block* initialBlock = static_cast<Block*>(memory_);
initialBlock->size = size_;

freeList_ = new Node{ initialBlock, nullptr };
allocatedList_ = nullptr;

pthread_mutex_init(&lock_, nullptr);
}

void MyAllocator::destroy() {
pthread_mutex_lock(&lock_);

free(memory_);
memory_ = nullptr;

Node* current = freeList_;
while (current) {
Node* next = current->next;
delete current;
current = next;
}

freeList_ = nullptr;

current = allocatedList_;
while (current) {
Node* next = current->next;
delete current;
current = next;
}

allocatedList_ = nullptr;

pthread_mutex_unlock(&lock_);
pthread_mutex_destroy(&lock_);
}

void* MyAllocator::allocate(int size) {
pthread_mutex_lock(&lock_);

Node* prev = nullptr;
Node* curr = freeList_;
Node* bestPrev = nullptr;
Node* bestFit = nullptr;
size_t totalSize = size + sizeof(size_t);

if (algorithm_ == BEST_FIT) {
while (curr) {
if (curr->block->size >= totalSize && (!bestFit || curr->block->size < bestFit->block->size)) {
bestFit = curr;
bestPrev = prev;
}
prev = curr;
curr = curr->next;
}
curr = bestFit;
prev = bestPrev;
} else {
while (curr && curr->block->size < totalSize) {
prev = curr;
curr = curr->next;
}
}

if (curr) {
Block* block = curr->block;

if (block->size >= totalSize + sizeof(Block)) {
Block* newBlock = reinterpret_cast<Block*>(reinterpret_cast<char*>(block) + totalSize);
newBlock->size = block->size - totalSize;

Node* newNode = new Node{ newBlock, nullptr };

curr->block->size = totalSize;

if (prev) {
prev->next = newNode;
} else {
freeList_ = newNode;
}
} else {
if (prev) {
prev->next = curr->next;
} else {
freeList_ = curr->next;
}
curr->block->size = totalSize;
}

Node* temp = allocatedList_;
if (!temp) {
allocatedList_ = curr;
} else {
while (temp->next) {
temp = temp->next;
}
temp->next = curr;
}
curr->next = nullptr;

*reinterpret_cast<size_t*>(block) = totalSize;

pthread_mutex_unlock(&lock_);
return reinterpret_cast<char*>(block) + sizeof(size_t);
}

pthread_mutex_unlock(&lock_);
return nullptr;
}

void MyAllocator::deallocate(void* ptr) {
assert(ptr != nullptr);

pthread_mutex_lock(&lock_);

Block* block = reinterpret_cast<Block*>(reinterpret_cast<char*>(ptr) - sizeof(size_t));

Node* newNode = new Node{ block, nullptr };

if (!freeList_) {
freeList_ = newNode;
} else {
Node* curr = freeList_;
while (curr->next) {
curr = curr->next;
}
curr->next = newNode;
}

Node* curr = allocatedList_;
Node* prev = nullptr;

while (curr && curr->block != block) {
prev = curr;
curr = curr->next;
}

if (curr) {
if (prev) {
prev->next = curr->next;
} else {
allocatedList_ = curr->next;
}
delete curr;
}

bool merged;
do {
merged = false;
Node* current = freeList_;
while (current) {
Node* checker = current;
while (checker->next) {
if (reinterpret_cast<char*>(current->block) + current->block->size == reinterpret_cast<char*>(checker->next->block)) {
current->block->size += checker->next->block->size;
Node* temp = checker->next;
checker->next = checker->next->next;
delete temp;
merged = true;
} else {
checker = checker->next;
}
}
current = current->next;
}
} while (merged);

pthread_mutex_unlock(&lock_);
}

int MyAllocator::compactAllocation(std::vector<void*>& before, std::vector<void*>& after) {
pthread_mutex_lock(&lock_);

int compactedSize = 0;
size_t offset = 0;
Node* current = allocatedList_;

Node* temp;
while (freeList_) {
temp = freeList_;
freeList_ = freeList_->next;
delete temp;
}

while (current) {
Node* next = current->next;
Block* block = current->block;
if (reinterpret_cast<char*>(block) != reinterpret_cast<char*>(memory_) + offset) {
std::memmove(reinterpret_cast<char*>(memory_) + offset, block, block->size);
before.push_back(reinterpret_cast<char*>(block) + sizeof(size_t));
after.push_back(reinterpret_cast<char*>(memory_) + offset + sizeof(size_t));
compactedSize++;
}
block = reinterpret_cast<Block*>(reinterpret_cast<char*>(memory_) + offset);
current->block = block;
offset += block->size;
current = next;
}

if (offset < static_cast<size_t>(size_)) {
freeList_ = new Node{ reinterpret_cast<Block*>(reinterpret_cast<char*>(memory_) + offset), nullptr };
freeList_->block->size = size_ - offset;
} else {
freeList_ = nullptr;
}

pthread_mutex_unlock(&lock_);
return compactedSize;
}

int MyAllocator::availableMemory() {
pthread_mutex_lock(&lock_);

int availableMemorySize = 0;
Node* current = freeList_;
while (current) {
availableMemorySize += current->block->size;
current = current->next;
}

pthread_mutex_unlock(&lock_);
return availableMemorySize;
}

void MyAllocator::printStatistics() {
pthread_mutex_lock(&lock_);

int allocatedSize = 0;
int allocatedChunks = 0;
int freeSize = 0;
int freeChunks = 0;
int smallestFreeChunkSize = size_;
int largestFreeChunkSize = 0;

Node* current = allocatedList_;
while (current) {
allocatedSize += current->block->size;
allocatedChunks++;
current = current->next;
}

current = freeList_;
while (current) {
freeSize += current->block->size;
if (current->block->size > largestFreeChunkSize) {
largestFreeChunkSize = current->block->size;
}
if (current->block->size < smallestFreeChunkSize) {
smallestFreeChunkSize = current->block->size;
}
freeChunks++;
current = current->next;
}

printf("Allocated size = %d\n", allocatedSize);
printf("Allocated chunks = %d\n", allocatedChunks);
printf("Free size = %d\n", freeSize);
printf("Free chunks = %d\n", freeChunks);
printf("Largest free chunk size = %d\n", largestFreeChunkSize);
printf("Smallest free chunk size = %d\n", smallestFreeChunkSize);

pthread_mutex_unlock(&lock_);
}
Loading

0 comments on commit 85b7753

Please sign in to comment.