testutil.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2007, Google Inc. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met: 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions of source code must retain the above copyright 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions in binary form must reproduce the above 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer 127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// in the documentation and/or other materials provided with the 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// distribution. 141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// * Neither the name of Google Inc. nor the names of its 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contributors may be used to endorse or promote products derived from 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this software without specific prior written permission. 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// --- 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: Craig Silverstein 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A few routines that are useful for multiple tests in this directory. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "config_for_unittests.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h> // for NULL, abort() 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On FreeBSD, if you #include <sys/resource.h>, you have to get stdint first. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_STDINT_H 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdint.h> 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_SYS_RESOURCE_H 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/resource.h> 43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "tests/testutil.h" 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// When compiled 64-bit and run on systems with swap several unittests will end 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// up trying to consume all of RAM+swap, and that can take quite some time. By 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// limiting the address-space size we get sufficient coverage without blowing 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// out job limits. 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetTestResourceLimit() { 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_SYS_RESOURCE_H 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The actual resource we need to set varies depending on which flavour of 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // unix. On Linux we need RLIMIT_AS because that covers the use of mmap. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Otherwise hopefully RLIMIT_RSS is good enough. (Unfortunately 64-bit 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and 32-bit headers disagree on the type of these constants!) 57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#ifdef RLIMIT_AS 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define USE_RESOURCE RLIMIT_AS 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define USE_RESOURCE RLIMIT_RSS 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Restrict the test to 1GiB, which should fit comfortably well on both 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 32-bit and 64-bit hosts, and executes in ~1s. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const rlim_t kMaxMem = 1<<30; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci struct rlimit rlim; 681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (getrlimit(USE_RESOURCE, &rlim) == 0) { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rlim.rlim_cur == RLIM_INFINITY || rlim.rlim_cur > kMaxMem) { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rlim.rlim_cur = kMaxMem; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setrlimit(USE_RESOURCE, &rlim); // ignore result 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* HAVE_SYS_RESOURCE_H */ 75effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 76effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 77effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 78effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstruct FunctionAndId { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void (*ptr_to_function)(int); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int id; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(NO_THREADS) || !(defined(HAVE_PTHREAD) || defined(_WIN32)) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void RunThread(void (*fn)()) { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*fn)(); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void RunManyThreads(void (*fn)(), int count) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // I guess the best we can do is run fn sequentially, 'count' times 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < count; i++) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*fn)(); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void RunManyThreadsWithId(void (*fn)(int), int count, int) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < count; i++) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*fn)(i); // stacksize doesn't make sense in a non-threaded context 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(_WIN32) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef WIN32_LEAN_AND_MEAN 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define WIN32_LEAN_AND_MEAN /* We always want minimal includes */ 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h> 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This helper function has the signature that pthread_create wants. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD WINAPI RunFunctionInThread(LPVOID ptr_to_ptr_to_fn) { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (**static_cast<void (**)()>(ptr_to_ptr_to_fn))(); // runs fn 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD WINAPI RunFunctionInThreadWithId(LPVOID ptr_to_fnid) { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FunctionAndId* fn_and_id = static_cast<FunctionAndId*>(ptr_to_fnid); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*fn_and_id->ptr_to_function)(fn_and_id->id); // runs fn 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void RunManyThreads(void (*fn)(), int count) { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD dummy; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HANDLE* hThread = new HANDLE[count]; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < count; i++) { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hThread[i] = CreateThread(NULL, 0, RunFunctionInThread, &fn, 0, &dummy); 125 if (hThread[i] == NULL) ExitProcess(i); 126 } 127 WaitForMultipleObjects(count, hThread, TRUE, INFINITE); 128 for (int i = 0; i < count; i++) { 129 CloseHandle(hThread[i]); 130 } 131 delete[] hThread; 132 } 133 134 void RunThread(void (*fn)()) { 135 RunManyThreads(fn, 1); 136 } 137 138 void RunManyThreadsWithId(void (*fn)(int), int count, int stacksize) { 139 DWORD dummy; 140 HANDLE* hThread = new HANDLE[count]; 141 FunctionAndId* fn_and_ids = new FunctionAndId[count]; 142 for (int i = 0; i < count; i++) { 143 fn_and_ids[i].ptr_to_function = fn; 144 fn_and_ids[i].id = i; 145 hThread[i] = CreateThread(NULL, stacksize, RunFunctionInThreadWithId, 146 &fn_and_ids[i], 0, &dummy); 147 if (hThread[i] == NULL) ExitProcess(i); 148 } 149 WaitForMultipleObjects(count, hThread, TRUE, INFINITE); 150 for (int i = 0; i < count; i++) { 151 CloseHandle(hThread[i]); 152 } 153 delete[] fn_and_ids; 154 delete[] hThread; 155 } 156} 157 158#else // not NO_THREADS, not !HAVE_PTHREAD, not _WIN32 159 160#include <pthread.h> 161 162#define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0) 163 164extern "C" { 165 // This helper function has the signature that pthread_create wants. 166 static void* RunFunctionInThread(void *ptr_to_ptr_to_fn) { 167 (**static_cast<void (**)()>(ptr_to_ptr_to_fn))(); // runs fn 168 return NULL; 169 } 170 171 static void* RunFunctionInThreadWithId(void *ptr_to_fnid) { 172 FunctionAndId* fn_and_id = static_cast<FunctionAndId*>(ptr_to_fnid); 173 (*fn_and_id->ptr_to_function)(fn_and_id->id); // runs fn 174 return NULL; 175 } 176 177 // Run a function in a thread of its own and wait for it to finish. 178 // This is useful for tcmalloc testing, because each thread is 179 // handled separately in tcmalloc, so there's interesting stuff to 180 // test even if the threads are not running concurrently. 181 void RunThread(void (*fn)()) { 182 pthread_t thr; 183 // Even though fn is on the stack, it's safe to pass a pointer to it, 184 // because we pthread_join immediately (ie, before RunInThread exits). 185 SAFE_PTHREAD(pthread_create(&thr, NULL, RunFunctionInThread, &fn)); 186 SAFE_PTHREAD(pthread_join(thr, NULL)); 187 } 188 189 void RunManyThreads(void (*fn)(), int count) { 190 pthread_t* thr = new pthread_t[count]; 191 for (int i = 0; i < count; i++) { 192 SAFE_PTHREAD(pthread_create(&thr[i], NULL, RunFunctionInThread, &fn)); 193 } 194 for (int i = 0; i < count; i++) { 195 SAFE_PTHREAD(pthread_join(thr[i], NULL)); 196 } 197 delete[] thr; 198 } 199 200 void RunManyThreadsWithId(void (*fn)(int), int count, int stacksize) { 201 pthread_attr_t attr; 202 pthread_attr_init(&attr); 203 pthread_attr_setstacksize(&attr, stacksize); 204 205 pthread_t* thr = new pthread_t[count]; 206 FunctionAndId* fn_and_ids = new FunctionAndId[count]; 207 for (int i = 0; i < count; i++) { 208 fn_and_ids[i].ptr_to_function = fn; 209 fn_and_ids[i].id = i; 210 SAFE_PTHREAD(pthread_create(&thr[i], &attr, 211 RunFunctionInThreadWithId, &fn_and_ids[i])); 212 } 213 for (int i = 0; i < count; i++) { 214 SAFE_PTHREAD(pthread_join(thr[i], NULL)); 215 } 216 delete[] fn_and_ids; 217 delete[] thr; 218 219 pthread_attr_destroy(&attr); 220 } 221} 222 223#endif 224