#include #include #include #include #include #include #include "asm/cacheparams.h" #include #include "perfcounters.h" #include "color.h" #include "litmus.h" #define CPU 1 #define NR_LOOPS 10000 static int pages_per_datum; /* Number of pages in a "data" element, each with same color. */ static int nr_data; /* Number of "data" elements. */ struct page; #define NR_PAGE_INTS ((PAGE_SIZE - CACHE_LINE_SIZE) / sizeof(uint32_t)) struct page { struct page *ptr; struct page *_unused[CACHE_LINE_SIZE / sizeof(struct page*) - 1]; uint32_t ints[NR_PAGE_INTS]; }; struct datum { struct page *pages; }; /* * Get a random number in [0, max). Not really a good way to do this. */ static int randrange(const int max) { return (rand() / (RAND_MAX / max + 1)); } static void setup_page_ints(struct page *page) { int i; for (i = 0; i < NR_PAGE_INTS; i++) { page->ints[i] = randrange(RAND_MAX); } } /* * Sattolo's algorithm makes a random cycle that includes all the elements * in the items array. */ static void sattolo(int *items, const int len) { int i; /* first set up 0, 1, ..., n - 1 */ for (i = 0; i < len; i++) items[i] = i; /* note: i is now n */ while (1 < i--) { /* 0 <= j < i */ int t, j = randrange(i); t = items[i]; items[i] = items[j]; items[j] = t; } } static uint32_t get_sum(struct page *page) { uint32_t sum = 0; int i; for (i = 0; i < NR_PAGE_INTS; i += CACHE_LINE_SIZE / sizeof(uint32_t)) { sum += page->ints[i]; } return sum; } static uint32_t do_read(struct page* page) { struct page *old; uint32_t sum = 0; do { old = page; page = page->ptr; sum += get_sum(old); } while (page); return sum; } #define MULT 699050667 #define SHIFT 24 static inline int64_t clocksource_cyc2ns(cycles_t cycles, uint32_t mult, uint32_t shift) { return ((uint64_t) cycles * mult) >> shift; } #if 0 static void print_difference(const cycles_t start, const cycles_t end) { cycles_t diff = end - start; printf("difference: %10llu = %10llu ns\n", diff, clocksource_cyc2ns(diff, MULT, SHIFT)); } #endif #define quit_on_err(err, msg) do { \ if (err) { \ fprintf(stderr, "error: " msg); \ goto out; \ } \ } while (0) int main(int argc, char **argv) { struct color_ctrl_page *color_ctrl; struct datum *data; int *read_order; int i, j, err = 0; cycles_t start, end; uint32_t sum = 0; int64_t nanoseconds; double avg_nanoseconds; quit_on_err(PAGE_SIZE != sizeof(struct page), "PAGE_SIZE != sizeof(struct page)\n"); if (3 > argc) { fprintf(stderr, "%s: [pages-per-datum] [nr-data]\n", argv[0]); err = 1; goto out; } pages_per_datum = atoi(argv[1]); nr_data = atoi(argv[2]); quit_on_err(0 == nr_data || 0 == pages_per_datum, "zero argument\n"); quit_on_err(16 < nr_data, "too many nr_data\n"); read_order = malloc(pages_per_datum * sizeof(*read_order)); data = malloc(nr_data * sizeof(*data)); quit_on_err(!read_order || !data, "malloc\n"); err = be_migrate_to(CPU); quit_on_err(err, "migrate to cpu\n"); color_ctrl = get_color_ctrl(); if (!color_ctrl) { fprintf(stderr, "could not map color ctrl\n"); err = -1; goto out; } /* Always allocating this many pages of the same color. */ color_ctrl->pages[0] = pages_per_datum; for (i = 0; i < nr_data; i++) { const unsigned nr_bytes = sizeof(data[i].pages[0]) * pages_per_datum; /* give each datum its own color (XXX no checks to ensure not > * NR_COLORS!) */ color_ctrl->colors[0] = i; fprintf(stderr, "color_mallocing %u bytes\n", nr_bytes); data[i].pages = color_malloc(nr_bytes); if (!data[i].pages) { fprintf(stderr, "could not color malloc\n"); err = -1; goto out; } } sattolo(read_order, pages_per_datum); for (i = 0; i < nr_data; i++) { for (j = 0; j < pages_per_datum; j++) { if (0 != read_order[j]) { /* not the last element */ data[i].pages[j].ptr = &(data[i].pages[read_order[j]]); } else { /* last element in pages inside of datum walk */ if (nr_data - 1 == i) { /* last element globally */ data[i].pages[j].ptr = NULL; } else { /* jump to next datum */ data[i].pages[j].ptr = &(data[i + 1].pages[0]); } } setup_page_ints(&(data[i].pages[j])); } } #if 0 null_call(&start); null_call(&end); print_difference(start, end); null_call(&start); sum += do_read(data[0].pages); null_call(&end); print_difference(start, end); null_call(&start); sum += do_read(data[0].pages); null_call(&end); print_difference(start, end); null_call(&start); sum += do_read(data[0].pages); null_call(&end); print_difference(start, end); #endif null_call(&start); for (i = 0; i < NR_LOOPS; i++) { sum += do_read(data[0].pages); } null_call(&end); nanoseconds = clocksource_cyc2ns(end - start, MULT, SHIFT); avg_nanoseconds = ((double)nanoseconds) / NR_LOOPS; printf("%3d, %10.3f, %10.3f\n", nr_data, avg_nanoseconds, avg_nanoseconds / (nr_data * pages_per_datum)); out: return err; }