1/* 2 * Copyright (c) 2014, ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 8 */ 9#define _GNU_SOURCE 10 11#include <stdlib.h> 12#include <stdio.h> 13#include <stdint.h> 14#include <string.h> 15#include <assert.h> 16#include <stdbool.h> 17#include <sys/time.h> 18 19#include <sched.h> /* CPU_SET et. al. */ 20#include <pthread.h> 21 22#ifdef BARRELFISH 23#include <barrelfish/barrelfish.h> 24#include <octopus/octopus.h> 25#else 26#define MAX_COREID 1024 27#define USER_PANIC_ERR(x...) 28#define USER_PANIC(x...) 29#define err_is_fail(x) false 30typedef size_t errval_t; 31#endif 32 33#define NUM_INCR 1000000 34static size_t sanity = 0; 35static size_t cpu_count = 4; 36 37static void* prj_thread(void* param) 38{ 39#if BARRELFISH 40 printf("Hello from thread %"PRIu64" on core %"PRIuCOREID"\n", 41 (uint64_t)param, disp_get_core_id()); 42#endif 43 sanity = 1; 44 //messages_handler_loop(); 45 return 0; 46} 47 48static int pthread_create_join_test(void) { 49 pthread_t tid; 50 pthread_attr_t attr; 51 pthread_attr_init(&attr); 52 53 for (size_t rep = 0; rep < 20; rep++) { 54 printf("Create a new thread rep=%zu\n", rep); 55 int rv = pthread_create(&tid, &attr, prj_thread, NULL); 56 if (rv){ 57 printf("[ERROR] return code from pthread_create() is %d\n", rv); 58 return 1; 59 } 60 61 /* wait for threads to finish */ 62 pthread_join(tid, NULL); 63 64 assert(sanity == 1); 65 sanity = 0; 66 printf("Joined thread.\n"); 67 } 68 69 printf("%s PASS\n", __FUNCTION__); 70 return 0; 71} 72 73static int pthread_setaffinity_test(void) { 74 75 pthread_t tid; 76 pthread_attr_t attr; 77 pthread_attr_init(&attr); 78 cpu_set_t set; 79 80 for (size_t rep = 0; rep < cpu_count; rep++) { 81 printf("Create a new thread on core %zu\n", rep); 82 sanity = 0; 83 84 CPU_ZERO(&set); 85 CPU_SET(rep, &set); 86 pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &set); 87 int rv = pthread_create(&tid, &attr, prj_thread, NULL); 88 if (rv){ 89 printf("[ERROR] return code from pthread_create() is %d\n", rv); 90 return 1; 91 } 92 93 /* wait for threads to finish */ 94 pthread_join(tid, NULL); 95 //assert(sanity == 1); 96 } 97 98 printf("%s PASS\n", __FUNCTION__); 99 return 0; 100} 101 102static pthread_mutex_t lock; 103 104static size_t atomic_counter; 105static void* mutex_increment(void* param) 106{ 107 struct timeval start; 108 struct timeval end; 109 110 gettimeofday(&start, NULL); 111 for (size_t i=0; i < NUM_INCR; i++) { 112 pthread_mutex_lock(&lock); 113 if (atomic_counter % 10000 == 0) { 114 debug_printf("progress\n"); 115 } 116 atomic_counter++; 117 pthread_mutex_unlock(&lock); 118 } 119 gettimeofday(&end, NULL); 120 121 assert(atomic_counter >= NUM_INCR); 122 double diff_usec = (((end).tv_sec*1000000L + (end).tv_usec) - ((start).tv_sec*1000000L+(start).tv_usec)); 123 124 debug_printf("%s:%s:%d: end-start [usec] = %.4lf\n", 125 __FILE__, __FUNCTION__, __LINE__, diff_usec); 126 127 return 0; 128} 129 130static int pthread_mutex_performance(void) { 131 pthread_t tid[cpu_count]; 132 pthread_attr_t attr; 133 pthread_attr_init(&attr); 134 pthread_mutex_init(&lock, NULL); 135 cpu_set_t set; 136 137 for (size_t rep = 0; rep < cpu_count; rep++) { 138 printf("Create a new thread on core %zu\n", rep); 139 CPU_ZERO(&set); 140 CPU_SET(rep, &set); 141 pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &set); 142 int rv = pthread_create(&tid[rep], &attr, mutex_increment, NULL); 143 if (rv){ 144 printf("[ERROR] return code from pthread_create() is %d\n", rv); 145 return 1; 146 } 147 } 148 for (size_t rep = 0; rep < cpu_count; rep++) { 149 printf("%s:%s:%d: waiting for %zu\n", __FILE__, __FUNCTION__, __LINE__, rep); 150 pthread_join(tid[rep], NULL); 151 } 152 assert(atomic_counter == cpu_count*NUM_INCR); 153 154 155 printf("%s PASS\n", __FUNCTION__); 156 157 return 0; 158} 159 160static bool is_spanned[MAX_COREID] = { false }; 161 162static void domain_spanned_callback(void *arg, errval_t err) 163{ 164 if (err_is_fail(err)) { 165 USER_PANIC_ERR(err, "domain spanning failed."); 166 } 167 uintptr_t i = (uintptr_t) arg; 168 is_spanned[i] = true; 169} 170 171int main(int argc, char** argv) 172{ 173 int r = 0; 174#ifdef BARRELFISH 175 oct_init(); 176 static char* local_apics = "r'hw\\.processor\\.[0-9]+' { enabled: 1 }"; 177 char** names; 178 errval_t err = oct_get_names(&names, &cpu_count, local_apics); 179 if (err_is_fail(err)) { 180 DEBUG_ERR(err, "Can not get core count"); 181 return 1; 182 } 183 oct_free_names(names, cpu_count); 184 185 // Spawn to other cores: 186 for (size_t rep = 0; rep < cpu_count; rep++) { 187 if (rep != disp_get_core_id()) { 188 err = domain_new_dispatcher(rep, domain_spanned_callback, (void*)(uintptr_t)rep); 189 if (err_is_fail(err)) { 190 USER_PANIC_ERR(err, "domain_new_dispatcher failed"); 191 } 192 193 while (!is_spanned[rep]) { 194 thread_yield(); 195 } 196 } 197 } 198#endif 199 200 r = pthread_mutex_performance(); 201 if (r != 0) { 202 USER_PANIC("pthread_mutex_performance failed"); 203 } 204 205 r = pthread_setaffinity_test(); 206 if (r != 0) { 207 USER_PANIC("pthread_setaffinity_test failed"); 208 } 209 210 r = pthread_create_join_test(); 211 if (r != 0) { 212 USER_PANIC("pthread_create_join_test failed"); 213 } 214 215 printf("TESTS PASSED\n"); 216 217#ifdef BARRELFISH 218 // XXX: threads on remote cores page-fault if parent exits :( 219 messages_handler_loop(); 220#endif 221 return 0; 222}