Skip to content

Commit

Permalink
Merge pull request lkl#34 from alexandrasandulescu/tracer-assignment
Browse files Browse the repository at this point in the history
Add tracer assignment
  • Loading branch information
dbaluta authored Mar 16, 2018
2 parents ed00a31 + 2e95ab8 commit 0865b29
Show file tree
Hide file tree
Showing 15 changed files with 1,475 additions and 0 deletions.
15 changes: 15 additions & 0 deletions tools/labs/templates/tracer_assignment/checker/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
objects = _test/tracer_test.o

.PHONY: all clean

all: tracer_test

tracer_test:
$(CC) -Wall -g -m32 -static -o $@ $(objects)


run: all
./run_tests.bash

clean:
-rm -f tracer_test *~ tracer_helper.ko
95 changes: 95 additions & 0 deletions tools/labs/templates/tracer_assignment/checker/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
= KPROBE BASED TRACER TEST SUITE ==

Test suite for kprobe based tracer

== FILES ==

README
* this file

Makefile.checker
* Makefile for automating the build process

_checker
* script to run all tests defined in _test/tracer_test.c

_test/Makefile
* test suite internal Makefile (creates necessary object files)

_test/tracer_test.c
* test suite for Kprobe Based Tracer

_test/tracer_test.h
* test suite header file

_test/tracer.h
* kprobe tracer header file (macros and structures)

_test/test.h
* useful macros for testing

_test/debug.h
* debugging macros

_test/util.h
* useful macros for generic use (error processing)

_helper/tracer_helper.c
* helper kernel module for simulating kprobed ops

== BUILDING ==

Use the Makefile to properly build the tracer_test executable and
the tracer_helper.ko module:

make -f Makefile.checker

== RUNNING ==

Copy your tracer.ko module and _checker, tracer_test and tracer_helper.ko
to fsimg/root directory on your QEMU/KVM virtual machine.

In order to run the test suite you can either use the _checker
script or run the tracer_test executable.

The _checker script runs all tests and computes assignment grade:

./_checker

In order to run a specific test pass the test number (1 .. 10) to the
tracer_test executable.

./tracer_test 5

== TESTS ==

Tests are basically unit tests. A single function in the test_fun_array (see
tracer_test.c) is called each time the tracer_test executable is invoked,
testing a single functionality (and assuming previous tests have been run and
passed).

The EXIT_IF_FAIL macro (see test.h) is unnecessary since after each test, the
program completes.

Each test function follows the unit test pattern: initialization, action,
evaluation. The test macro (see test.h) is invoked at the end of each test
for evaluating and grading the test.

== DEBUGGING ==

The debug.h header file consists of several macros useful for debugging
(dprintf, dlog). There are multiple uses of these macros throughout the above
files.

In order to turn debug messages on, you must define the DEBUG macro, either in
a header file, or, I suggest, in the Makefile. The LOG_LEVEL macro limits the
log message types that are to be printed, by default LOG_WARNING (see enum in
debug.h). You may redefine it in a header file or in the Makefile.

Rapid enabling of debug messages is achieved by commenting out the CPPFLAGS
line in the Makefile. It turns on debugging and enables all log messages
(LOG_DEBUG).

== OTHER ==

srand48() and drand48() are used for generating random numbers.
24 changes: 24 additions & 0 deletions tools/labs/templates/tracer_assignment/checker/_checker
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/sh

first_test=1
last_test=10
executable=tracer_test

for i in $(seq $first_test $last_test); do
./"$executable" $i
done | tee results.txt

cat results.txt | grep '\[.*\]$' | awk -F '[] /[]+' '
BEGIN {
sum=0
}
{
sum += $2;
}
END {
printf "\n%66s [%03d/100]\n", "Total:", sum;
}'

rm -f results.txt
4 changes: 4 additions & 0 deletions tools/labs/templates/tracer_assignment/checker/_helper/Kbuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
EXTRA_CFLAGS = -Wall -g

obj-m = tracer_helper.o

35 changes: 35 additions & 0 deletions tools/labs/templates/tracer_assignment/checker/_helper/helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#ifndef _HELPER__
#define _HELPER__

#include <asm/ioctl.h>

#define NAMESIZE 64
#define MCOUNT 128

#define PREPARE_TEST _IOW('t', 19, unsigned int)
#define START_TEST _IOW('t', 20, unsigned int)
#define STOP_TEST _IOW('t', 21, unsigned int)

/*XXX match test_params with tracers_stats
* perhaps use the same struct
*/
struct test_params {
pid_t pid;
char thread_name[NAMESIZE];
int idx; /* index for multi-kthreaded test */
/*
* kcalls: 5
* alloc : [1024] [8] [128] [10] [128]
* free : [0] [0] [1] [0] [1]
*/
int kcalls; /* number of kmalloc calls */
int alloc[MCOUNT]; /* sizes of kmalloc allocations */
int free[MCOUNT]; /* intmap for which allocations to free */
int sched;
int up;
int down;
int lock;
int unlock;
};

#endif
201 changes: 201 additions & 0 deletions tools/labs/templates/tracer_assignment/checker/_helper/tracer_helper.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/semaphore.h>
#include <linux/mutex.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <asm/ioctl.h>
#include <linux/uaccess.h>
#include <linux/semaphore.h>
#include <linux/mutex.h>

#include "helper.h"


#define HELPER_MINOR 30

/* number of paralel kernel threads */
static wait_queue_head_t wq[MCOUNT];

/*XXX: this looks like a poor design, please refactor */
static int thread_prepared[MCOUNT] = {0, };
static int thread_running[MCOUNT] = {0, };
static int thread_should_stop[MCOUNT] = {0, };
static struct task_struct *t[MCOUNT] = {NULL, };

static struct test_params tp[MCOUNT];
static int tcount;

void do_work(void)
{
int i, j;
int a = 0;

for (i = 0; i < 1000; i++)
for (j = 0; j < 1000; j++)
a = i * j;
}

int thread_fn(void *data)
{
int i;

void *k_addr[MCOUNT];
struct semaphore sem;
struct mutex lock;

struct test_params *tp;

tp = (struct test_params *)data;

thread_prepared[tp->idx] = 1;
wake_up_interruptible(&wq[tp->idx]);

wait_event_interruptible(wq[tp->idx], thread_running[tp->idx] == 1);

for (i = 0; i < tp->kcalls; i++)
k_addr[i] = kmalloc(tp->alloc[i], GFP_KERNEL);

/*XXX: do proper cleanup, avoid memory leaks */
for (i = 0; i < tp->kcalls; i++)
if (tp->free[i] && k_addr[i])
kfree(k_addr[i]);

for (i = 0; i < tp->sched; i++)
schedule();

/* TODO: use tp->down for down_interruptible */
sema_init(&sem, 1);
for (i = 0; i < tp->up; i++) {
up(&sem);
do_work();
down_interruptible(&sem);
}
/* TODO: use to->unlock for mutex_unlock */
mutex_init(&lock);
for (i = 0; i < tp->lock; i++) {
mutex_lock(&lock);
do_work();
mutex_unlock(&lock);
}

wait_event_interruptible(wq[tp->idx], thread_should_stop[tp->idx] == 1);

/* reset state machine */
thread_prepared[tp->idx] = 0;
thread_running[tp->idx] = 0;
thread_should_stop[tp->idx] = 0;

return 0;
}
static int helper_open(struct inode *inode, struct file *file)
{
#ifdef DEBUG
pr_info("tracer-helper: open\n");
#endif
return 0;
}

static int helper_release(struct inode *inode, struct file *file)
{
#ifdef DEBUG
pr_info("tracer-helper: close\n");
#endif
return 0;
}

static long helper_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int ret = 0;

switch (cmd) {
case PREPARE_TEST:
if (copy_from_user(&tp[tcount], (struct test_param *)arg,
sizeof(tp[tcount]))) {
pr_info("Error copy to user\n");
return -EFAULT;
}
t[tp[tcount].idx] = kthread_run(thread_fn, &tp[tcount], "%s",
tp[tcount].thread_name);
if (!t[tp[tcount].idx]) {
pr_info("Could not create thread!\n");
return -ENOMEM;
}

ret = t[tp[tcount].idx]->pid;
wait_event_interruptible(wq[tp[tcount].idx],
thread_prepared[tp[tcount].idx] == 1);
tcount++;
break;
case START_TEST:
#if 0
pr_info("%s: start test for idx %lu\n", __func__, arg);
#endif
thread_running[arg] = 1;
wake_up_interruptible(&wq[arg]);
break;
case STOP_TEST:
#if 0
pr_info("%s: stop test for idx %lu\n", __func__, arg);
#endif
thread_should_stop[arg] = 1;
wake_up_interruptible(&wq[arg]);
kthread_stop(t[arg]);
break;
default:
break;
}

return ret;
}

static const struct file_operations tracer_fops = {
.open = helper_open,
.unlocked_ioctl = helper_ioctl,
.release = helper_release,
};

static struct miscdevice helper_dev = {
.minor = HELPER_MINOR,
.name = "helper",
.fops = &tracer_fops,
};

static int __init tracer_helper_init(void)
{
int rc, i;

rc = misc_register(&helper_dev);
if (rc < 0) {
pr_err("misc_register: fail\n");
return rc;
}

for (i = 0; i < MCOUNT; i++)
init_waitqueue_head(&wq[i]);
#ifdef DEBUG
pr_info("tracer-helper: init\n");
#endif
return 0;
}

static void __exit tracer_helper_exit(void)
{
misc_deregister(&helper_dev);
#ifdef DEBUG
pr_info("tracer-helper: exit\n");
#endif
}

MODULE_AUTHOR("Daniel Baluta");
MODULE_LICENSE("GPL");

module_init(tracer_helper_init);
module_exit(tracer_helper_exit);
11 changes: 11 additions & 0 deletions tools/labs/templates/tracer_assignment/checker/_test/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#CPPFLAGS = -DDEBUG -DLOG_LEVEL=LOG_DEBUG
CFLAGS = -Wall -g -static -m32

.PHONY: all clean

all: tracer_test.o

stp_test.o: tracer_test.c tracer_test.h tracer.h test.h util.h debug.h

clean:
-rm -f *~ *.o
Loading

0 comments on commit 0865b29

Please sign in to comment.