Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion include/coldtrace/entries.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#define PTR_MASK 0xFFFFFFFFFFFF0000UL
#define PTR_SHIFT_VALUE 16
#define ZERO_FLAG 0x80
#define INVALID_SIZE -1

#define COLDTRACE_FREE 0
#define COLDTRACE_ALLOC 1
Expand Down Expand Up @@ -50,7 +51,8 @@ const char *coldtrace_entry_type_str(coldtrace_entry_type type);

coldtrace_entry_type coldtrace_entry_parse_type(const void *buf);
uint64_t coldtrace_entry_parse_ptr(const void *buf);
size_t coldtrace_entry_parse_size(const void *buf);
size_t coldtrace_entry_get_size(const void *buf);
uint64_t coldtrace_entry_parse_size(const void *buf);

static inline struct coldtrace_entry_header
coldtrace_make_entry_header(const coldtrace_entry_type type, uint64_t ptr)
Expand Down
14 changes: 13 additions & 1 deletion src/entries.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,20 @@ coldtrace_entry_parse_ptr(const void *buf)
return (typed_ptr & PTR_MASK) >> PTR_SHIFT_VALUE;
}

size_t
uint64_t
coldtrace_entry_parse_size(const void *buf)
{
// alloc, mmap, munmap, read, write have size
int type = coldtrace_entry_parse_type(buf);
if (type == 1 || type == 2 || type == 3 || type == 22 || type == 23) {
uint64_t size = ((uint64_t *)buf)[1];
return size;
}
return INVALID_SIZE;
}

size_t
coldtrace_entry_get_size(const void *buf)
{
size_t next = 0;
switch (coldtrace_entry_parse_type(buf)) {
Expand Down
66 changes: 44 additions & 22 deletions test/checkers/trace_checker.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ struct next_expected_entry_iterator {
int atleast;
int atmost;
int check;
int size;
struct expected_entry *e;
};

Expand Down Expand Up @@ -91,7 +92,7 @@ iter_advance(struct entry_it *it)
if (it->size < sizeof(uint64_t))
return;

size_t size = coldtrace_entry_parse_size(it->buf);
size_t size = coldtrace_entry_get_size(it->buf);
if (size == 0)
return;
if (size > it->size)
Expand Down Expand Up @@ -131,6 +132,12 @@ iter_pointer_value(struct entry_it it)
return coldtrace_entry_parse_ptr(it.buf);
}

uint64_t
iter_size(struct entry_it it)
{
return coldtrace_entry_parse_size(it.buf);
}

static void
init_expected_entry_iterator(struct next_expected_entry_iterator *iter,
struct expected_entry *exp)
Expand All @@ -152,7 +159,7 @@ next_entry_and_reset(struct next_expected_entry_iterator *iter)
iter->check = iter->e->check;
}
static void
check_matching_ptr(coldtrace_entry_type type, uint64_t ptr_value,
check_matching_ptr(coldtrace_entry_type type, uint64_t ptr_value, uint64_t size,
struct next_expected_entry_iterator *iter, uint64_t tid,
int i)
{
Expand Down Expand Up @@ -180,11 +187,26 @@ check_matching_ptr(coldtrace_entry_type type, uint64_t ptr_value,
coldtrace_entry_type_str((iter->e)->type));
}
}

