Skip to content
Snippets Groups Projects
Commit 12fcb49e authored by Matteo Cicuttin's avatar Matteo Cicuttin
Browse files

INFO0939-2021 code.

parent 3b1b0ca2
Branches
No related tags found
No related merge requests found
Prerequisites for the class:
---
* Having access to a Unix machine
* Having access to the compiler (`gcc` or `clang`), the debugger (`gdb`) and `wget`
* NIC5 satisfies all the requirements
Instructions for downloading the example code
---
The git repository is located at [here](https://gitlab.onelab.info/mcicuttin/snippets/INFO0939) (`https://gitlab.onelab.info/mcicuttin/snippets/INFO0939`). We will use the following files:
- `intdiv.c` for the `assert()` example on the integer division program
- `stack_corrupt.c` for a debugging exercise
- `cache.c` for a profiling exercise
You can download the files on your machine or on NIC5 via `wget`:
```
# This command is needed only when you open a new shell
export REPO_BASE=https://gitlab.onelab.info/mcicuttin/snippets/INFO0939/-/raw/master/
# Files are then donwloaded as following:
wget $REPO_BASE/intdiv.c
wget $REPO_BASE/stack_corrupt.c
wget $REPO_BASE/cache.c
```
GDB Cheatsheet
---
To debug with GDB: `gdb <progname>`, then
* `r`: Run the program
* `bt`: Print the backtrace of a crashed program
* `frame`: Select the stack frame you want to analyze
* `s` or `step`: step one statement, enter the function if statement is a function call
* `n` or `next`: execute next statement
* `c`: continue until the end of the program or the next breakpoint
* `break <file:line>`: set a breakpoint
* `p`: print the value of a variable
Integer division program & `assert()`
---
You are not really required to run this code, but...
* Compile with `gcc -g -o intdiv intdiv.c` (debug mode)
* Compile with `gcc -O3 -DNDEBUG -o intdiv intdiv.c` (release mode)
* Try to pass a negative integer to the function, compile the program in both modes and see what happens
Debugging exercise with `stack_corrupt.c`
---
* Compile with `gcc -g -o stack_corrupt stack_corrupt.c`
* Run with `./stack_corrupt`. What do you see?
* Launch the code in GDB and try to explain what you see
Profiling exercise with `cache.c`
---
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/resource.h>
static void *
Malloc(size_t size)
{
void *ret = malloc(size);
if (!ret)
{
printf("malloc() failed\n");
abort();
}
return ret;
}
static void
preheat(double *out, const double *mat, const double *vec,
size_t m, size_t n)
{
for (size_t i = 0; i < m; i++)
for (size_t j = 0; j < n; j++)
out[i] += mat[i*n + j] * vec[j];
}
static void
mvp_good(double *out, const double *mat, const double *vec,
size_t m, size_t n)
{
for (size_t i = 0; i < m; i++)
for (size_t j = 0; j < n; j++)
out[i] += mat[i*n + j] * vec[j];
}
static void
mvp_bad(double *out, const double *mat, const double *vec,
size_t m, size_t n)
{
for (size_t j = 0; j < n; j++)
for (size_t i = 0; i < m; i++)
out[i] += mat[i*n + j] * vec[j];
}
static double
compute_time(const struct rusage *rstart, const struct rusage *rend)
{
double ret = rend->ru_utime.tv_sec + rend->ru_utime.tv_usec/1e6;
ret -= rstart->ru_utime.tv_sec + rstart->ru_utime.tv_usec/1e6;
return ret;
}
int
main(int argc, char * const argv[])
{
int rows = 0, cols = 0;
int ch;
while ( (ch = getopt(argc, argv, "r:c:")) != -1 )
{
switch (ch)
{
case 'r':
rows = atoi(optarg);
break;
case 'c':
cols = atoi(optarg);
break;
case '?':
default:
printf("Usage: %s -r <rows> -c <cols>\n", argv[0]);
exit(EXIT_FAILURE);
}
}
if (rows < 1 || cols < 1)
{
printf("Number of rows and cols must be >1\n");
exit(EXIT_FAILURE);
}
double *mat = (double *) Malloc(rows*cols*sizeof(double));
double *vec = (double *) Malloc(cols*sizeof(double));
double *out = (double *) Malloc(rows*sizeof(double));
preheat(out, mat, vec, rows, cols);
struct rusage rstart, rend;
getrusage(RUSAGE_SELF, &rstart);
mvp_good(out, mat, vec, rows, cols);
getrusage(RUSAGE_SELF, &rend);
double time = compute_time(&rstart, &rend);
printf("Good MVP: %g secs\n", time);
getrusage(RUSAGE_SELF, &rstart);
mvp_bad(out, mat, vec, rows, cols);
getrusage(RUSAGE_SELF, &rend);
time = compute_time(&rstart, &rend);
printf("Bad MVP: %g secs\n", time);
free(out);
free(vec);
free(mat);
return 0;
}
#include <stdio.h>
#include <assert.h>
typedef struct div_result {
int quo;
int rem;
} div_result_t;
static void
integer_division(int x, int y, struct div_result *res)
{
/* Precondition: for the program to work, the input must satisfy
* x >= 0 (just to keep things simple)
* y > 0 (because division by zero is not defined)
*/
assert(x >= 0 && y > 0);
res->quo = 0;
res->rem = x;
/* The loop invariant is that
* - quotient * y + res has to be equal to x
* - y > 0
* The invariant must be true before, during and after the loop.
*/
assert( (res.quo*y + res.rem == x) && res.rem >= 0 && y > 0 );
while (res.rem >= y)
{
/* At this point invariant AND while condition should be valid */
assert( (res.quo*y + res.rem == x) && res.rem >= 0 && y > 0 && res.rem >= y );
res.rem = res.rem - y;
res.quo = res.quo + 1;
/* At this point the invariant should be re-established */
assert( (res.quo*y + res.rem == x) && res.rem >= 0 && y > 0 );
}
/* Postcondition: invariant AND NOT while condition */
assert( (res.quo*y + res.rem == x) && res.rem >= 0 && y > 0 && rem < y );
/* In addition, note that IF we enter the cycle THEN res.rem ALWAYS
* decreases. res.rem is a ``bound function'' and allows you to say
* that your program ALWAYS terminates. */
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSZ 4
struct mystruct
{
int x;
char y[BUFSZ];
};
static void
fun(struct mystruct *s)
{
s->x = 42;
strcpy(s->y, "Hello world, this is INFO0939");
}
int main(void)
{
int *x = (int *) malloc(400);
struct mystruct s;
fun(&s);
free(x);
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment