System Programming: Low-Level C++ Development and System Integration
System Programming: Low-Level C++ Development and System Integration
In this post, I’ll share insights from my System Programming project, which demonstrates advanced low-level C++ development techniques, system integration, and performance optimization in system-level applications.
Project Overview
The System Programming project showcases comprehensive low-level programming skills using C++, focusing on system integration, memory management, performance optimization, and operating system interaction. This project demonstrates mastery of system-level programming concepts and modern C++ development practices.
Technical Architecture
Project Structure
SystemProgramming/
├── src/
│ ├── memory_management/
│ │ ├── custom_allocator.cpp
│ │ ├── memory_pool.cpp
│ │ └── smart_pointers.cpp
│ ├── file_system/
│ │ ├── file_operations.cpp
│ │ ├── directory_traversal.cpp
│ │ └── file_monitoring.cpp
│ ├── networking/
│ │ ├── tcp_server.cpp
│ │ ├── udp_client.cpp
│ │ └── socket_wrapper.cpp
│ ├── threading/
│ │ ├── thread_pool.cpp
│ │ ├── mutex_wrapper.cpp
│ │ └── async_operations.cpp
│ ├── performance/
│ │ ├── profiling.cpp
│ │ ├── optimization.cpp
│ │ └── benchmarking.cpp
│ └── utilities/
│ ├── logging.cpp
│ ├── configuration.cpp
│ └── error_handling.cpp
├── include/
├── tests/
├── benchmarks/
├── CMakeLists.txt
└── README.mdCore Components
Custom Memory Allocator
// src/memory_management/custom_allocator.cpp
#include <memory>
#include <unordered_map>
#include <mutex>
#include <algorithm>
namespace SystemProgramming {
class CustomAllocator {
private:
struct Block {
void* ptr;
size_t size;
bool isFree;
Block* next;
Block* prev;
};
void* memoryPool;
size_t poolSize;
Block* freeList;
Block* usedList;
std::mutex allocatorMutex;
std::unordered_map<void*, Block*> blockMap;
static constexpr size_t ALIGNMENT = 8;
static constexpr size_t MIN_BLOCK_SIZE = 32;
public:
explicit CustomAllocator(size_t poolSize = 1024 * 1024)
: poolSize(poolSize), freeList(nullptr), usedList(nullptr) {
initializePool();
}
~CustomAllocator() {
std::free(memoryPool);
}
void* allocate(size_t size) {
std::lock_guard<std::mutex> lock(allocatorMutex);
// Align size to ALIGNMENT boundary
size = alignSize(size);
// Find suitable free block
Block* block = findFreeBlock(size);
if (!block) {
return nullptr; // Out of memory
}
// Split block if it's too large
if (block->size > size + sizeof(Block) + MIN_BLOCK_SIZE) {
splitBlock(block, size);
}
// Move block from free list to used list
moveToUsedList(block);
blockMap[block->ptr] = block;
return block->ptr;
}
void deallocate(void* ptr) {
if (!ptr) return;
std::lock_guard<std::mutex> lock(allocatorMutex);
auto it = blockMap.find(ptr);
if (it == blockMap.end()) {
return; // Invalid pointer
}
Block* block = it->second;
blockMap.erase(it);
// Move block from used list to free list
moveToFreeList(block);
// Try to coalesce with adjacent free blocks
coalesceBlocks(block);
}
size_t getUsedMemory() const {
std::lock_guard<std::mutex> lock(allocatorMutex);
size_t used = 0;
Block* current = usedList;
while (current) {
used += current->size;
current = current->next;
}
return used;
}
size_t getFreeMemory() const {
std::lock_guard<std::mutex> lock(allocatorMutex);
size_t free = 0;
Block* current = freeList;
while (current) {
free += current->size;
current = current->next;
}
return free;
}
private:
void initializePool() {
memoryPool = std::aligned_alloc(ALIGNMENT, poolSize);
if (!memoryPool) {
throw std::bad_alloc();
}
// Create initial free block
Block* initialBlock = static_cast<Block*>(memoryPool);
initialBlock->ptr = static_cast<char*>(memoryPool) + sizeof(Block);
initialBlock->size = poolSize - sizeof(Block);
initialBlock->isFree = true;
initialBlock->next = nullptr;
initialBlock->prev = nullptr;
freeList = initialBlock;
}
size_t alignSize(size_t size) {
return (size + ALIGNMENT - 1) & ~(ALIGNMENT - 1);
}
Block* findFreeBlock(size_t size) {
Block* current = freeList;
while (current) {
if (current->size >= size) {
return current;
}
current = current->next;
}
return nullptr;
}
void splitBlock(Block* block, size_t size) {
Block* newBlock = reinterpret_cast<Block*>(
static_cast<char*>(block->ptr) + size);
newBlock->ptr = static_cast<char*>(newBlock) + sizeof(Block);
newBlock->size = block->size - size - sizeof(Block);
newBlock->isFree = true;
newBlock->next = block->next;
newBlock->prev = block->prev;
if (newBlock->next) {
newBlock->next->prev = newBlock;
}
if (newBlock->prev) {
newBlock->prev->next = newBlock;
}
block->size = size;
if (block == freeList) {
freeList = newBlock;
}
}
void moveToUsedList(Block* block) {
// Remove from free list
if (block->prev) {
block->prev->next = block->next;
} else {
freeList = block->next;
}
if (block->next) {
block->next->prev = block->prev;
}
// Add to used list
block->isFree = false;
block->next = usedList;
block->prev = nullptr;
if (usedList) {
usedList->prev = block;
}
usedList = block;
}
void moveToFreeList(Block* block) {
// Remove from used list
if (block->prev) {
block->prev->next = block->next;
} else {
usedList = block->next;
}
if (block->next) {
block->next->prev = block->prev;
}
// Add to free list
block->isFree = true;
block->next = freeList;
block->prev = nullptr;
if (freeList) {
freeList->prev = block;
}
freeList = block;
}
void coalesceBlocks(Block* block) {
// Coalesce with next block
if (block->next && block->next->isFree) {
Block* nextBlock = block->next;
// Remove next block from free list
if (nextBlock->prev) {
nextBlock->prev->next = nextBlock->next;
} else {
freeList = nextBlock->next;
}
if (nextBlock->next) {
nextBlock->next->prev = nextBlock->prev;
}
// Merge blocks
block->size += nextBlock->size + sizeof(Block);
block->next = nextBlock->next;
if (nextBlock->next) {
nextBlock->next->prev = block;
}
}
// Coalesce with previous block
if (block->prev && block->prev->isFree) {
Block* prevBlock = block->prev;
// Remove current block from free list
if (block->prev) {
block->prev->next = block->next;
} else {
freeList = block->next;
}
if (block->next) {
block->next->prev = block->prev;
}
// Merge blocks
prevBlock->size += block->size + sizeof(Block);
prevBlock->next = block->next;
if (block->next) {
block->next->prev = prevBlock;
}
}
}
};
// Custom allocator for STL containers
template<typename T>
class STLAllocator {
private:
CustomAllocator* allocator;
public:
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
explicit STLAllocator(CustomAllocator* alloc) : allocator(alloc) {}
template<typename U>
STLAllocator(const STLAllocator<U>& other) : allocator(other.allocator) {}
pointer allocate(size_type n) {
return static_cast<pointer>(allocator->allocate(n * sizeof(T)));
}
void deallocate(pointer p, size_type n) {
allocator->deallocate(p);
}
template<typename U>
bool operator==(const STLAllocator<U>& other) const {
return allocator == other.allocator;
}
template<typename U>
bool operator!=(const STLAllocator<U>& other) const {
return !(*this == other);
}
};
} // namespace SystemProgramming
Thread Pool Implementation
// src/threading/thread_pool.cpp
#include <thread>
#include <queue>
#include <vector>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <atomic>
namespace SystemProgramming {
class ThreadPool {
private:
std::vector<std::thread> workers;
std::queue<std::function<void()>> tasks;
std::mutex queueMutex;
std::condition_variable condition;
std::atomic<bool> stop;
public:
explicit ThreadPool(size_t numThreads = std::thread::hardware_concurrency())
: stop(false) {
for (size_t i = 0; i < numThreads; ++i) {
workers.emplace_back([this] {
while (true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(queueMutex);
condition.wait(lock, [this] { return stop || !tasks.empty(); });
if (stop && tasks.empty()) {
return;
}
task = std::move(tasks.front());
tasks.pop();
}
task();
}
});
}
}
~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queueMutex);
stop = true;
}
condition.notify_all();
for (std::thread& worker : workers) {
worker.join();
}
}
template<typename F, typename... Args>
auto enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type> {
using return_type = typename std::result_of<F(Args...)>::type;
auto task = std::make_shared<std::packaged_task<return_type()>>(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
std::future<return_type> result = task->get_future();
{
std::unique_lock<std::mutex> lock(queueMutex);
if (stop) {
throw std::runtime_error("enqueue on stopped ThreadPool");
}
tasks.emplace([task] { (*task)(); });
}
condition.notify_one();
return result;
}
size_t getTaskCount() const {
std::unique_lock<std::mutex> lock(queueMutex);
return tasks.size();
}
size_t getWorkerCount() const {
return workers.size();
}
};
// Advanced thread pool with priority queues
class PriorityThreadPool {
private:
struct Task {
std::function<void()> function;
int priority;
bool operator<(const Task& other) const {
return priority < other.priority; // Higher priority first
}
};
std::vector<std::thread> workers;
std::priority_queue<Task> tasks;
std::mutex queueMutex;
std::condition_variable condition;
std::atomic<bool> stop;
public:
explicit PriorityThreadPool(size_t numThreads = std::thread::hardware_concurrency())
: stop(false) {
for (size_t i = 0; i < numThreads; ++i) {
workers.emplace_back([this] {
while (true) {
Task task;
{
std::unique_lock<std::mutex> lock(queueMutex);
condition.wait(lock, [this] { return stop || !tasks.empty(); });
if (stop && tasks.empty()) {
return;
}
task = std::move(const_cast<Task&>(tasks.top()));
tasks.pop();
}
task.function();
}
});
}
}
~PriorityThreadPool() {
{
std::unique_lock<std::mutex> lock(queueMutex);
stop = true;
}
condition.notify_all();
for (std::thread& worker : workers) {
worker.join();
}
}
template<typename F, typename... Args>
auto enqueue(int priority, F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type> {
using return_type = typename std::result_of<F(Args...)>::type;
auto task = std::make_shared<std::packaged_task<return_type()>>(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
std::future<return_type> result = task->get_future();
{
std::unique_lock<std::mutex> lock(queueMutex);
if (stop) {
throw std::runtime_error("enqueue on stopped PriorityThreadPool");
}
tasks.emplace([task] { (*task)(); }, priority);
}
condition.notify_one();
return result;
}
};
} // namespace SystemProgramming
File System Operations
// src/file_system/file_operations.cpp
#include <fstream>
#include <filesystem>
#include <chrono>
#include <functional>
namespace SystemProgramming {
class FileOperations {
public:
// Asynchronous file operations
static std::future<std::string> readFileAsync(const std::string& filename) {
return std::async(std::launch::async, [filename]() -> std::string {
std::ifstream file(filename, std::ios::binary);
if (!file) {
throw std::runtime_error("Cannot open file: " + filename);
}
file.seekg(0, std::ios::end);
size_t size = file.tellg();
file.seekg(0, std::ios::beg);
std::string content(size, '\0');
file.read(&content[0], size);
return content;
});
}
static std::future<void> writeFileAsync(const std::string& filename,
const std::string& content) {
return std::async(std::launch::async, [filename, content]() {
std::ofstream file(filename, std::ios::binary);
if (!file) {
throw std::runtime_error("Cannot create file: " + filename);
}
file.write(content.data(), content.size());
});
}
// Memory-mapped file operations
class MemoryMappedFile {
private:
void* mappedMemory;
size_t fileSize;
int fileDescriptor;
public:
explicit MemoryMappedFile(const std::string& filename)
: mappedMemory(nullptr), fileSize(0), fileDescriptor(-1) {
fileDescriptor = open(filename.c_str(), O_RDONLY);
if (fileDescriptor == -1) {
throw std::runtime_error("Cannot open file: " + filename);
}
struct stat fileStat;
if (fstat(fileDescriptor, &fileStat) == -1) {
close(fileDescriptor);
throw std::runtime_error("Cannot get file stats: " + filename);
}
fileSize = fileStat.st_size;
mappedMemory = mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE,
fileDescriptor, 0);
if (mappedMemory == MAP_FAILED) {
close(fileDescriptor);
throw std::runtime_error("Cannot map file to memory: " + filename);
}
}
~MemoryMappedFile() {
if (mappedMemory != MAP_FAILED) {
munmap(mappedMemory, fileSize);
}
if (fileDescriptor != -1) {
close(fileDescriptor);
}
}
const void* getData() const { return mappedMemory; }
size_t getSize() const { return fileSize; }
// Non-copyable
MemoryMappedFile(const MemoryMappedFile&) = delete;
MemoryMappedFile& operator=(const MemoryMappedFile&) = delete;
};
// File monitoring
class FileMonitor {
private:
std::string watchPath;
std::function<void(const std::string&)> callback;
std::atomic<bool> running;
std::thread monitorThread;
public:
FileMonitor(const std::string& path,
std::function<void(const std::string&)> cb)
: watchPath(path), callback(cb), running(false) {}
~FileMonitor() {
stop();
}
void start() {
if (running) return;
running = true;
monitorThread = std::thread([this] {
monitorLoop();
});
}
void stop() {
if (!running) return;
running = false;
if (monitorThread.joinable()) {
monitorThread.join();
}
}
private:
void monitorLoop() {
auto lastWriteTime = std::filesystem::last_write_time(watchPath);
while (running) {
try {
auto currentWriteTime = std::filesystem::last_write_time(watchPath);
if (currentWriteTime != lastWriteTime) {
callback(watchPath);
lastWriteTime = currentWriteTime;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
} catch (const std::exception& e) {
// Handle file system errors
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
}
};
// Directory traversal
static std::vector<std::string> traverseDirectory(const std::string& path,
bool recursive = true) {
std::vector<std::string> files;
try {
if (recursive) {
for (const auto& entry : std::filesystem::recursive_directory_iterator(path)) {
if (entry.is_regular_file()) {
files.push_back(entry.path().string());
}
}
} else {
for (const auto& entry : std::filesystem::directory_iterator(path)) {
if (entry.is_regular_file()) {
files.push_back(entry.path().string());
}
}
}
} catch (const std::filesystem::filesystem_error& e) {
throw std::runtime_error("Directory traversal error: " + std::string(e.what()));
}
return files;
}
// File operations with error handling
static bool copyFile(const std::string& source, const std::string& destination) {
try {
std::filesystem::copy_file(source, destination,
std::filesystem::copy_options::overwrite_existing);
return true;
} catch (const std::filesystem::filesystem_error& e) {
return false;
}
}
static bool moveFile(const std::string& source, const std::string& destination) {
try {
std::filesystem::rename(source, destination);
return true;
} catch (const std::filesystem::filesystem_error& e) {
return false;
}
}
static bool deleteFile(const std::string& filename) {
try {
return std::filesystem::remove(filename);
} catch (const std::filesystem::filesystem_error& e) {
return false;
}
}
};
} // namespace SystemProgramming
Network Operations
// src/networking/tcp_server.cpp
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
namespace SystemProgramming {
class TCPServer {
private:
int serverSocket;
int port;
std::atomic<bool> running;
std::thread serverThread;
std::vector<std::thread> clientThreads;
std::mutex clientMutex;
public:
explicit TCPServer(int port) : port(port), running(false) {
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == -1) {
throw std::runtime_error("Failed to create socket");
}
// Set socket options
int opt = 1;
if (setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
throw std::runtime_error("Failed to set socket options");
}
// Make socket non-blocking
int flags = fcntl(serverSocket, F_GETFL, 0);
fcntl(serverSocket, F_SETFL, flags | O_NONBLOCK);
}
~TCPServer() {
stop();
if (serverSocket != -1) {
close(serverSocket);
}
}
void start() {
if (running) return;
// Bind socket
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
if (bind(serverSocket, (struct sockaddr*)&address, sizeof(address)) == -1) {
throw std::runtime_error("Failed to bind socket");
}
// Listen for connections
if (listen(serverSocket, 10) == -1) {
throw std::runtime_error("Failed to listen on socket");
}
running = true;
serverThread = std::thread([this] { serverLoop(); });
}
void stop() {
if (!running) return;
running = false;
if (serverThread.joinable()) {
serverThread.join();
}
// Close all client connections
std::lock_guard<std::mutex> lock(clientMutex);
for (auto& thread : clientThreads) {
if (thread.joinable()) {
thread.join();
}
}
clientThreads.clear();
}
private:
void serverLoop() {
struct pollfd pollFds[1];
pollFds[0].fd = serverSocket;
pollFds[0].events = POLLIN;
while (running) {
int result = poll(pollFds, 1, 1000); // 1 second timeout
if (result > 0 && (pollFds[0].revents & POLLIN)) {
// Accept new connection
struct sockaddr_in clientAddress;
socklen_t clientAddressLen = sizeof(clientAddress);
int clientSocket = accept(serverSocket,
(struct sockaddr*)&clientAddress,
&clientAddressLen);
if (clientSocket != -1) {
// Handle client in separate thread
std::lock_guard<std::mutex> lock(clientMutex);
clientThreads.emplace_back([this, clientSocket, clientAddress] {
handleClient(clientSocket, clientAddress);
});
}
}
}
}
void handleClient(int clientSocket, const struct sockaddr_in& clientAddress) {
char buffer[4096];
while (running) {
ssize_t bytesReceived = recv(clientSocket, buffer, sizeof(buffer) - 1, 0);
if (bytesReceived <= 0) {
break; // Client disconnected
}
buffer[bytesReceived] = '\0';
// Process received data
std::string response = processRequest(buffer);
// Send response
send(clientSocket, response.c_str(), response.length(), 0);
}
close(clientSocket);
}
virtual std::string processRequest(const std::string& request) {
// Default implementation - echo the request
return "Echo: " + request;
}
};
// UDP Client implementation
class UDPClient {
private:
int socketFd;
struct sockaddr_in serverAddress;
public:
UDPClient(const std::string& serverIP, int serverPort) {
socketFd = socket(AF_INET, SOCK_DGRAM, 0);
if (socketFd == -1) {
throw std::runtime_error("Failed to create UDP socket");
}
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(serverPort);
inet_pton(AF_INET, serverIP.c_str(), &serverAddress.sin_addr);
}
~UDPClient() {
if (socketFd != -1) {
close(socketFd);
}
}
bool sendMessage(const std::string& message) {
ssize_t bytesSent = sendto(socketFd, message.c_str(), message.length(), 0,
(struct sockaddr*)&serverAddress, sizeof(serverAddress));
return bytesSent == static_cast<ssize_t>(message.length());
}
std::string receiveMessage(size_t maxSize = 4096) {
char buffer[maxSize];
struct sockaddr_in fromAddress;
socklen_t fromAddressLen = sizeof(fromAddress);
ssize_t bytesReceived = recvfrom(socketFd, buffer, maxSize - 1, 0,
(struct sockaddr*)&fromAddress, &fromAddressLen);
if (bytesReceived > 0) {
buffer[bytesReceived] = '\0';
return std::string(buffer);
}
return "";
}
};
} // namespace SystemProgramming
Performance Profiling
// src/performance/profiling.cpp
#include <chrono>
#include <unordered_map>
#include <mutex>
#include <fstream>
#include <iomanip>
namespace SystemProgramming {
class PerformanceProfiler {
private:
struct ProfileData {
std::chrono::high_resolution_clock::time_point startTime;
std::chrono::nanoseconds totalTime{0};
size_t callCount{0};
std::chrono::nanoseconds minTime{std::chrono::nanoseconds::max()};
std::chrono::nanoseconds maxTime{std::chrono::nanoseconds::min()};
};
std::unordered_map<std::string, ProfileData> profiles;
std::mutex profileMutex;
public:
class ScopedTimer {
private:
PerformanceProfiler* profiler;
std::string functionName;
std::chrono::high_resolution_clock::time_point startTime;
public:
ScopedTimer(PerformanceProfiler* prof, const std::string& name)
: profiler(prof), functionName(name) {
startTime = std::chrono::high_resolution_clock::now();
}
~ScopedTimer() {
auto endTime = std::chrono::high_resolution_clock::now();
auto duration = endTime - startTime;
profiler->recordProfile(functionName, duration);
}
};
void startProfile(const std::string& functionName) {
std::lock_guard<std::mutex> lock(profileMutex);
profiles[functionName].startTime = std::chrono::high_resolution_clock::now();
}
void endProfile(const std::string& functionName) {
auto endTime = std::chrono::high_resolution_clock::now();
std::lock_guard<std::mutex> lock(profileMutex);
auto& profile = profiles[functionName];
auto duration = endTime - profile.startTime;
profile.totalTime += duration;
profile.callCount++;
profile.minTime = std::min(profile.minTime, duration);
profile.maxTime = std::max(profile.maxTime, duration);
}
void recordProfile(const std::string& functionName,
std::chrono::nanoseconds duration) {
std::lock_guard<std::mutex> lock(profileMutex);
auto& profile = profiles[functionName];
profile.totalTime += duration;
profile.callCount++;
profile.minTime = std::min(profile.minTime, duration);
profile.maxTime = std::max(profile.maxTime, duration);
}
void printReport() const {
std::lock_guard<std::mutex> lock(profileMutex);
std::cout << std::left << std::setw(30) << "Function Name"
<< std::setw(15) << "Calls"
<< std::setw(20) << "Total Time (ms)"
<< std::setw(20) << "Avg Time (ms)"
<< std::setw(20) << "Min Time (ms)"
<< std::setw(20) << "Max Time (ms)" << std::endl;
std::cout << std::string(105, '-') << std::endl;
for (const auto& [name, data] : profiles) {
double totalMs = std::chrono::duration<double, std::milli>(data.totalTime).count();
double avgMs = totalMs / data.callCount;
double minMs = std::chrono::duration<double, std::milli>(data.minTime).count();
double maxMs = std::chrono::duration<double, std::milli>(data.maxTime).count();
std::cout << std::left << std::setw(30) << name
<< std::setw(15) << data.callCount
<< std::setw(20) << std::fixed << std::setprecision(3) << totalMs
<< std::setw(20) << avgMs
<< std::setw(20) << minMs
<< std::setw(20) << maxMs << std::endl;
}
}
void saveReportToFile(const std::string& filename) const {
std::lock_guard<std::mutex> lock(profileMutex);
std::ofstream file(filename);
if (!file) {
throw std::runtime_error("Cannot create report file: " + filename);
}
file << "Performance Profile Report\n";
file << "Generated at: " << std::chrono::system_clock::now().time_since_epoch().count() << "\n\n";
file << std::left << std::setw(30) << "Function Name"
<< std::setw(15) << "Calls"
<< std::setw(20) << "Total Time (ms)"
<< std::setw(20) << "Avg Time (ms)"
<< std::setw(20) << "Min Time (ms)"
<< std::setw(20) << "Max Time (ms)" << std::endl;
file << std::string(105, '-') << std::endl;
for (const auto& [name, data] : profiles) {
double totalMs = std::chrono::duration<double, std::milli>(data.totalTime).count();
double avgMs = totalMs / data.callCount;
double minMs = std::chrono::duration<double, std::milli>(data.minTime).count();
double maxMs = std::chrono::duration<double, std::milli>(data.maxTime).count();
file << std::left << std::setw(30) << name
<< std::setw(15) << data.callCount
<< std::setw(20) << std::fixed << std::setprecision(3) << totalMs
<< std::setw(20) << avgMs
<< std::setw(20) << minMs
<< std::setw(20) << maxMs << std::endl;
}
}
void reset() {
std::lock_guard<std::mutex> lock(profileMutex);
profiles.clear();
}
};
// Global profiler instance
extern PerformanceProfiler g_profiler;
// Macro for easy profiling
#define PROFILE_FUNCTION() \
PerformanceProfiler::ScopedTimer _timer(&g_profiler, __FUNCTION__)
#define PROFILE_SCOPE(name) \
PerformanceProfiler::ScopedTimer _timer(&g_profiler, name)
} // namespace SystemProgramming
CMake Build System
CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(SystemProgramming VERSION 1.0.0 LANGUAGES CXX)
# Set C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Compiler flags
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -DNDEBUG")
endif()
# Include directories
include_directories(include)
# Source files
set(SOURCES
src/memory_management/custom_allocator.cpp
src/memory_management/memory_pool.cpp
src/file_system/file_operations.cpp
src/file_system/directory_traversal.cpp
src/networking/tcp_server.cpp
src/networking/udp_client.cpp
src/threading/thread_pool.cpp
src/threading/mutex_wrapper.cpp
src/performance/profiling.cpp
src/performance/optimization.cpp
src/utilities/logging.cpp
src/utilities/configuration.cpp
)
# Create library
add_library(SystemProgrammingLib STATIC ${SOURCES})
# Link libraries
find_package(Threads REQUIRED)
target_link_libraries(SystemProgrammingLib Threads::Threads)
# Create executable
add_executable(SystemProgramming main.cpp)
target_link_libraries(SystemProgramming SystemProgrammingLib)
# Testing
enable_testing()
add_subdirectory(tests)
# Benchmarking
add_subdirectory(benchmarks)
# Installation
install(TARGETS SystemProgramming SystemProgrammingLib
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
install(DIRECTORY include/ DESTINATION include)Testing Framework
Unit Tests
// tests/test_memory_management.cpp
#include <gtest/gtest.h>
#include "SystemProgramming/custom_allocator.h"
class CustomAllocatorTest : public ::testing::Test {
protected:
void SetUp() override {
allocator = std::make_unique<SystemProgramming::CustomAllocator>(1024 * 1024);
}
std::unique_ptr<SystemProgramming::CustomAllocator> allocator;
};
TEST_F(CustomAllocatorTest, BasicAllocation) {
void* ptr = allocator->allocate(100);
ASSERT_NE(ptr, nullptr);
allocator->deallocate(ptr);
}
TEST_F(CustomAllocatorTest, MultipleAllocations) {
std::vector<void*> pointers;
for (int i = 0; i < 100; ++i) {
void* ptr = allocator->allocate(50);
ASSERT_NE(ptr, nullptr);
pointers.push_back(ptr);
}
for (void* ptr : pointers) {
allocator->deallocate(ptr);
}
}
TEST_F(CustomAllocatorTest, MemoryUsage) {
size_t initialFree = allocator->getFreeMemory();
void* ptr = allocator->allocate(1000);
ASSERT_NE(ptr, nullptr);
size_t usedAfterAlloc = allocator->getUsedMemory();
ASSERT_GT(usedAfterAlloc, 0);
allocator->deallocate(ptr);
size_t freeAfterDealloc = allocator->getFreeMemory();
ASSERT_EQ(freeAfterDealloc, initialFree);
}
TEST_F(CustomAllocatorTest, STLAllocator) {
using Allocator = SystemProgramming::STLAllocator<int>;
Allocator stlAllocator(allocator.get());
std::vector<int, Allocator> vec(stlAllocator);
for (int i = 0; i < 1000; ++i) {
vec.push_back(i);
}
ASSERT_EQ(vec.size(), 1000);
for (int i = 0; i < 1000; ++i) {
ASSERT_EQ(vec[i], i);
}
}Lessons Learned
System Programming
- Memory Management: Efficient custom memory allocators and smart pointers
- Threading: Advanced thread pool implementations and synchronization
- File Systems: Asynchronous file operations and memory mapping
- Networking: Low-level socket programming and server implementations
Performance Optimization
- Profiling: Comprehensive performance profiling and analysis
- Memory Optimization: Custom allocators and memory pool management
- Concurrency: Efficient thread pool and async operation patterns
- System Integration: Direct system call usage and optimization
C++ Development
- Modern C++: Use of C++17 features and best practices
- RAII: Resource management and exception safety
- Templates: Generic programming and STL integration
- Testing: Comprehensive unit testing and benchmarking
Future Enhancements
Advanced Features
- Lock-Free Programming: Implement lock-free data structures
- GPU Computing: CUDA integration for parallel processing
- Real-Time Systems: Real-time scheduling and priority management
- Distributed Systems: Network protocols and distributed algorithms
Performance Improvements
- SIMD Instructions: Vectorized operations for performance
- Cache Optimization: Cache-friendly data structures and algorithms
- Memory Mapping: Advanced memory mapping techniques
- Profiling Tools: Integration with external profiling tools
Conclusion
The System Programming project demonstrates comprehensive low-level C++ development skills and system integration expertise. Key achievements include:
- Advanced Memory Management: Custom allocators and memory pool implementations
- Concurrent Programming: Thread pools and synchronization primitives
- System Integration: File system operations and network programming
- Performance Optimization: Profiling tools and optimization techniques
- Modern C++: Use of C++17 features and best practices
- Testing: Comprehensive testing and benchmarking frameworks
The project is available on GitHub and serves as a comprehensive example of system-level programming and performance optimization.
This project represents my deep dive into system programming and demonstrates how low-level programming skills can be applied to create high-performance, efficient systems. The lessons learned here continue to influence my approach to performance-critical applications and system design.