static void
_check_size(coldtrace_entry_type type, uint64_t ptr_value, uint64_t size,
struct next_expected_entry_iterator *iter, uint64_t tid, int i)
{
if ((iter->e)->size == INVALID_SIZE) {
return;
} else if (size != (uint64_t)(iter->e)->size) {
log_fatal("thread=%lu entry=%d size mismatch found=%lu expected=%d",
tid, i, size, (iter->e)->size);
} else if (size == (uint64_t)(iter->e)->size) {
log_info("thread=%lu entry=%d size match=%d", tid, i, (iter->e)->size);
}
}
static void _check_next(coldtrace_entry_type type, uint64_t ptr_value,
uint64_t size,
struct next_expected_entry_iterator *iter, uint64_t tid,
int i);
static void
_check_strict(coldtrace_entry_type type, uint64_t ptr_value,
_check_strict(coldtrace_entry_type type, uint64_t ptr_value, uint64_t size,
struct next_expected_entry_iterator *iter, uint64_t tid, int i)
{
bool mismatch = (type != (iter->e)->type);
Expand All @@ -201,18 +223,20 @@ _check_strict(coldtrace_entry_type type, uint64_t ptr_value,
if (next->set && next->atleast > 0 && type == next->type) {
// skip optional
next_entry_and_reset(iter);
_check_next(type, ptr_value, iter, tid, i);
_check_next(type, ptr_value, size, iter, tid, i);
return;
}
// advance pointer
next_entry_and_reset(iter);
log_warn("%lu event mismatch (go to next)", tid);
_check_next(type, ptr_value, iter, tid, i);
_check_next(type, ptr_value, size, iter, tid, i);
return;
}

// matched
check_matching_ptr(type, ptr_value, iter, tid, i);
check_matching_ptr(type, ptr_value, size, iter, tid, i);

_check_size(type, ptr_value, size, iter, tid, i);

// if it was required make it optional
if (iter->atleast > 0)
Expand All @@ -225,7 +249,7 @@ _check_strict(coldtrace_entry_type type, uint64_t ptr_value,
next_entry_and_reset(iter);
}
static void
_check_wildcard(coldtrace_entry_type type, uint64_t ptr_value,
_check_wildcard(coldtrace_entry_type type, uint64_t ptr_value, uint64_t size,
struct next_expected_entry_iterator *iter, uint64_t tid, int i)
{
struct expected_entry *wild = (iter->e);
Expand All @@ -240,20 +264,24 @@ _check_wildcard(coldtrace_entry_type type, uint64_t ptr_value,
if (wild->check == NO_CHECK) {
log_info("thread=%lu entry=%d wildcard match=%s", tid, i,
coldtrace_entry_type_str(wild->type));
_check_size(type, ptr_value, size, iter, tid, i);
next_entry_and_reset(iter);
return;
}

// check the ptr
uint64_t *check_val = &_entry_ptr_values[wild->check];
if (*check_val == CHECK_UNINITIALIZED) {
*check_val = ptr_value;
log_info("thread=%lu entry=%d wildcard match=%s match=ptr=%lu", tid, i,
coldtrace_entry_type_str(wild->type), ptr_value);
_check_size(type, ptr_value, size, iter, tid, i);
next_entry_and_reset(iter);
} else if (*check_val == ptr_value) {
// ptr match
log_info("thread=%lu entry=%d wildcard match=%s match=ptr=%lu", tid, i,
coldtrace_entry_type_str(wild->type), ptr_value);
_check_size(type, ptr_value, size, iter, tid, i);
next_entry_and_reset(iter);
} else {
// ptr mismatch
Expand All @@ -266,15 +294,15 @@ _check_wildcard(coldtrace_entry_type type, uint64_t ptr_value,
}

static void
_check_next(coldtrace_entry_type type, uint64_t ptr_value,
_check_next(coldtrace_entry_type type, uint64_t ptr_value, uint64_t size,
struct next_expected_entry_iterator *iter, uint64_t tid, int i)
{
if (!(iter->e)->wild) {
// wild false
_check_strict(type, ptr_value, iter, tid, i);
_check_strict(type, ptr_value, size, iter, tid, i);
} else {
// wild true
_check_wildcard(type, ptr_value, iter, tid, i);
_check_wildcard(type, ptr_value, size, iter, tid, i);
}
}
// -----------------------------------------------------------------------------
Expand All @@ -288,31 +316,25 @@ coldtrace_writer_close(void *page, const size_t size, uint64_t tid)
static caslock_t loop_lock = CASLOCK_INIT();

log_info("checking thread=%lu", tid);
struct entry_it it = iter_init(page, size);
struct expected_entry *next = _expected[tid];
struct entry_it it = iter_init(page, size);
struct expected_entry *exp = _expected[tid];
struct next_expected_entry_iterator *expected_it =
&_expected_iterators[tid];

// Initialize only once
if (expected_it->e == NULL && next != NULL) {
init_expected_entry_iterator(expected_it, next);
if (expected_it->e == NULL && exp != NULL) {
init_expected_entry_iterator(expected_it, exp);
}

if (_close_callback)
_close_callback(page, size);

caslock_acquire(&loop_lock);

struct entry_it print_it = iter_init(page, size);
for (int i = 0; iter_next(print_it); iter_advance(&print_it), i++) {
coldtrace_entry_type type = iter_type(print_it);
log_info("thread=%lu entry=%d %s %lu", tid, i,
coldtrace_entry_type_str(type), iter_pointer_value(print_it));
}

for (int i = 0; iter_next(it); iter_advance(&it), i++) {
coldtrace_entry_type type = iter_type(it);
uint64_t ptr_value = iter_pointer_value(it);
uint64_t size = iter_size(it);

for (size_t j = 0; j < _entry_callback_count; j++)
_entry_callbacks[j](it.buf);
Expand All @@ -326,7 +348,7 @@ coldtrace_writer_close(void *page, const size_t size, uint64_t tid)
continue;
}

_check_next(type, ptr_value, expected_it, tid, i);
_check_next(type, ptr_value, size, expected_it, tid, i);
}

for (uint64_t t = 0; t < MAX_NTHREADS; t++) {
Expand Down
39 changes: 32 additions & 7 deletions test/checkers/trace_checker.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,43 +24,68 @@ struct expected_entry {
unsigned atmost;
bool wild;
int check; // for pointer: -1 = no check , != -1 = check on that location
int size;
};

#define EXPECT_ENTRY(TYPE) \
(struct expected_entry) \
{ \
.type = TYPE, .set = true, .atleast = 1, .atmost = 1, .wild = false, \
.check = -1 \
.check = -1, .size = -1 \
}
#define EXPECT_VALUE(TYPE, CHECK) \
(struct expected_entry) \
{ \
.type = TYPE, .set = true, .atleast = 1, .atmost = 1, .wild = false, \
.check = CHECK \
.check = CHECK, .size = -1, \
}
#define EXPECT_SIZE(TYPE, SIZE) \
(struct expected_entry) \
{ \
.type = TYPE, .set = true, .atleast = 1, .atmost = 1, .wild = false, \
.check = -1, .size = SIZE \
}
#define EXPECT_VALUE_SIZE(TYPE, CHECK, SIZE) \
(struct expected_entry) \
{ \
.type = TYPE, .set = true, .atleast = 1, .atmost = 1, .wild = false, \
.check = CHECK, .size = SIZE \
}
#define EXPECT_SUFFIX(TYPE) \
(struct expected_entry) \
{ \
.type = TYPE, .set = true, .atleast = 1, .atmost = 1, .wild = true, \
.check = -1, \
.check = -1, .size = -1, \
}
#define EXPECT_SUFFIX_VALUE(TYPE, CHECK) \
(struct expected_entry) \
{ \
.type = TYPE, .set = true, .atleast = 1, .atmost = 1, .wild = true, \
.check = CHECK, \
.check = CHECK, .size = -1, \
}
#define EXPECT_SOME(TYPE, ATLEAST, ATMOST) \
(struct expected_entry) \
{ \
.type = TYPE, .set = true, .atleast = ATLEAST, .atmost = ATMOST, \
.wild = false, .check = -1, \
.wild = false, .check = -1, .size = -1, \
}
#define EXPECT_SOME_VALUE(TYPE, ATLEAST, ATMOST, CHECK) \
(struct expected_entry) \
{ \
.type = TYPE, .set = true, .atleast = ATLEAST, .atmost = ATMOST, \
.wild = false, .check = CHECK, \
.wild = false, .check = CHECK, .size = -1, \
}
#define EXPECT_SOME_SIZE(TYPE, ATLEAST, ATMOST, SIZE) \
(struct expected_entry) \
{ \
.type = TYPE, .set = true, .atleast = ATLEAST, .atmost = ATMOST, \
.wild = false, .check = -1, .size = SIZE, \
}
#define EXPECT_SOME_VALUE_SIZE(TYPE, ATLEAST, ATMOST, CHECK, SIZE) \
(struct expected_entry) \
{ \
.type = TYPE, .set = true, .atleast = ATLEAST, .atmost = ATMOST, \
.wild = false, .check = CHECK, .size = SIZE, \
}

#define EXPECTED_ANY_SUFFIX EXPECT_SUFFIX(0, 0)
Expand All @@ -69,7 +94,7 @@ struct expected_entry {
(struct expected_entry) \
{ \
.type = 0, .set = false, .atleast = 0, .atmost = 0, .wild = false, \
.check = -1 \
.check = -1, .size = -1 \
}

void register_expected_trace(uint64_t tid, struct expected_entry *trace);
Expand Down
4 changes: 3 additions & 1 deletion test/trace_atomic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@

#define ATOMIC_RW_CYCLE \
EXPECT_SUFFIX_VALUE(COLDTRACE_ATOMIC_READ, 5), \
EXPECT_SUFFIX_VALUE(COLDTRACE_ATOMIC_WRITE, 5)
EXPECT_SUFFIX_VALUE(COLDTRACE_ATOMIC_WRITE, 5), \
EXPECT_SOME_SIZE(COLDTRACE_READ, 0, 1, sizeof(uint8_t)), \
EXPECT_SOME_SIZE(COLDTRACE_WRITE, 0, 1, sizeof(uint8_t))

struct expected_entry expected_1[] = {
EXPECT_SOME_VALUE(COLDTRACE_ALLOC, 0, 1, 0),
Expand Down
2 changes: 0 additions & 2 deletions test/trace_fence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ struct expected_entry expected_3[] = {
EXPECT_VALUE(COLDTRACE_ATOMIC_READ, 1),
EXPECT_VALUE(COLDTRACE_ATOMIC_READ, 2),
EXPECT_VALUE(COLDTRACE_FENCE, 6),
EXPECT_SOME(COLDTRACE_WRITE, 0, 1),
EXPECT_SOME(COLDTRACE_READ, 0, 2),
EXPECT_SUFFIX_VALUE(COLDTRACE_THREAD_EXIT, 4),
EXPECT_END,
};
Expand Down
40 changes: 40 additions & 0 deletions test/trace_read_write_size.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include <trace_checker.h>

struct expected_entry expected_1[] = {
EXPECT_SOME(COLDTRACE_ALLOC, 0, 1),
EXPECT_VALUE_SIZE(COLDTRACE_ALLOC, 0, 10 * sizeof(int)),
EXPECT_VALUE_SIZE(COLDTRACE_WRITE, 0, sizeof(int)),
EXPECT_SOME_SIZE(COLDTRACE_WRITE, 9, 9, sizeof(int)),
EXPECT_VALUE_SIZE(COLDTRACE_READ, 0, sizeof(int)),
EXPECT_SOME(COLDTRACE_ALLOC, 0, 1),
EXPECT_SOME_SIZE(COLDTRACE_READ, 9, 9, sizeof(int)),
EXPECT_ENTRY(COLDTRACE_FREE),
EXPECT_ENTRY(COLDTRACE_THREAD_EXIT),
EXPECT_END,
};

int
main(void)
{
register_expected_trace(1, expected_1);

// alloc
int *arr = (int *)malloc(10 * sizeof(int));
if (!arr) {
log_fatal("malloc failed");
return 1;
}

for (int i = 0; i < 10; i++) {
arr[i] = i * 2; // write
}

for (int i = 0; i < 10; i++) {
printf("arr[%d] = %d\n", i, arr[i]); // read
}

// free
free(arr);

return 0;
}