1/** 2 * \file 3 * \brief APIC timer drift benchmark 4 */ 5 6/* 7 * Copyright (c) 2009, 2010, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <stdio.h> 16#include <inttypes.h> 17#include <barrelfish/barrelfish.h> 18#include <barrelfish/waitset.h> 19#include <barrelfish/sys_debug.h> 20#include <bench/bench.h> 21 22/// Number of iterations (experiment will run for 12 hours) 23#define ITERATIONS 43200 24//#define ITERATIONS 10 25 26/// Delay between iterations in milliseconds 27#define DELAY 1000 28 29typedef volatile uintptr_t spinflag_t; 30 31union padstruct { 32 spinflag_t start; 33 uint8_t pad[64]; 34}; 35 36static int init_done = 1; 37static union padstruct startflag[MAX_CPUS] __attribute__ ((aligned(64))); 38static uint32_t timestamp[MAX_CPUS][ITERATIONS]; 39static int nthreads; 40static uint64_t tscperms = 0; 41 42static void domain_spanned(void *arg, errval_t reterr) 43{ 44 assert(err_is_ok(reterr)); 45 init_done++; 46} 47 48static int apic_measure_loop(void *arg) 49{ 50 coreid_t mycore = disp_get_core_id(), 51 nextcore = (mycore + 1) % nthreads; 52 uint64_t lasttsc = 0, iteration = 0, tscdelay = DELAY * tscperms; 53 54 for(;;) { 55 if(mycore != 0 || lasttsc != 0) { 56 // Wait for signal and reset 57 while(startflag[mycore].start == 0); 58 startflag[mycore].start = 0; 59 } 60 61 // Get local APIC timer value 62 errval_t err = sys_debug_get_apic_timer(×tamp[mycore][iteration]); 63 assert(err_is_ok(err)); 64 65 iteration++; 66 67 if(mycore == 0 && lasttsc != 0) { // Master 68 if(iteration == ITERATIONS) { 69 // We're done 70 return 0; 71 } 72 73 // Wait for rest of DELAY 74 uint64_t tscnow; 75 76 do { 77 tscnow = rdtsc(); 78 } while(tscnow < lasttsc + tscdelay); 79 80 lasttsc = tscnow; 81 } else { 82 lasttsc = rdtsc(); 83 } 84 85 // Signal next core 86 startflag[nextcore].start = 1; 87 } 88 89 return 0; 90} 91 92int main(int argc, char *argv[]) 93{ 94 int my_core_id = disp_get_core_id(); 95 errval_t err; 96 97 if(argc < 2) { 98 printf("Usage: %s threads\n", argv[0]); 99 } 100 nthreads = atoi(argv[1]); 101 102 err = sys_debug_get_tsc_per_ms(&tscperms); 103 assert(err_is_ok(err)); 104 105 uint32_t tickspersec; 106 err = sys_debug_get_apic_ticks_per_sec(&tickspersec); 107 assert(err_is_ok(err)); 108 printf("APIC ticks per second: %" PRIu32 "\n", tickspersec); 109 110 bench_init(); 111 112 /* Span domain to all cores */ 113 for (int i = my_core_id + 1; i < nthreads + my_core_id; i++) { 114 err = domain_new_dispatcher(i, domain_spanned, NULL); 115 if (err_is_fail(err)) { 116 DEBUG_ERR(err, "failed to span domain"); 117 } 118 assert(err_is_ok(err)); 119 } 120 121 while(init_done < nthreads) { 122 thread_yield(); 123 } 124 125 // Start all threads 126 for (int i = my_core_id + 1; i < nthreads + my_core_id; i++) { 127 err = domain_thread_create_on(i, apic_measure_loop, NULL, NULL); 128 assert(err_is_ok(err)); 129 } 130 131 // Start locally 132 apic_measure_loop(NULL); 133 134 printf("Running on %d cores.\n", nthreads); 135 136 // Output data 137 for(uint64_t i = 0; i < ITERATIONS; i++) { 138 printf("%" PRIu64 ": ", i); 139 for(int n = 0; n < nthreads; n++) { 140 printf("%" PRIu32 " ", timestamp[n][i]); 141 } 142 printf("\n"); 143 } 144 145 printf("client done.\n"); 146 return 0; 147} 148