Commit b624f083 authored by bbguimaraes's avatar bbguimaraes
Browse files

mem_manager

parent 1ed8e933
......@@ -3,6 +3,7 @@ for details/demos/screenshots.
- asm: simple assembly program that slides a three-digit number across the
terminal and an external seven-segment display.
- mem_manager: best-fit memory allocator simluation.
- nqueens: n-queens solver and graphical display.
- sudoku: Sudoku solver library/GUI using genetic algorithms.
- tablut: ANSI C / ncurses implementation of the game Tablut.
CXXFLAGS = -std=c++11
all: mem_manager
mem_manager: memory.o mem_manager.cpp
.PHONY: clean
clean:
rm -f *.o mem_manager
Simulation of a memory management component. Allocates a region of memory and
handles loading and unloading of processes, finding free positions using the
best-fit algorithm.
$ ./mem_manager
>> defmem 64
>> d
0: $$$$$$$$ $$$$$$$$ $$$$$$$$ $$$$$$$$
32: $$$$$$$$ $$$$$$$$ $$$$$$$$ $$$$$$$$
>> load 1 4 a
>> d
0: aaaa$$$$ $$$$$$$$ $$$$$$$$ $$$$$$$$
32: $$$$$$$$ $$$$$$$$ $$$$$$$$ $$$$$$$$
>> load 2 16 b
>> d
0: aaaabbbb bbbbbbbb bbbb$$$$ $$$$$$$$
32: $$$$$$$$ $$$$$$$$ $$$$$$$$ $$$$$$$$
>> load 3 4 c
>> d
0: aaaabbbb bbbbbbbb bbbbcccc $$$$$$$$
32: $$$$$$$$ $$$$$$$$ $$$$$$$$ $$$$$$$$
>> load 4 8 d
>> d
0: aaaabbbb bbbbbbbb bbbbcccc dddddddd
32: $$$$$$$$ $$$$$$$$ $$$$$$$$ $$$$$$$$
>> load 5 4 e
>> d
0: aaaabbbb bbbbbbbb bbbbcccc dddddddd
32: eeee$$$$ $$$$$$$$ $$$$$$$$ $$$$$$$$
>> load 6 4 f
>> d
0: aaaabbbb bbbbbbbb bbbbcccc dddddddd
32: eeeeffff $$$$$$$$ $$$$$$$$ $$$$$$$$
>> load 7 4 g
>> d
0: aaaabbbb bbbbbbbb bbbbcccc dddddddd
32: eeeeffff gggg$$$$ $$$$$$$$ $$$$$$$$
>> del 2
>> d
0: aaaa$$$$ $$$$$$$$ $$$$cccc dddddddd
32: eeeeffff gggg$$$$ $$$$$$$$ $$$$$$$$
>> load 2 4 b
>> d
0: aaaabbbb $$$$$$$$ $$$$cccc dddddddd
32: eeeeffff gggg$$$$ $$$$$$$$ $$$$$$$$
>> del 4
>> d
0: aaaabbbb $$$$$$$$ $$$$cccc $$$$$$$$
32: eeeeffff gggg$$$$ $$$$$$$$ $$$$$$$$
>> del 6
>> d
0: aaaabbbb $$$$$$$$ $$$$cccc $$$$$$$$
32: eeee$$$$ gggg$$$$ $$$$$$$$ $$$$$$$$
>> load 2 4 b
>> d
0: aaaabbbb $$$$$$$$ $$$$cccc $$$$$$$$
32: eeeebbbb gggg$$$$ $$$$$$$$ $$$$$$$$
>> compact
>> d
0: aaaabbbb cccceeee bbbbgggg $$$$$$$$
32: $$$$$$$$ $$$$$$$$ $$$$$$$$ $$$$$$$$
#include <iostream>
#include <string>
#include <exception>
#include <unistd.h>
#include <boost/lexical_cast.hpp>
#include "memory.h"
Memory * memory;
class ParseException : public std::exception {
std::string msg;
public:
ParseException(const std::string & msg) : msg(msg) {}
virtual ~ParseException() throw() {}
const char * what() const throw() {return this->msg.c_str();}
};
unsigned int read_uint(const std::string & name) {
std::string s;
std::cin >> s;
try {
return boost::lexical_cast<unsigned int>(s);
} catch(boost::bad_lexical_cast & ex) {
throw ParseException(name + ": invalid value");
}
}
char read_char() {
char c;
std::cin >> c;
return c;
}
void log_error(const std::exception & ex) {
std::cerr << ex.what() << std::endl;
}
void cmd_defmem(void) {
unsigned int size = read_uint("size");
if(memory)
delete memory;
memory = new Memory(size);
}
void cmd_load(void) {
unsigned int pid = read_uint("pid");
unsigned int size = read_uint("size");
char fill = read_char();
try {
memory->create_process(pid, size, fill);
} catch(std::exception& ex) {
log_error(ex);
}
}
void cmd_del(void) {
unsigned int pid = read_uint("pid");
try {
memory->delete_process(pid);
} catch(std::exception& ex) {
log_error(ex);
}
}
void cmd_reset(void) {
delete memory;
memory = 0;
}
void cmd_dump_proc(void) {
unsigned int pid = read_uint("pid");
try {
std::cout << memory->dump_proc(pid);
} catch(std::exception& ex) {
log_error(ex);
}
}
void cmd_dump_mem(void) {
std::cout << memory->dump_mem();
}
void cmd_compact(void) {
memory->compact();
}
void cmd_d(void) {
if(memory)
std::cout << memory->d();
}
bool execute(void) {
std::string command;
std::cin >> command;
if(!std::cin || command == "exit")
return false;
else if(memory == 0 && command != "defmem")
std::cout << "Call defmem first.";
else if(command == "defmem")
cmd_defmem();
else if(command == "load")
cmd_load();
else if(command == "del")
cmd_del();
else if(command == "reset")
cmd_reset();
else if(command == "dump_proc")
cmd_dump_proc();
else if(command == "dump_mem")
cmd_dump_mem();
else if(command == "compact")
cmd_compact();
else if(command == "d")
cmd_d();
else
std::cout << "\nUnknown command.";
return true;
}
int main(int /*argc*/, char** /*argv*/) {
bool tty = isatty(0);
bool run = true;
do {
if(tty)
std::cout << ">> ";
try {
run = execute();
} catch(const ParseException & ex) {
log_error(ex);
}
} while(run);
delete memory;
}
#include "memory.h"
#include <algorithm>
#include <sstream>
const unsigned int Memory::BLOCK_SIZE = 32;
Memory::Memory(unsigned int size) {
if(size <= 0)
throw MemoryException("Memory size must be grater than 0.");
this->size = size;
this->memory = new char[size + 1];
memory[size] = 0;
for(unsigned int i = 0; i < size; i++)
memory[i] = EMPTY_CHAR;
}
void Memory::create_process(unsigned int pid, unsigned int size, char fill) {
auto at = get_free_position(size);
auto p = Process(pid, size, fill);
p.set_position(get_position(at));
this->processes.insert(at, p);
for(unsigned int i = 0; i < size; i++)
memory[p.position() + i] = fill;
}
void Memory::delete_process(unsigned int pid) {
auto it = this->find_process_by_pid(pid);
if(it == this->processes.cend())
throw MemoryException("Process doesn't exist.");
for(unsigned int i = 0; i < it->size(); i++)
memory[it->position() + i] = '$';
this->processes.erase(it);
}
void Memory::compact(void) {
auto it = this->processes.begin();
unsigned int last = 0;
for(; it != this->processes.cend(); ++it) {
if(it->position() > last) {
for(unsigned int i = 0; i < it->size(); ++i)
memory[it->position() + i] = '$';
it->set_position(last);
for(unsigned int i = 0; i < it->size(); ++i)
memory[it->position() + i] = it->fill();
}
last = it->position() + it->size();
}
}
unsigned int
Memory::get_position(std::list<Process>::const_iterator at) const {
if(at == this->processes.cbegin())
return 0;
if(at == this->processes.cend())
return this->processes.back().position()
+ this->processes.back().size();
auto prev = --at;
return prev->position() + prev->size();
}
std::string Memory::dump_proc(unsigned int pid) const {
auto it = this->find_process_by_pid(pid);
if(it == this->processes.cend())
throw MemoryException("Process doesn't exist.");
return dump_proc(*it);
}
std::string Memory::dump_proc(const Process& p) const {
std::stringstream output;
output << "Process " << p.pid() << ":";
output << "\n start: " << p.position();
output << "\n size: " << p.size() ;
output << "\n last: " << p.position() + p.size() - 1;
output << "\n fill: " << memory[p.position()];
output << "\n";
return output.str();
}
std::string Memory::dump_mem(void) const {
std::stringstream output;
unsigned int last = 0;
auto it = this->processes.cbegin();
while(it != this->processes.cend()) {
if(it->position() != last)
output << "Empty space: " << (it->position() - last) << "\n";
output << dump_proc(*it);
last = it->position() + it->size();
++it;
}
if(last < size)
output << "Empty space: " << (size - last) << "\n";
return output.str();
}
std::string Memory::d() const {
std::stringstream output;
const unsigned int n_digits = calc_digits(size);
for(unsigned int i = 0; i < this->size; i += BLOCK_SIZE) {
output << this->format_index(i, n_digits);
const unsigned int n_bits = std::min(BLOCK_SIZE, this->size - i);
for(unsigned int b = 0; b < n_bits; ++b) {
if((0 < b) && (b % 8 == 0))
output << " ";
output << memory[i + b];
}
output << "\n";
}
return output.str();
}
int Memory::calc_digits(int n) const {
int n_digits = 0;
while(n > 0) {
n_digits++;
n /= 10;
}
return n_digits;
}
std::string Memory::format_index(unsigned int i, unsigned int n_digits) const {
std::stringstream str_stream;
str_stream << i << ":";
std::string str;
str_stream >> str;
str.resize(n_digits + 2, ' ');
return str;
}
std::list<Process>::const_iterator
Memory::find_process_by_pid(unsigned int pid) const {
return std::find_if(
this->processes.cbegin(), this->processes.cend(),
[&pid](const Process & p){return p.pid() == pid;});
}
std::list<Process>::const_iterator
Memory::get_free_position(unsigned int size) const {
auto it = this->processes.cbegin();
auto next = ++this->processes.cbegin();
auto best = this->processes.cend();
unsigned int best_size = this->size + 1;
unsigned int last = 0;
while(it != this->processes.cend()) {
unsigned int gap = it->position() - last;
if(size <= gap && gap < best_size) {
best_size = gap;
best = it;
}
last = it->position() + it->size();
it = next;
++next;
}
unsigned int gap = this->size - last;
if(size <= gap && gap < best_size) {
best_size = gap;
best = it;
}
if(best_size > this->size)
throw MemoryException("Not enought space in memory.");
return best;
}
#ifndef MEMORY_H
#define MEMORY_H
#include <exception>
#include <list>
#include <string>
#include "process.h"
class Memory {
public:
Memory(unsigned int size);
~Memory() { delete[] memory; }
/** Create a process. **/
void create_process(unsigned int pid, unsigned int size, char fill);
/** Delete process. **/
void delete_process(unsigned int pid);
/** Reallocate all processes to eliminate gaps. **/
void compact();
/** Return string showing information about one process. **/
std::string dump_proc(unsigned int pid) const;
/** Return string showing information about one process. **/
std::string dump_proc(const Process& p) const;
/** Return string showing free and occupied spaces. **/
std::string dump_mem() const;
/** Return string representation of the constents of memory. **/
std::string d() const;
private:
const static char EMPTY_CHAR = '$';
const static unsigned int BLOCK_SIZE;
int calc_digits(int n) const;
unsigned int get_position(std::list<Process>::const_iterator at) const;
std::list<Process>::const_iterator
find_process_by_pid(unsigned int pid) const;
/**
* Find a position in memory big enough to store [size] bytes, using
* the Best-Fit algorithm.
*/
std::list<Process>::const_iterator
get_free_position(unsigned int size) const;
std::string format_index(unsigned int i, unsigned int n_digits) const;
/** Memory size. **/
unsigned int size;
/** Memory content. **/
char* memory;
/** Array of processes. **/
std::list<Process> processes;
};
class MemoryException : public std::exception {
std::string msg;
public:
MemoryException(const std::string & msg) : msg(msg) {}
virtual ~MemoryException() throw() {}
virtual const char * what() const throw() {return this->msg.c_str();}
};
#endif
#ifndef PROCESS_H
#define PROCESS_H
class Process {
unsigned int m_pid;
unsigned int m_size;
unsigned int m_position;
char m_fill;
public:
Process(unsigned int pid, unsigned int size, char fill)
: m_pid(pid), m_size(size), m_fill(fill) {}
~Process() {}
unsigned int pid() const {return m_pid;}
unsigned int size() const {return m_size;}
unsigned int position() const{ return m_position;}
char fill() const {return m_fill;}
void set_position(unsigned int position) {this->m_position = position;}
};
#endif
defmem 64
d
load 1 4 a
d
load 2 16 b
d
load 3 4 c
d
load 4 8 d
d
load 5 4 e
d
load 6 4 f
d
load 7 4 g
d
del 2
d
load 2 4 b
d
del 4
d
del 6
d
load 2 4 b
d
compact
d
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment