Skip to content

Commit

Permalink
Rewrite with circular doubly-linked list
Browse files Browse the repository at this point in the history
In original CMU assignment, a singly-linked list was used. However,
toward to Linux kernel development, we would like to stick to its linked
list implementation. That is, we take the circular doubly-linked list to
re-implement the queue oriented operations. In addition, we introduce
some LeetCode exercises based on Linux-like lists.

Now, queue is replaced with linux kernel linked list. Also, implementation
of l_new, l_free, l_insert_head, l_insert_tail, l_remove_head and l_size
are added.

Implementation of l_sort and l_reverse are added.

Add command "mid" which would return the middle element in list.
Relative test also be added in this commit

Add command "swap" which would swap every two adjacent nodes in list.
Relative test also be added in this commit.
Reference:
    https://leetcode.com/problems/swap-nodes-in-pairs/

Replace "get_mid" with "remove_mid", which is LeetCode problem.
Relative test bench also be updated in this commit.
Reference:
    https://leetcode.com/problems/delete-the-middle-node-of-a-linked-list/

Add command remove_tail.

Suppress the null pointer errors

Newer versions of cppcheck find the potential NULL pointer
bug in list_entry. The function is difficult to refactor without
extensive work, so suppress the potential NULL pointer error
which cannot occur for now.

remove_tail and remove_head was re-desinged. We extract "free" from
remove_.* because "free" is not stable (lead not constant time).
Relative testbench also update in this commit.

Add function "is_circular" which check if the queue is doubly circular.

Suppress simulation of list removal on Arm64

We suffered from some unknown issues that simulation of list removal can
not pass on Arm64 based platforms such as ThunderX2/Linux and Apple M1
(macOS).

At the moment, we just skip the simulations for Arm64.

We support new command: dedup.
Relative test bench also be updated.

Co-authored-by: eecheng87 <[email protected]>
  • Loading branch information
jserv and eecheng87 committed Feb 14, 2022
1 parent d941f0c commit 284f69d
Show file tree
Hide file tree
Showing 34 changed files with 1,228 additions and 406 deletions.
12 changes: 12 additions & 0 deletions .ci/check-format.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash

SOURCES=$(find $(git rev-parse --show-toplevel) | egrep "\.(cpp|h)\$")

set -x

for file in ${SOURCES};
do
clang-format-12 ${file} > expected-format
diff -u -p --label="${file}" --label="expected coding style" ${file} expected-format
done
exit $(clang-format-12 --output-replacements-xml ${SOURCES} | egrep -c "</replacement>")
12 changes: 12 additions & 0 deletions .ci/check-sanity.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash

SHA1SUM=$(which sha1sum)
if [ $? -ne 0 ]; then
SHA1SUM=shasum
fi

$SHA1SUM -c scripts/checksums
if [ $? -ne 0 ]; then
echo "[!] You are not allowed to change the header file queue.h or list.h" >&2
exit 1
fi
11 changes: 11 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,14 @@ UseTab: Never
IndentWidth: 4
BreakBeforeBraces: Linux
AccessModifierOffset: -4
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
- list_for_each
- list_for_each_safe
- list_for_each_entry
- list_for_each_entry_safe
- hlist_for_each_entry
- rb_list_foreach
- rb_list_foreach_safe
30 changes: 30 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: CI

on: [push, pull_request]

jobs:
lab0-c:
runs-on: ubuntu-20.04
steps:
- uses: actions/[email protected]
- name: install-dependencies
run: |
.ci/check-sanity.sh
sudo apt-get update
sudo apt-get -q -y install build-essential cppcheck
- name: make
run: make
- name: make check
run: make check
- name: make test
run: make test

coding-style:
runs-on: ubuntu-20.04
steps:
- uses: actions/[email protected]
- name: coding convention
run: |
sudo apt-get install -q -y clang-format-12
sh .ci/check-format.sh
shell: bash
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ of the skills tested are:
* Implementing robust code that operates correctly with invalid arguments, including NULL pointers.

The lab involves implementing a queue, supporting both last-in, first-out (LIFO) and first-in-first-out (FIFO)
queueing disciplines. The underlying data structure is a singly-linked list, enhanced to make some of the
operations more efficient.
queueing disciplines. The underlying data structure is a circular doubly-linked list, enhanced to make some of
the operations more efficient.

## Prerequisites

Expand Down
74 changes: 32 additions & 42 deletions console.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,48 +69,13 @@ static bool has_infile = false;
static cmd_function quit_helpers[MAXQUIT];
static int quit_helper_cnt = 0;

static bool do_quit_cmd(int argc, char *argv[]);
static bool do_help_cmd(int argc, char *argv[]);
static bool do_option_cmd(int argc, char *argv[]);
static bool do_source_cmd(int argc, char *argv[]);
static bool do_log_cmd(int argc, char *argv[]);
static bool do_time_cmd(int argc, char *argv[]);
static bool do_comment_cmd(int argc, char *argv[]);

static void init_in();

static bool push_file(char *fname);
static void pop_file();

static bool interpret_cmda(int argc, char *argv[]);

/* Initialize interpreter */
void init_cmd()
{
cmd_list = NULL;
param_list = NULL;
err_cnt = 0;
quit_flag = false;

add_cmd("help", do_help_cmd, " | Show documentation");
add_cmd("option", do_option_cmd,
" [name val] | Display or set options");
add_cmd("quit", do_quit_cmd, " | Exit program");
add_cmd("source", do_source_cmd,
" file | Read commands from source file");
add_cmd("log", do_log_cmd, " file | Copy output to file");
add_cmd("time", do_time_cmd, " cmd arg ... | Time command execution");
add_cmd("#", do_comment_cmd, " ... | Display comment");
add_param("simulation", &simulation, "Start/Stop simulation mode", NULL);
add_param("verbose", &verblevel, "Verbosity level", NULL);
add_param("error", &err_limit, "Number of errors until exit", NULL);
add_param("echo", &echo, "Do/don't echo commands", NULL);

init_in();
init_time(&last_time);
first_time = last_time;
}

/* Add a new command */
void add_cmd(char *name, cmd_function operation, char *documentation)
{
Expand Down Expand Up @@ -264,7 +229,7 @@ void set_echo(bool on)
}

/* Built-in commands */
static bool do_quit_cmd(int argc, char *argv[])
static bool do_quit(int argc, char *argv[])
{
cmd_ptr c = cmd_list;
bool ok = true;
Expand Down Expand Up @@ -292,7 +257,7 @@ static bool do_quit_cmd(int argc, char *argv[])
return ok;
}

static bool do_help_cmd(int argc, char *argv[])
static bool do_help(int argc, char *argv[])
{
cmd_ptr clist = cmd_list;
report(1, "Commands:", argv[0]);
Expand Down Expand Up @@ -336,7 +301,7 @@ bool get_int(char *vname, int *loc)
return true;
}

static bool do_option_cmd(int argc, char *argv[])
static bool do_option(int argc, char *argv[])
{
if (argc == 1) {
param_ptr plist = param_list;
Expand Down Expand Up @@ -383,7 +348,7 @@ static bool do_option_cmd(int argc, char *argv[])
return true;
}

static bool do_source_cmd(int argc, char *argv[])
static bool do_source(int argc, char *argv[])
{
if (argc < 2) {
report(1, "No source file given");
Expand All @@ -398,7 +363,7 @@ static bool do_source_cmd(int argc, char *argv[])
return true;
}

static bool do_log_cmd(int argc, char *argv[])
static bool do_log(int argc, char *argv[])
{
if (argc < 2) {
report(1, "No log file given");
Expand All @@ -412,7 +377,7 @@ static bool do_log_cmd(int argc, char *argv[])
return result;
}

static bool do_time_cmd(int argc, char *argv[])
static bool do_time(int argc, char *argv[])
{
double delta = delta_time(&last_time);
bool ok = true;
Expand All @@ -432,6 +397,31 @@ static bool do_time_cmd(int argc, char *argv[])
return ok;
}

/* Initialize interpreter */
void init_cmd()
{
cmd_list = NULL;
param_list = NULL;
err_cnt = 0;
quit_flag = false;

ADD_COMMAND(help, " | Show documentation");
ADD_COMMAND(option, " [name val] | Display or set options");
ADD_COMMAND(quit, " | Exit program");
ADD_COMMAND(source, " file | Read commands from source file");
ADD_COMMAND(log, " file | Copy output to file");
ADD_COMMAND(time, " cmd arg ... | Time command execution");
add_cmd("#", do_comment_cmd, " ... | Display comment");
add_param("simulation", &simulation, "Start/Stop simulation mode", NULL);
add_param("verbose", &verblevel, "Verbosity level", NULL);
add_param("error", &err_limit, "Number of errors until exit", NULL);
add_param("echo", &echo, "Do/don't echo commands", NULL);

init_in();
init_time(&last_time);
first_time = last_time;
}

/* Create new buffer for named file.
* Name == NULL for stdin.
* Return true if successful.
Expand Down Expand Up @@ -600,7 +590,7 @@ bool finish_cmd()
{
bool ok = true;
if (!quit_flag)
ok = ok && do_quit_cmd(0, NULL);
ok = ok && do_quit(0, NULL);
has_infile = false;
return ok && err_cnt == 0;
}
Expand Down
1 change: 1 addition & 0 deletions console.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ void init_cmd();

/* Add a new command */
void add_cmd(char *name, cmd_function operation, char *documentation);
#define ADD_COMMAND(cmd, msg) add_cmd(#cmd, do_##cmd, msg)

/* Add a new parameter */
void add_param(char *name,
Expand Down
86 changes: 71 additions & 15 deletions dudect/constant.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,53 @@
#include "queue.h"
#include "random.h"

#define NR_MEASURE 150
#define N_MEASURE 150

/* Allow random number range from 0 to 65535 */
const size_t chunk_size = 16;

/* Number of measurements per test */
const size_t number_measurements = NR_MEASURE;
const size_t n_measure = N_MEASURE;

const int drop_size = 20;

/* Maintain a queue independent from the qtest since
* we do not want the test to affect the original functionality
*/
static queue_t *q = NULL;
static char random_string[NR_MEASURE][8];
static struct list_head *l = NULL;

static char random_string[N_MEASURE][8];
static int random_string_iter = 0;
enum { test_insert_tail, test_size };

enum {
test_insert_head,
test_insert_tail,
test_remove_head,
test_remove_tail,
};

/* Implement the necessary queue interface to simulation */
void init_dut(void)
{
q = NULL;
l = NULL;
}

char *get_random_string(void)
{
random_string_iter = (random_string_iter + 1) % NR_MEASURE;
random_string_iter = (random_string_iter + 1) % N_MEASURE;
return random_string[random_string_iter];
}

void prepare_inputs(uint8_t *input_data, uint8_t *classes)
{
randombytes(input_data, number_measurements * chunk_size);
for (size_t i = 0; i < number_measurements; i++) {
randombytes(input_data, n_measure * chunk_size);
for (size_t i = 0; i < n_measure; i++) {
classes[i] = randombit();
if (classes[i] == 0)
memset(input_data + (size_t) i * chunk_size, 0, chunk_size);
}

for (size_t i = 0; i < NR_MEASURE; ++i) {
for (size_t i = 0; i < N_MEASURE; ++i) {
/* Generate random string */
randombytes((uint8_t *) random_string[i], 7);
random_string[i][7] = 0;
Expand All @@ -57,9 +68,25 @@ void measure(int64_t *before_ticks,
uint8_t *input_data,
int mode)
{
assert(mode == test_insert_tail || mode == test_size);
if (mode == test_insert_tail) {
for (size_t i = drop_size; i < number_measurements - drop_size; i++) {
assert(mode == test_insert_head || mode == test_insert_tail ||
mode == test_remove_head || mode == test_remove_tail);

switch (mode) {
case test_insert_head:
for (size_t i = drop_size; i < n_measure - drop_size; i++) {
char *s = get_random_string();
dut_new();
dut_insert_head(
get_random_string(),
*(uint16_t *) (input_data + i * chunk_size) % 10000);
before_ticks[i] = cpucycles();
dut_insert_head(s, 1);
after_ticks[i] = cpucycles();
dut_free();
}
break;
case test_insert_tail:
for (size_t i = drop_size; i < n_measure - drop_size; i++) {
char *s = get_random_string();
dut_new();
dut_insert_head(
Expand All @@ -70,8 +97,37 @@ void measure(int64_t *before_ticks,
after_ticks[i] = cpucycles();
dut_free();
}
} else {
for (size_t i = drop_size; i < number_measurements - drop_size; i++) {
break;
case test_remove_head:
for (size_t i = drop_size; i < n_measure - drop_size; i++) {
dut_new();
dut_insert_head(
get_random_string(),
*(uint16_t *) (input_data + i * chunk_size) % 10000);
before_ticks[i] = cpucycles();
element_t *e = q_remove_head(l, NULL, 0);
after_ticks[i] = cpucycles();
if (e)
q_release_element(e);
dut_free();
}
break;
case test_remove_tail:
for (size_t i = drop_size; i < n_measure - drop_size; i++) {
dut_new();
dut_insert_head(
get_random_string(),
*(uint16_t *) (input_data + i * chunk_size) % 10000);
before_ticks[i] = cpucycles();
element_t *e = q_remove_tail(l, NULL, 0);
after_ticks[i] = cpucycles();
if (e)
q_release_element(e);
dut_free();
}
break;
default:
for (size_t i = drop_size; i < n_measure - drop_size; i++) {
dut_new();
dut_insert_head(
get_random_string(),
Expand Down
Loading

0 comments on commit 284f69d

Please sign in to comment.