CSCI 237
Computer Organization
Home | Lectures | Labs | CS@Williams
Lab 4: Memory Management and C Programming
Assigned | Apr 3/4, 2024 |
---|---|
Due Date | Apr 9/10 at 11:59pm. |
Files | lab4.tar [Slides] |
Submissions | Submit your solutions using submit237 4 bitmap.c . |
Overview
The most direct goals of this lab are to explore manual memory management (explicitly allocating and freeing memory) and using structs, pointers, and arrays.
The indirect (but perhaps more important) goal of this lab is to practice designing and implementing software that meets an interface's specification. Although you must implement a specific set of functions that must have specific behaviors, instructions on how to design and test the interface's implementation are less clearly specified compared to previous labs.
Instructions
The starter code for this lab is minimal, consisting of a handful of very small files: [bitmap.h], [bitmap.c], [bitmap_test.c], and [Makefile], The primary purpose of the starter code is to define standard function definitions so that I can run and test your code in a consistent way. For this reason it is important to preserve the types/definitions of the functions exactly.
Implementing a Bitmap
In this lab, you will be implementing a "bitmap". A bitmap, roughly speaking, is a logical array of individually addressable bits (elements that can take on the value of 0 or 1). The bitmap we will be implementing is a simplified version of Java's BitSet class. (In our bitmap, we will only be setting and querying individual bits; there won't be any "Set" or "Range" operations.)
Bitmaps have a variety of uses. In graphics, the bits are a direct representation of the pixels in the image. The left half of image below shows the bits in the bitmap, and the right half depicts what would show on screen. In monochrome systems, one bit is used to represent one pixel.
Bitmaps can also be used to track the status of a set of resources.
If each resource is assigned a unique identifier (an integer index),
then a resource could be marked "available" if its corresponding
entry in the bitmap has value "0", or marked "in-use" if its
corresponding entry in the bitmap has value "1".
A minimal set of operations we would need to track this information
is a set()
operation, which assigns the value 1
to the bit at a particular index,
an unset()
operation, which assigns the value 0
to the bit at a particular index,
and a get()
operation, which returns the value of the
bit at a particular index (either a 0
or a 1
).
When a bitmap that contains n
bits is initialized,
each of the bits is initialized to the value 0
.
The Bitmap Files
To implement and test your bitmap, you will modify
the files bitmap.c
and bitmap_test.c
.
You should not modify bitmap.h
.
Like in many C programs,
the header file contains the declaration of each required operation,
and the corresponding ".c" file is where you will implement the functions.
The bitmap_test.c
file has a int main(int argc, char **argv)
function,
and it is where you should write code that incrementally tests your functions as you
implement them. Rules in the Makefile
file can be used
to compile your code; typing make
at the command line should
build the executable program bitmap_test
for you. Note that we will not grade
bitmap_test.c
, but you are strongly encouraged to use it for testing
your bitmap implementation. You will not be able to rely solely on the autograder for testing.
Bitmap Design
You will be implementing your bitmap's functionality
using the struct bitmap
defined in bitmap.h
This structure has three fields:
uint64_t n_bytes
: The number of bytes in the bitmap (not bits!). Note: our bitmap data is
stored as an array of characters (bytes), and n_bytes is the size of that array. When calculating n_bytes, you
may have to add padding to get to a multiple of 8.
n_valid_bits
: since our memory can be allocated/accessed at byte granularity, we need to "pad"
the number of bits in our bitmap to a multiple of 8. But the padding is not logically part of our bitmap, so we
should only be able to get/set bits from bit number 0 up to bit n_valid_bits-1.
char *bits
: The actual bitmap. This memory buffer must be malloc()
'ed
and free()
'd by your program during allocate_bitmap(uint64_t num_bits)
and free_bitmap(struct bitmap *bmap)
.
Function Specifications
To complete the lab, you must implement the following six functions as described below:
struct bitmap *allocate_bitmap(uint64_t num_bits)
: uses malloc()
to
allocate a struct bitmap
and its array of bits such that it is large enough to
hold num_bits
valid bits. Sets all struct fields appropriately.
void free_bitmap(struct bitmap *bmap)
: given a pointer to a struct
bitmap
that was returned by a prior call to allocate_bitmap()
, frees all
memory associated with the structure (including the internal bit array).
char get_bit(struct bitmap *bmap, uint64_t i)
: yields the value of a given bit (either
a 0
or 1
). If i
is out of range, returns 0.
void set_bit(struct bitmap *bmap, uint64_t i)
: sets the bit at position i
to have value 1
, regardless of whether the bit was already set. If i
is
out of range, has no effect.
void unset_bit(struct bitmap *bmap, uint64_t i)
: sets the bit at position i
to have value 0
, regardless of whether the bit was already unset. If i
is
out of range, has no effect.
uint64_t first_unset_bit(struct bitmap *bmap)
: returns the lowest index that has a
bit with value 0
. If all valid bits within the bitmap is set, returns
bitmap->n_valid_bits
(the first bit index *after* the valid range of bitmap bits).
To help you visualize the state of your bitmap, we have provided the
function void dump_bitmap(struct bitmap *bmap)
for you.
It prints the structure fields as well as a visual representation of
the bitmap. Although void dump_bitmap(struct bitmap *bmap)
is not sufficient to thoroughly test your implementation's correctness,
it is useful for quick checks and diagnoses.
Note that dump_bitmap()
depends on your get_bit()
function,
so it may not display meaningful values for your bitmap's bits until that function is correctly implemented.
Testing Your Code
You should plan your implementation strategy so that you can incrementally test. You should design tests that verify that you've achieved the desired functionality. We will test your implementation by calling your functions and comparing the results to a reference bitmap implementation. "Illegal" operations (like trying to call set() on a bit outside the bitmap's range) should not crash your program, but they should not modify the bitmap's state. Be sure to think about all of the functionality that you are asked to implement and test that your bitmap behaves as specified.
Submitting
To submit your lab, please use submit237 4 bitmap.c.
This lab was designed to reinforce some of the most challenging aspects of C programming (pointers and memory management) in a fun, but straightforward way.