diff options
Diffstat (limited to 'backend')
53 files changed, 5078 insertions, 0 deletions
diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt new file mode 100644 index 00000000..73a79edb --- /dev/null +++ b/backend/CMakeLists.txt @@ -0,0 +1,104 @@ +project (PF) + +cmake_minimum_required (VERSION 2.6.0) + +set (PF_CMAKE_DIR "${PF_SOURCE_DIR}/cmake") +set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PF_CMAKE_DIR}") + +############################################################## +# Compilation directives +############################################################## + +set (PF_DEBUG_MEMORY false CACHE bool "Activate the memory debugger") +set (PF_USE_BLOB false CACHE bool "Compile everything from one big file") +set (PF_VERBOSE_VECTORIZER false CACHE bool "Output vectorizer diagnostic (GCC only)") + +############################################################## +# Compiler +############################################################## +if (UNIX) + set (COMPILER "GCC" CACHE INT "Compiler to choose on Linux (GCC,ICC,CLANG)") +endif (UNIX) + +if (WIN32) + if (MINGW) + set (DEF "-D") + else (MINGW) + set (DEF "/D") + endif (MINGW) +else (WIN32) + set (DEF "-D") +endif (WIN32) + +if (PF_DEBUG_MEMORY) + set (PF_DEBUG_MEMORY_FLAG "${DEF}PF_DEBUG_MEMORY=1") +else (PF_DEBUG_MEMORY) + set (PF_DEBUG_MEMORY_FLAG "${DEF}PF_DEBUG_MEMORY=0") +endif (PF_DEBUG_MEMORY) + +## Linux compilation +if (CMAKE_SYSTEM_NAME STREQUAL "Linux") + # Hide all symbols and allows the symbols declared as visible to be exported + set (VISIBILITY_FLAG "-fvisibility=hidden") + + if (COMPILER STREQUAL "GCC") + set (CMAKE_CXX_FLAGS "-Wstrict-aliasing=2 -Wno-invalid-offsetof -fstrict-aliasing -msse2 -ffast-math -fPIC -Wall -fno-rtti -std=c++0x") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PF_DEBUG_MEMORY_FLAG}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${VISIBILITY_FLAG} -Wl,-E") + set (CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG -ftree-vectorize") + if (PF_VERBOSE_VECTORIZER) + set (CMAKE_CXX_FLAGS "-ftree-vectorizer-verbose=2") + endif (PF_VERBOSE_VECTORIZER) + elseif (COMPILER STREQUAL "CLANG") + set (CMAKE_C_COMPILER "clang") + set (CMAKE_C_FLAGS "-Wall -std=c99") + set (CMAKE_C_FLAGS_DEBUG "-g") + set (CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG") + set (CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG") + set (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g") + set (CMAKE_CXX_COMPILER "clang++") + set (CMAKE_CXX_FLAGS "-fstrict-aliasing -msse2 -ffast-math -fPIC -Wall -Wno-format-security -Wno-invalid-offsetof -std=c++0x") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PF_DEBUG_MEMORY_FLAG}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${VISIBILITY_FLAG}") + set (CMAKE_CXX_FLAGS_DEBUG "-g") + set (CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG") + set (CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") + set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") + set (CMAKE_AR "/usr/bin/llvm-ar") + set (CMAKE_LINKER "/usr/bin/llvm-ld") + set (CMAKE_NM "/usr/bin/llvm-nm") + set (CMAKE_OBJDUMP "/usr/bin/llvm-objdump") + set (CMAKE_RANLIB "ranlib") + elseif (COMPILER STREQUAL "ICC") + set (CMAKE_CXX_COMPILER "icpc") + set (CMAKE_C_COMPILER "icc") + set (CMAKE_CXX_FLAGS "-std=c++0x -wd2928 -Wall -fPIC -fstrict-aliasing -fp-model fast -xSSE2") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PF_DEBUG_MEMORY_FLAG}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${VISIBILITY_FLAG} -Wl,-E") + set (CMAKE_CXX_FLAGS_DEBUG "-g -O0") + set (CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O2") + set (CCMAKE_CXX_FLAGS_RELWITHDEBINFO "-g -O2") + set (CCMAKE_CXX_FLAGS_MINSIZEREL "-Os") + set (CMAKE_EXE_LINKER_FLAGS "") + endif () + +## Windows compilation +elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows") + if (MINGW) + if (PF_VERBOSE_VECTORIZER) + set (CMAKE_CXX_FLAGS "-ftree-vectorizer-verbose=2") + endif (PF_VERBOSE_VECTORIZER) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PF_DEBUG_MEMORY_FLAG} -Wno-invalid-offsetof -fstrict-aliasing -msse2 -ffast-math -Wall -fno-rtti -std=c++0x") + set (CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") + else (MINGW) + set (COMMON_FLAGS "${PF_DEBUG_MEMORY_FLAG} /arch:SSE2 /D_CRT_SECURE_NO_WARNINGS /DNOMINMAX /GR- /GS- /W3 /wd4275") + set (CMAKE_CXX_FLAGS ${COMMON_FLAGS}) + set (CMAKE_C_FLAGS ${COMMON_FLAGS}) + endif (MINGW) +endif () + +############################################################## +# Project source code +############################################################## +add_subdirectory (src) + diff --git a/backend/src/CMakeLists.txt b/backend/src/CMakeLists.txt new file mode 100644 index 00000000..5a3b20b6 --- /dev/null +++ b/backend/src/CMakeLists.txt @@ -0,0 +1,42 @@ +set (GBE_SRC + sys/vector.hpp + sys/hash_map.hpp + sys/map.hpp + sys/string.cpp + sys/string.hpp + sys/filename.cpp + sys/filename.hpp + sys/library.cpp + sys/library.hpp + sys/thread.cpp + sys/thread.hpp + sys/alloc.cpp + sys/alloc.hpp + sys/sysinfo.cpp + sys/sysinfo.hpp + sys/ref.hpp + sys/mutex.cpp + sys/mutex.hpp + sys/condition.cpp + sys/condition.hpp + sys/platform.cpp + sys/platform.hpp + sys/logging.cpp + sys/logging.hpp + sys/default_path.cpp + sys/default_path.hpp) + +set (COMPILE_UTEST false CACHE bool "Compile or not the unit tests") +if (COMPILE_UTEST) + set (GBE_SRC ${GBE_SRC}) +endif (COMPILE_UTEST) + +if (UNIX) + set (EXEC_DEPENDENCIES pthread dl) +else (UNIX) + set (EXEC_DEPENDENCIES) +endif (UNIX) + +include_directories (.) +add_library (gbe SHARED ${GBE_SRC}) + diff --git a/backend/src/ir/function.cpp b/backend/src/ir/function.cpp new file mode 100644 index 00000000..12001d60 --- /dev/null +++ b/backend/src/ir/function.cpp @@ -0,0 +1,19 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + diff --git a/backend/src/ir/function.hpp b/backend/src/ir/function.hpp new file mode 100644 index 00000000..12001d60 --- /dev/null +++ b/backend/src/ir/function.hpp @@ -0,0 +1,19 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + diff --git a/backend/src/ir/instruction.cpp b/backend/src/ir/instruction.cpp new file mode 100644 index 00000000..12001d60 --- /dev/null +++ b/backend/src/ir/instruction.cpp @@ -0,0 +1,19 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + diff --git a/backend/src/ir/instruction.hpp b/backend/src/ir/instruction.hpp new file mode 100644 index 00000000..12001d60 --- /dev/null +++ b/backend/src/ir/instruction.hpp @@ -0,0 +1,19 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + diff --git a/backend/src/ir/register.cpp b/backend/src/ir/register.cpp new file mode 100644 index 00000000..12001d60 --- /dev/null +++ b/backend/src/ir/register.cpp @@ -0,0 +1,19 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + diff --git a/backend/src/ir/register.hpp b/backend/src/ir/register.hpp new file mode 100644 index 00000000..12001d60 --- /dev/null +++ b/backend/src/ir/register.hpp @@ -0,0 +1,19 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + diff --git a/backend/src/ir/scope.cpp b/backend/src/ir/scope.cpp new file mode 100644 index 00000000..12001d60 --- /dev/null +++ b/backend/src/ir/scope.cpp @@ -0,0 +1,19 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + diff --git a/backend/src/ir/scope.hpp b/backend/src/ir/scope.hpp new file mode 100644 index 00000000..12001d60 --- /dev/null +++ b/backend/src/ir/scope.hpp @@ -0,0 +1,19 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + diff --git a/backend/src/ir/unit.cpp b/backend/src/ir/unit.cpp new file mode 100644 index 00000000..12001d60 --- /dev/null +++ b/backend/src/ir/unit.cpp @@ -0,0 +1,19 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + diff --git a/backend/src/ir/unit.hpp b/backend/src/ir/unit.hpp new file mode 100644 index 00000000..12001d60 --- /dev/null +++ b/backend/src/ir/unit.hpp @@ -0,0 +1,19 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + diff --git a/backend/src/sys/alloc.cpp b/backend/src/sys/alloc.cpp new file mode 100644 index 00000000..e23ae8e6 --- /dev/null +++ b/backend/src/sys/alloc.cpp @@ -0,0 +1,261 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "sys/alloc.hpp" +#include "sys/atomic.hpp" +#include "sys/mutex.hpp" + +#if PF_DEBUG_MEMORY +#ifdef __MSVC__ +#include <unordered_map> +#else +#include <tr1/unordered_map> +#endif /* __MSVC__ */ +#include <cstring> +#endif /* PF_DEBUG_MEMORY */ + +#if defined(__ICC__) +#include <stdint.h> +#endif /* __ICC__ */ +#include <map> +#include <vector> + +//////////////////////////////////////////////////////////////////////////////// +/// Memory debugger +//////////////////////////////////////////////////////////////////////////////// +namespace pf +{ + +#if PF_DEBUG_MEMORY + /*! Store each allocation data */ + struct AllocData { + INLINE AllocData(void) {} + INLINE AllocData(int fileName_, int functionName_, int line_, intptr_t alloc_) : + fileName(fileName_), functionName(functionName_), line(line_), alloc(alloc_) {} + int fileName, functionName, line; + intptr_t alloc; + }; + + /*! Store allocation information */ + struct MemDebugger { + MemDebugger(void) : unfreedNum(0), allocNum(0) {} + void* insertAlloc(void *ptr, const char *file, const char *function, int line); + void removeAlloc(void *ptr); + void dumpAlloc(void); + void dumpData(const AllocData &data); + /*! Count the still unfreed allocations */ + volatile intptr_t unfreedNum; + /*! Total number of allocations done */ + volatile intptr_t allocNum; + /*! Sorts the file name and function name strings */ + std::tr1::unordered_map<const char*, int> staticStringMap; + /*! Each element contains the actual string */ + std::vector<const char*> staticStringVector; + std::map<uintptr_t, AllocData> allocMap; + /*! Protect the memory debugger accesses */ + MutexSys mutex; + }; + + void* MemDebugger::insertAlloc(void *ptr, const char *file, const char *function, int line) + { + if (ptr == NULL) return ptr; + Lock<MutexSys> lock(mutex); + const uintptr_t iptr = (uintptr_t) ptr; + if (UNLIKELY(allocMap.find(iptr) != allocMap.end())) { + this->dumpData(allocMap.find(iptr)->second); + FATAL("Pointer already in map"); + } + const auto fileIt = staticStringMap.find(file); + const auto functionIt = staticStringMap.find(function); + int fileName, functionName; + if (fileIt == staticStringMap.end()) { + staticStringVector.push_back(file); + staticStringMap[file] = fileName = int(staticStringVector.size()) - 1; + } else + fileName = staticStringMap[file]; + if (functionIt == staticStringMap.end()) { + staticStringVector.push_back(function); + staticStringMap[function] = functionName = int(staticStringVector.size()) - 1; + } else + functionName = staticStringMap[function]; + allocMap[iptr] = AllocData(fileName, functionName, line, allocNum); + unfreedNum++; + allocNum++; + return ptr; + } + + void MemDebugger::removeAlloc(void *ptr) + { + if (ptr == NULL) return; + Lock<MutexSys> lock(mutex); + const uintptr_t iptr = (uintptr_t) ptr; + FATAL_IF(allocMap.find(iptr) == allocMap.end(), "Pointer not referenced"); + //if(allocMap.find(iptr) == allocMap.end()) debugbreak(); + allocMap.erase(iptr); + unfreedNum--; + } + + void MemDebugger::dumpData(const AllocData &data) { + std::cerr << "ALLOC " << data.alloc << ": " << + "file " << staticStringVector[data.fileName] << ", " << + "function " << staticStringVector[data.functionName] << ", " << + "line " << data.line << std::endl; + } + + void MemDebugger::dumpAlloc(void) { + std::cerr << "MemDebugger: Unfreed number: " << unfreedNum << std::endl; + for (auto it = allocMap.begin(); it != allocMap.end(); ++it) + this->dumpData(it->second); + std::cerr << "MemDebugger: " << staticStringVector.size() + << " allocated static strings" << std::endl; + } + + /*! The user can deactivate the memory initialization */ + static bool memoryInitializationEnabled = true; + + /*! Declare C like interface functions here */ + static MemDebugger *memDebugger = NULL; + void* MemDebuggerInsertAlloc(void *ptr, const char *file, const char *function, int line) { + if (memDebugger) return memDebugger->insertAlloc(ptr, file, function, line); + return ptr; + } + void MemDebuggerRemoveAlloc(void *ptr) { + if (memDebugger) memDebugger->removeAlloc(ptr); + } + void MemDebuggerDumpAlloc(void) { + if (memDebugger) memDebugger->dumpAlloc(); + } + void MemDebuggerEnableMemoryInitialization(bool enabled) { + memoryInitializationEnabled = enabled; + } + void MemDebuggerInitializeMem(void *mem, size_t sz) { + if (memoryInitializationEnabled) std::memset(mem, 0xcd, sz); + } + void MemDebuggerStart(void) { + if (memDebugger) MemDebuggerEnd(); + memDebugger = new MemDebugger; + } + void MemDebuggerEnd(void) { + MemDebugger *_debug = memDebugger; + memDebugger = NULL; + delete _debug; + } +#endif /* PF_DEBUG_MEMORY */ +} + +namespace pf +{ + void* malloc(size_t size) { + void *ptr = std::malloc(size); + MemDebuggerInitializeMem(ptr, size); + return ptr; + } + + void* realloc(void *ptr, size_t size) { +#if PF_DEBUG_MEMORY + if (ptr) MemDebuggerRemoveAlloc(ptr); +#endif /* PF_DEBUG_MEMORY */ + PF_ASSERT(size); + if (ptr == NULL) { + ptr = std::realloc(ptr, size); + MemDebuggerInitializeMem(ptr, size); + return ptr; + } else + return std::realloc(ptr, size); + } + + void free(void *ptr) { if (ptr != NULL) std::free(ptr); } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Windows Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __WIN32__ + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +namespace pf +{ + void* alignedMalloc(size_t size, size_t align) { + void* ptr = _mm_malloc(size,align); + FATAL_IF (!ptr && size, "memory allocation failed"); + MemDebuggerInitializeMem(ptr, size); + return ptr; + } + + void alignedFree(void *ptr) { _mm_free(ptr); } +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Linux Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __LINUX__ + +#include <unistd.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <malloc.h> +#include <iostream> + +namespace pf +{ + void* alignedMalloc(size_t size, size_t align) { + void* ptr = memalign(align,size); + FATAL_IF (!ptr && size, "memory allocation failed"); + MemDebuggerInitializeMem(ptr, size); + return ptr; + } + + void alignedFree(void *ptr) { free(ptr); } +} + +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// MacOS Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __MACOSX__ + +#include <cstdlib> + +namespace pf +{ + void* alignedMalloc(size_t size, size_t align) { + void* mem = malloc(size+(align-1)+sizeof(void*)); + FATAL_IF (!mem && size, "memory allocation failed"); + char* aligned = ((char*)mem) + sizeof(void*); + aligned += align - ((uintptr_t)aligned & (align - 1)); + ((void**)aligned)[-1] = mem; + MemDebuggerInitializeMem(aligned, size); + return aligned; + } + + void alignedFree(void* ptr) { + PF_ASSERT(ptr); + free(((void**)ptr)[-1]); + } +} + +#endif + diff --git a/backend/src/sys/alloc.hpp b/backend/src/sys/alloc.hpp new file mode 100644 index 00000000..5b686343 --- /dev/null +++ b/backend/src/sys/alloc.hpp @@ -0,0 +1,229 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_ALLOC_HPP__ +#define __PF_ALLOC_HPP__ + +#include "sys/platform.hpp" +#include <cstdlib> +#include <new> + +namespace pf +{ + /*! regular allocation */ + void* malloc(size_t size); + void* realloc(void *ptr, size_t size); + void free(void *ptr); + + /*! Aligned allocation */ + void* alignedMalloc(size_t size, size_t align = 64); + void alignedFree(void* ptr); + + /*! Monitor memory allocations */ +#if PF_DEBUG_MEMORY + void* MemDebuggerInsertAlloc(void*, const char*, const char*, int); + void MemDebuggerRemoveAlloc(void *ptr); + void MemDebuggerDumpAlloc(void); + void MemDebuggerInitializeMem(void *mem, size_t sz); + void MemDebuggerEnableMemoryInitialization(bool enabled); + void MemDebuggerStart(void); + void MemDebuggerEnd(void); +#else + INLINE void* MemDebuggerInsertAlloc(void *ptr, const char*, const char*, int) {return ptr;} + INLINE void MemDebuggerRemoveAlloc(void *ptr) {} + INLINE void MemDebuggerDumpAlloc(void) {} + INLINE void MemDebuggerInitializeMem(void *mem, size_t sz) {} + INLINE void MemDebuggerEnableMemoryInitialization(bool enabled) {} + INLINE void MemDebuggerStart(void) {} + INLINE void MemDebuggerEnd(void) {} +#endif /* PF_DEBUG_MEMORY */ + + /*! Properly handle the allocated type */ + template <typename T> + T* _MemDebuggerInsertAlloc(T *ptr, const char *file, const char *function, int line) { + MemDebuggerInsertAlloc(ptr, file, function, line); + return ptr; + } +} /* namespace pf */ + +/*! Declare a structure with custom allocators */ +#define PF_STRUCT(TYPE) \ + void* operator new(size_t size) { \ + if (AlignOf<TYPE>::value > sizeof(uintptr_t)) \ + return pf::alignedMalloc(size, AlignOf<TYPE>::value); \ + else \ + return pf::malloc(size); \ + } \ + void* operator new[](size_t size) { \ + if (AlignOf<TYPE>::value > sizeof(uintptr_t)) \ + return pf::alignedMalloc(size, AlignOf<TYPE>::value); \ + else \ + return pf::malloc(size); \ + } \ + void operator delete(void* ptr) { \ + if (AlignOf<TYPE>::value > sizeof(uintptr_t)) \ + return pf::alignedFree(ptr); \ + else \ + return pf::free(ptr); \ + } \ + void operator delete[](void* ptr) { \ + if (AlignOf<TYPE>::value > sizeof(uintptr_t)) \ + return pf::alignedFree(ptr); \ + else \ + return pf::free(ptr); \ + } \ + +/*! Declare a class with custom allocators */ +#define PF_CLASS(TYPE) \ +public: \ + PF_STRUCT(TYPE) \ +private: + +/*! Declare an aligned structure */ +#define PF_ALIGNED_STRUCT(ALIGN) \ + void* operator new(size_t size) { return pf::alignedMalloc(size, ALIGN); }\ + void* operator new[](size_t size) { return pf::alignedMalloc(size, ALIGN); }\ + void operator delete(void* ptr) { pf::alignedFree(ptr); } \ + void operator delete[](void* ptr) { pf::alignedFree(ptr); } + +/*! Declare an aligned class */ +#define PF_ALIGNED_CLASS(ALIGN) \ +public: \ + PF_ALIGNED_STRUCT(ALIGN) \ +private: + +/*! Macros to handle allocation position */ +#define PF_NEW(T,...) \ + pf::_MemDebuggerInsertAlloc(new T(__VA_ARGS__), __FILE__, __FUNCTION__, __LINE__) + +#define PF_NEW_ARRAY(T,N,...) \ + pf::_MemDebuggerInsertAlloc(new T[N](__VA_ARGS__), __FILE__, __FUNCTION__, __LINE__) + +#define PF_NEW_P(T,X,...) \ + pf::_MemDebuggerInsertAlloc(new (X) T(__VA_ARGS__), __FILE__, __FUNCTION__, __LINE__) + +#define PF_DELETE(X) \ + do { pf::MemDebuggerRemoveAlloc(X); delete X; } while (0) + +#define PF_DELETE_ARRAY(X) \ + do { pf::MemDebuggerRemoveAlloc(X); delete[] X; } while (0) + +#define PF_MALLOC(SZ) \ + pf::MemDebuggerInsertAlloc(pf::malloc(SZ),__FILE__, __FUNCTION__, __LINE__) + +#define PF_REALLOC(PTR, SZ) \ + pf::MemDebuggerInsertAlloc(pf::realloc(PTR, SZ),__FILE__, __FUNCTION__, __LINE__) + +#define PF_FREE(X) \ + do { pf::MemDebuggerRemoveAlloc(X); pf::free(X); } while (0) + +#define PF_ALIGNED_FREE(X) \ + do { pf::MemDebuggerRemoveAlloc(X); pf::alignedFree(X); } while (0) + +#define PF_ALIGNED_MALLOC(SZ,ALIGN) \ + pf::MemDebuggerInsertAlloc(pf::alignedMalloc(SZ,ALIGN),__FILE__, __FUNCTION__, __LINE__) + +namespace pf +{ + /*! STL compliant allocator to intercept all memory allocations */ + template<typename T> + class Allocator { + public: + typedef T value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef typename std::allocator<void>::const_pointer void_allocator_ptr; + template<typename U> + struct rebind { typedef Allocator<U> other; }; + + INLINE Allocator(void) {} + INLINE ~Allocator(void) {} + INLINE Allocator(Allocator const&) {} + template<typename U> + INLINE Allocator(Allocator<U> const&) {} + INLINE pointer address(reference r) { return &r; } + INLINE const_pointer address(const_reference r) { return &r; } + INLINE pointer allocate(size_type n, void_allocator_ptr = 0) { + if (AlignOf<T>::value > sizeof(uintptr_t)) + return (pointer) PF_ALIGNED_MALLOC(n*sizeof(T), AlignOf<T>::value); + else + return (pointer) PF_MALLOC(n * sizeof(T)); + } + INLINE void deallocate(pointer p, size_type) { + if (AlignOf<T>::value > sizeof(uintptr_t)) + PF_ALIGNED_FREE(p); + else + PF_FREE(p); + } + INLINE size_type max_size(void) const { + return std::numeric_limits<size_type>::max() / sizeof(T); + } + INLINE void construct(pointer p, const T& t = T()) { ::new(p) T(t); } + INLINE void destroy(pointer p) { p->~T(); } + INLINE bool operator==(Allocator const&) { return true; } + INLINE bool operator!=(Allocator const& a) { return !operator==(a); } + }; + + /*! A growing pool never deallocates */ + template <typename T> + class GrowingPool + { + public: + GrowingPool(void) : current(PF_NEW(GrowingPoolElem, 1)) {} + ~GrowingPool(void) { PF_ASSERT(current); PF_DELETE(current); } + T *allocate(void) { + if (UNLIKELY(current->allocated == current->maxElemNum)) { + GrowingPoolElem *elem = PF_NEW(GrowingPoolElem, 2 * current->maxElemNum); + elem->next = current; + current = elem; + } + T *data = current->data + current->allocated++; + return data; + } + private: + /*! Chunk of elements to allocate */ + class GrowingPoolElem + { + friend class GrowingPool; + GrowingPoolElem(size_t elemNum) { + this->data = PF_NEW_ARRAY(T, elemNum); + this->next = NULL; + this->maxElemNum = elemNum; + this->allocated = 0; + } + ~GrowingPoolElem(void) { + PF_ASSERT(this->data); + PF_DELETE_ARRAY(this->data); + if (this->next) PF_DELETE(this->next); + } + T *data; + GrowingPoolElem *next; + size_t allocated, maxElemNum; + }; + GrowingPoolElem *current; + PF_CLASS(GrowingPool); + }; +} /* namespace pf */ + +#endif /* __PF_ALLOC_HPP__ */ + diff --git a/backend/src/sys/array.hpp b/backend/src/sys/array.hpp new file mode 100644 index 00000000..04cc3c6c --- /dev/null +++ b/backend/src/sys/array.hpp @@ -0,0 +1,108 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_ARRAY_HPP__ +#define __PF_ARRAY_HPP__ + +#include "sys/platform.hpp" +#include <vector> + +namespace pf +{ + /*! Non resizable array with no checking. We make it non-copiable right now + * since we do not want to implement an expensive deep copy + */ + template<class T> + class array + { + public: + /*! Create an empty array */ + INLINE array(void) : elem(NULL), elemNum(0) {} + /*! Allocate an array with elemNum allocated elements */ + INLINE array(size_t elemNum) : elem(NULL), elemNum(0) { this->resize(elemNum); } + /*! Copy constructor */ + INLINE array(const array &other) { + this->elemNum = other.elemNum; + if (this->elemNum) { + this->elem = PF_NEW_ARRAY(T, this->elemNum); + for (size_t i = 0; i < this->elemNum; ++i) this->elem[i] = other.elem[i]; + } else + this->elem = NULL; + } + /*! Assignment operator */ + INLINE array& operator= (const array &other) { + if (this->elem != NULL && this->elemNum != other->elemNum) { + PF_DELETE_ARRAY(this->elem); + this->elem = NULL; + this->elemNum = 0; + } + this->elemNum = other.elemNum; + if (this->elemNum) { + if (this->elem == NULL) + this->elem = PF_NEW_ARRAY(T, this->elemNum); + for (size_t i = 0; i < this->elemNum; ++i) this->elem[i] = other.elem[i]; + } else + this->elem = NULL; + return *this; + } + /*! Delete the allocated elements */ + INLINE ~array(void) { PF_SAFE_DELETE_ARRAY(elem); } + /*! Free the already allocated elements and allocate a new array */ + INLINE void resize(size_t elemNum_) { + if (elemNum_ != this->elemNum) { + PF_SAFE_DELETE_ARRAY(elem); + if (elemNum_) + this->elem = PF_NEW_ARRAY(T, elemNum_); + else + this->elem = NULL; + this->elemNum = elemNum_; + } + } + /*! Steal the pointer. The array becomes emtpy */ + INLINE T *steal(void) { + T *stolen = this->elem; + this->elem = NULL; + this->elemNum = 0; + return stolen; + } + /*! First element */ + INLINE T *begin(void) { return this->elem; } + /*! First non-valid element */ + INLINE T *end(void) { return this->elem + elemNum; } + /*! Get element at position index (with a bound check) */ + INLINE T &operator[] (size_t index) { + PF_ASSERT(elem && index < elemNum); + return elem[index]; + } + /*! Get element at position index (with bound check) */ + INLINE const T &operator[] (size_t index) const { + PF_ASSERT(elem && index < elemNum); + return elem[index]; + } + /*! Return the number of elements */ + INLINE size_t size(void) const { return this->elemNum; } + private: + T *elem; //!< Points to the elements + size_t elemNum; //!< Number of elements in the array + PF_CLASS(array); + }; +} /* namespace pf */ + +#endif /* __PF_ARRAY_HPP__ */ + diff --git a/backend/src/sys/atomic.hpp b/backend/src/sys/atomic.hpp new file mode 100644 index 00000000..07b2fdaf --- /dev/null +++ b/backend/src/sys/atomic.hpp @@ -0,0 +1,57 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_ATOMIC_HPP__ +#define __PF_ATOMIC_HPP__ + +#include "sys/intrinsics.hpp" + +namespace pf +{ + template <typename T> + struct AtomicInternal { + protected: + AtomicInternal(const AtomicInternal&); // don't implement + AtomicInternal& operator= (const AtomicInternal&); // don't implement + + public: + INLINE AtomicInternal(void) {} + INLINE AtomicInternal(T data) : data(data) {} + INLINE AtomicInternal& operator =(const T input) { data = input; return *this; } + INLINE operator T() const { return data; } + INLINE void storeRelease(T x) { __store_release(&data, x); } + public: + INLINE friend T operator+= (AtomicInternal& value, T input) { return atomic_add(&value.data, input) + input; } + INLINE friend T operator++ (AtomicInternal& value) { return atomic_add(&value.data, 1) + 1; } + INLINE friend T operator-- (AtomicInternal& value) { return atomic_add(&value.data, -1) - 1; } + INLINE friend T operator++ (AtomicInternal& value, int) { return atomic_add(&value.data, 1); } + INLINE friend T operator-- (AtomicInternal& value, int) { return atomic_add(&value.data, -1); } + INLINE friend T cmpxchg (AtomicInternal& value, const T v, const T c) { return atomic_cmpxchg(&value.data,v,c); } + + private: + volatile T data; + PF_STRUCT(AtomicInternal); + }; + + typedef AtomicInternal<atomic32_t> Atomic32; + typedef AtomicInternal<atomic_t> Atomic; +} + +#endif /* __PF_ATOMIC_HPP__ */ + diff --git a/backend/src/sys/barrier.hpp b/backend/src/sys/barrier.hpp new file mode 100644 index 00000000..9182a98c --- /dev/null +++ b/backend/src/sys/barrier.hpp @@ -0,0 +1,62 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_BARRIER_H__ +#define __PF_BARRIER_H__ + +#include "sys/condition.hpp" + +namespace pf +{ + /*! system barrier using operating system */ + class BarrierSys + { + public: + + void init(size_t count) { + this->count = 0; + this->full_size = count; + } + + int wait() { + count_mutex.lock(); + count++; + if (count == full_size) { + count = 0; + cond.broadcast(); + count_mutex.unlock(); + return 1; + } + cond.wait(count_mutex); + count_mutex.unlock(); + return 0; + } + + protected: + size_t count, full_size; + MutexSys count_mutex; + ConditionSys cond; + PF_CLASS(BarrierSys); + }; + + /* default barrier type */ + class Barrier : public BarrierSys {}; +} + +#endif diff --git a/backend/src/sys/condition.cpp b/backend/src/sys/condition.cpp new file mode 100644 index 00000000..27923f22 --- /dev/null +++ b/backend/src/sys/condition.cpp @@ -0,0 +1,139 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "sys/condition.hpp" + +#if defined(__WIN32__) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +#if defined(__GNUC__) + +namespace pf +{ + // This is an implementation of POSIX "compatible" condition variables for + // Win32, as described by Douglas C. Schmidt and Irfan Pyarali: + // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html. The code is directly + // readapted from the glfw source code that may be found here: + // http://www.glfw.org + enum { + MINGW32_COND_SIGNAL = 0, + MINGW32_COND_BROADCAST = 1 + }; + + /*! Implement the internal condition variable implementation Mingw lacks */ + struct Mingw32Cond + { + HANDLE events[2]; //<! Signal and broadcast event HANDLEs + unsigned int waiters_count; //<! Count of the number of waiters + CRITICAL_SECTION waiters_count_lock;//!< Serialize access to <waiters_count> + }; + + ConditionSys::ConditionSys () + { + cond = (Mingw32Cond *) PF_NEW(Mingw32Cond); + ((Mingw32Cond *)cond)->waiters_count = 0; + ((Mingw32Cond *)cond)->events[MINGW32_COND_SIGNAL] = CreateEvent(NULL, FALSE, FALSE, NULL); + ((Mingw32Cond *)cond)->events[MINGW32_COND_BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL); + InitializeCriticalSection(&((Mingw32Cond *)cond)->waiters_count_lock); + } + + ConditionSys::~ConditionSys () + { + CloseHandle(((Mingw32Cond *)cond)->events[MINGW32_COND_SIGNAL]); + CloseHandle(((Mingw32Cond *)cond)->events[MINGW32_COND_BROADCAST]); + DeleteCriticalSection(&((Mingw32Cond *)cond)->waiters_count_lock); + PF_DELETE((Mingw32Cond *)cond); + } + + void ConditionSys::wait(MutexSys& mutex) + { + Mingw32Cond *cv = (Mingw32Cond *) cond; + int result, last_waiter; + DWORD timeout_ms; + + // Avoid race conditions + EnterCriticalSection(&cv->waiters_count_lock); + cv->waiters_count ++; + LeaveCriticalSection(&cv->waiters_count_lock); + + // It's ok to release the mutex here since Win32 manual-reset events + // maintain state when used with SetEvent() + LeaveCriticalSection((CRITICAL_SECTION *) mutex.mutex); + timeout_ms = INFINITE; + + // Wait for either event to become signaled + result = WaitForMultipleObjects(2, cv->events, FALSE, timeout_ms); + + // Check if we are the last waiter + EnterCriticalSection(&cv->waiters_count_lock); + cv->waiters_count --; + last_waiter = (result == WAIT_OBJECT_0 + MINGW32_COND_BROADCAST) && + (cv->waiters_count == 0); + LeaveCriticalSection(&cv->waiters_count_lock); + + // Some thread called broadcast + if (last_waiter) { + // We're the last waiter to be notified or to stop waiting, so + // reset the manual event + ResetEvent(cv->events[MINGW32_COND_BROADCAST]); + } + + // Reacquire the mutex + EnterCriticalSection((CRITICAL_SECTION *) mutex.mutex); + } + + void ConditionSys::broadcast() + { + Mingw32Cond *cv = (Mingw32Cond *) cond; + int have_waiters; + + // Avoid race conditions + EnterCriticalSection(&cv->waiters_count_lock); + have_waiters = cv->waiters_count > 0; + LeaveCriticalSection(&cv->waiters_count_lock); + + if (have_waiters) + SetEvent(cv->events[MINGW32_COND_BROADCAST]); + } +} /* namespace pf */ +#else + +namespace pf +{ + /*! system condition using windows API */ + ConditionSys::ConditionSys () { cond = PF_NEW(CONDITION_VARIABLE); InitializeConditionVariable((CONDITION_VARIABLE*)cond); } + ConditionSys::~ConditionSys() { PF_DELETE((CONDITION_VARIABLE*)cond); } + void ConditionSys::wait(MutexSys& mutex) { SleepConditionVariableCS((CONDITION_VARIABLE*)cond, (CRITICAL_SECTION*)mutex.mutex, INFINITE); } + void ConditionSys::broadcast() { WakeAllConditionVariable((CONDITION_VARIABLE*)cond); } +} /* namespace pf */ +#endif /* __GNUC__ */ +#endif /* __WIN32__ */ + +#if defined(__UNIX__) +#include <pthread.h> +namespace pf +{ + ConditionSys::ConditionSys () { cond = PF_NEW(pthread_cond_t); pthread_cond_init((pthread_cond_t*)cond,NULL); } + ConditionSys::~ConditionSys() { PF_DELETE((pthread_cond_t*)cond); } + void ConditionSys::wait(MutexSys& mutex) { pthread_cond_wait((pthread_cond_t*)cond, (pthread_mutex_t*)mutex.mutex); } + void ConditionSys::broadcast() { pthread_cond_broadcast((pthread_cond_t*)cond); } +} /* namespace pf */ +#endif /* __UNIX__ */ + diff --git a/backend/src/sys/condition.hpp b/backend/src/sys/condition.hpp new file mode 100644 index 00000000..a6d71f72 --- /dev/null +++ b/backend/src/sys/condition.hpp @@ -0,0 +1,40 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_CONDITION_HPP__ +#define __PF_CONDITION_HPP__ + +#include "sys/mutex.hpp" + +namespace pf +{ + class ConditionSys + { + public: + ConditionSys(void); + ~ConditionSys(void); + void wait(class MutexSys& mutex); + void broadcast(void); + protected: + void* cond; + }; +} + +#endif + diff --git a/backend/src/sys/constants.hpp b/backend/src/sys/constants.hpp new file mode 100644 index 00000000..9849d11d --- /dev/null +++ b/backend/src/sys/constants.hpp @@ -0,0 +1,144 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_CONSTANTS_HPP__ +#define __PF_CONSTANTS_HPP__ + +#ifndef NULL +#define NULL 0 +#endif + +#include <limits> + +namespace pf +{ + static struct NullTy { + } null MAYBE_UNUSED; + + static struct TrueTy { + INLINE operator bool( ) const { return true; } + } True MAYBE_UNUSED; + + static struct FalseTy { + INLINE operator bool( ) const { return false; } + } False MAYBE_UNUSED; + + static struct ZeroTy + { + INLINE operator double( ) const { return 0; } + INLINE operator float ( ) const { return 0; } + INLINE operator int64 ( ) const { return 0; } + INLINE operator uint64( ) const { return 0; } + INLINE operator int32 ( ) const { return 0; } + INLINE operator uint32( ) const { return 0; } + INLINE operator int16 ( ) const { return 0; } + INLINE operator uint16( ) const { return 0; } + INLINE operator int8 ( ) const { return 0; } + INLINE operator uint8 ( ) const { return 0; } +#ifndef __MSVC__ + INLINE operator size_t( ) const { return 0; } +#endif + + } zero MAYBE_UNUSED; + + static struct OneTy + { + INLINE operator double( ) const { return 1; } + INLINE operator float ( ) const { return 1; } + INLINE operator int64 ( ) const { return 1; } + INLINE operator uint64( ) const { return 1; } + INLINE operator int32 ( ) const { return 1; } + INLINE operator uint32( ) const { return 1; } + INLINE operator int16 ( ) const { return 1; } + INLINE operator uint16( ) const { return 1; } + INLINE operator int8 ( ) const { return 1; } + INLINE operator uint8 ( ) const { return 1; } +#ifndef __MSVC__ + INLINE operator size_t( ) const { return 1; } +#endif + } one MAYBE_UNUSED; + + static struct NegInfTy + { + INLINE operator double( ) const { return -std::numeric_limits<double>::infinity(); } + INLINE operator float ( ) const { return -std::numeric_limits<float>::infinity(); } + INLINE operator int64 ( ) const { return std::numeric_limits<int64>::min(); } + INLINE operator uint64( ) const { return std::numeric_limits<uint64>::min(); } + INLINE operator int32 ( ) const { return std::numeric_limits<int32>::min(); } + INLINE operator uint32( ) const { return std::numeric_limits<uint32>::min(); } + INLINE operator int16 ( ) const { return std::numeric_limits<int16>::min(); } + INLINE operator uint16( ) const { return std::numeric_limits<uint16>::min(); } + INLINE operator int8 ( ) const { return std::numeric_limits<int8>::min(); } + INLINE operator uint8 ( ) const { return std::numeric_limits<uint8>::min(); } +#ifndef __MSVC__ + INLINE operator size_t( ) const { return std::numeric_limits<size_t>::min(); } +#endif + + } neg_inf MAYBE_UNUSED; + + static struct PosInfTy + { + INLINE operator double( ) const { return std::numeric_limits<double>::infinity(); } + INLINE operator float ( ) const { return std::numeric_limits<float>::infinity(); } + INLINE operator int64 ( ) const { return std::numeric_limits<int64>::max(); } + INLINE operator uint64( ) const { return std::numeric_limits<uint64>::max(); } + INLINE operator int32 ( ) const { return std::numeric_limits<int32>::max(); } + INLINE operator uint32( ) const { return std::numeric_limits<uint32>::max(); } + INLINE operator int16 ( ) const { return std::numeric_limits<int16>::max(); } + INLINE operator uint16( ) const { return std::numeric_limits<uint16>::max(); } + INLINE operator int8 ( ) const { return std::numeric_limits<int8>::max(); } + INLINE operator uint8 ( ) const { return std::numeric_limits<uint8>::max(); } +#ifndef _WIN32 + INLINE operator size_t( ) const { return std::numeric_limits<size_t>::max(); } +#endif + } inf MAYBE_UNUSED, pos_inf MAYBE_UNUSED; + + static struct NaNTy + { + INLINE operator double( ) const { return std::numeric_limits<double>::quiet_NaN(); } + INLINE operator float ( ) const { return std::numeric_limits<float>::quiet_NaN(); } + } nan MAYBE_UNUSED; + + static struct UlpTy + { + INLINE operator double( ) const { return std::numeric_limits<double>::epsilon(); } + INLINE operator float ( ) const { return std::numeric_limits<float>::epsilon(); } + } ulp MAYBE_UNUSED; + + static struct PiTy + { + INLINE operator double( ) const { return 3.14159265358979323846; } + INLINE operator float ( ) const { return 3.14159265358979323846f; } + } pi MAYBE_UNUSED; + + static struct StepTy { + } step MAYBE_UNUSED; + + static struct EmptyTy { + } empty MAYBE_UNUSED; + + static struct FullTy { + } full MAYBE_UNUSED; + + static const size_t KB = 1024u; + static const size_t MB = KB*KB; + static const size_t GB = KB*MB; +} + +#endif diff --git a/backend/src/sys/default_path.cpp b/backend/src/sys/default_path.cpp new file mode 100644 index 00000000..3661feed --- /dev/null +++ b/backend/src/sys/default_path.cpp @@ -0,0 +1,38 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "sys/default_path.hpp" +#include "platform.hpp" + +namespace pf +{ + const char *defaultPath[] = { + "./share/", + "../share/", + "../../share/", + "./", + "../", + "../../", + "./data/", + "../data/", + "../../data/" + }; + const size_t defaultPathNum = ARRAY_ELEM_NUM(defaultPath); +} /* namespace pf */ + diff --git a/backend/src/sys/default_path.hpp b/backend/src/sys/default_path.hpp new file mode 100644 index 00000000..5f841790 --- /dev/null +++ b/backend/src/sys/default_path.hpp @@ -0,0 +1,34 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __DEFAULT_PATH_HPP__ +#define __DEFAULT_PATH_HPP__ + +#include <cstdlib> + +namespace pf +{ + /*! Where you may find data files and shaders */ + extern const char *defaultPath[]; + /*! Number of default paths */ + extern const size_t defaultPathNum; +} /* namespace pf */ + +#endif /* __DEFAULT_PATH_HPP__ */ + diff --git a/backend/src/sys/filename.cpp b/backend/src/sys/filename.cpp new file mode 100644 index 00000000..58221f5c --- /dev/null +++ b/backend/src/sys/filename.cpp @@ -0,0 +1,123 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "sys/platform.hpp" +#include "sys/filename.hpp" + +namespace pf +{ +#ifdef __WIN32__ + const char path_sep = '\\'; +#else + const char path_sep = '/'; +#endif + + /*! little helper to not depend on math */ + static size_t maxInt(size_t a, size_t b) { return index_t(a) < index_t(b) ? b : a; } + + /*! create an empty filename */ + FileName::FileName () {} + + /*! create a valid filename from a string */ + FileName::FileName (const char* in) { + filename = in; + for (size_t i=0; i<filename.size(); i++) + if (filename[i] == '\\' || filename[i] == '/') + filename[i] = path_sep; + while (!filename.empty() && filename[filename.size()-1] == path_sep) + filename.resize(filename.size()-1); + } + + /*! create a valid filename from a string */ + FileName::FileName (const std::string& in) { + filename = in; + for (size_t i=0; i<filename.size(); i++) + if (filename[i] == '\\' || filename[i] == '/') + filename[i] = path_sep; + while (!filename.empty() && filename[filename.size()-1] == path_sep) + filename.resize(filename.size()-1); + } + + /*! returns the path */ + FileName FileName::path() const { + size_t pos = maxInt(filename.find_last_of('\\'),filename.find_last_of('/')); + if (pos == std::string::npos) return FileName(); + return filename.substr(0,pos); + } + + /*! returns the basename */ + std::string FileName::base() const { + size_t pos = maxInt(filename.find_last_of('\\'),filename.find_last_of('/')); + if (pos == std::string::npos) return filename; + return filename.substr(pos+1); + } + + /*! returns the extension */ + std::string FileName::ext() const { + size_t pos = filename.find_last_of('.'); + if (pos == std::string::npos) return ""; + return filename.substr(pos+1); + } + + /*! returns the basename without extension */ + std::string FileName::name() const { + size_t start = maxInt(filename.find_last_of('\\'),filename.find_last_of('/')) + 1; + if (start == std::string::npos) start = 0; + size_t end = filename.find_last_of('.'); + if (end == std::string::npos || end < start) end = filename.size(); + return filename.substr(start, end - start); + } + + /*! replaces the extension */ + FileName FileName::setExt(const std::string& ext) const { + size_t start = maxInt(filename.find_last_of('\\'),filename.find_last_of('/')) + 1; + if (start == std::string::npos) start = 0; + size_t end = filename.find_last_of('.'); + if (end == std::string::npos || end < start) return FileName(filename+ext); + return FileName(filename.substr(0,end)+ext); + } + + /*! adds the extension */ + FileName FileName::addExt(const std::string& ext) const { + return FileName(filename+ext); + } + + /*! concatenates two filenames to this/other */ + FileName FileName::operator +( const FileName& other ) const { + if (filename == "") return FileName(other); + else return FileName(filename + path_sep + other.filename); + } + + /*! concatenates two filenames to this/other */ + FileName FileName::operator +( const std::string& other ) const { + return operator+(FileName(other)); + } + + /*! removes the base from a filename (if possible) */ + FileName FileName::operator -( const FileName& base ) const { + size_t pos = filename.find_first_of(base); + if (pos == std::string::npos) return *this; + return FileName(filename.substr(pos+1)); + } + + /*! output operator */ + std::ostream& operator<<(std::ostream& cout, const FileName& filename) { + return cout << filename.filename; + } +} diff --git a/backend/src/sys/filename.hpp b/backend/src/sys/filename.hpp new file mode 100644 index 00000000..4f4fb391 --- /dev/null +++ b/backend/src/sys/filename.hpp @@ -0,0 +1,72 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_FILENAME_HPP__ +#define __PF_FILENAME_HPP__ + +#include "platform.hpp" +#include <string> +#include <cstdio> + +namespace pf +{ + /*! Convenience class for handling file names and paths. */ + class FileName + { + public: + /*! create an empty filename */ + FileName (); + /*! create a valid filename from a string */ + FileName (const char* filename); + /*! create a valid filename from a string */ + FileName (const std::string& filename); + /*! auto convert into a string */ + operator std::string() const { return filename; } + /*! returns a string of the filename */ + const std::string str() const { return filename; } + /*! returns a c-string of the filename */ + const char* c_str() const { return filename.c_str(); } + /*! returns the path of a filename */ + FileName path() const; + /*! returns the file of a filename */ + std::string base() const; + /*! returns the base of a filename without extension */ + std::string name() const; + /*! returns the file extension */ + std::string ext() const; + /*! replaces the file extension */ + FileName setExt(const std::string& ext = "") const; + /*! adds file extension */ + FileName addExt(const std::string& ext = "") const; + /*! concatenates two filenames to this/other */ + FileName operator +( const FileName& other ) const; + /*! concatenates two filenames to this/other */ + FileName operator +( const std::string& other ) const; + /*! removes the base from a filename (if possible) */ + FileName operator -( const FileName& base ) const; + /*! output operator */ + friend std::ostream& operator<<(std::ostream& cout, const FileName& filename); + private: + std::string filename; + PF_CLASS(FileName); + }; +} + +#endif /* __PF_FILENAME_HPP__ */ + diff --git a/backend/src/sys/fixed_array.hpp b/backend/src/sys/fixed_array.hpp new file mode 100644 index 00000000..68593ecf --- /dev/null +++ b/backend/src/sys/fixed_array.hpp @@ -0,0 +1,79 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_FIXED_ARRAY_HPP__ +#define __PF_FIXED_ARRAY_HPP__ + +#include "platform.hpp" +#include <cstring> + +namespace pf +{ + /*! Regular C array but with bound checks */ + template<typename T, size_t N> + class fixed_array + { + public: + /*! Do not initialize the data */ + fixed_array(void) {} + /*! Copy the input array */ + fixed_array(const T array[N]) { std::memcpy(elem, array, N * sizeof(T)); } + /*! First element (non const) */ + T* begin(void) { return &elem[0]; } + /*! First non-valid element (non const) */ + T* end(void) { return begin() + N; } + /*! First element (const) */ + const T* begin(void) const { return &elem[0]; } + /*! First non-valid element (const) */ + const T* end(void) const { return begin() + N; } + /*! Number of elements in the array */ + size_t size(void) const { return N; } + /*! Get the pointer to the data (non-const) */ + T* data(void) { return &elem[0]; } + /*! Get the pointer to the data (const) */ + const T* data(void) const { return &elem[0]; } + /*! First element (const) */ + const T& front(void) const { return *begin(); } + /*! Last element (const) */ + const T& back(void) const { return *(end() - 1); } + /*! First element (non-const) */ + T& front(void) { return *begin(); } + /*! Last element (non-const) */ + T& back(void) { return *(end() - 1); } + /*! Get element at position index (with bound check) */ + INLINE T& operator[] (size_t index) { + PF_ASSERT(index < size()); + return elem[index]; + } + /*! Get element at position index (with bound check) */ + INLINE const T& operator[] (size_t index) const { + PF_ASSERT(index < size()); + return elem[index]; + } + private: + T elem[N]; //!< Store the elements + STATIC_ASSERT(N > 0); //!< zero element is not allowed + PF_CLASS(fixed_array); + }; + +} /* namespace pf */ + +#endif /* __PF_FIXED_ARRAY_HPP__ */ + + diff --git a/backend/src/sys/hash_map.hpp b/backend/src/sys/hash_map.hpp new file mode 100644 index 00000000..ab1a317d --- /dev/null +++ b/backend/src/sys/hash_map.hpp @@ -0,0 +1,73 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_HASH_MAP_HPP__ +#define __PF_HASH_MAP_HPP__ + +#include "sys/platform.hpp" + +#ifdef __MSVC__ +#include <unordered_map> +#else +#include <tr1/unordered_map> +#endif /* __MSVC__ */ + +namespace pf +{ + /*! Add specific allocator to the hash map */ + template <class Key, + class T, + class Hash = std::hash<Key>, + class Pred = std::equal_to<Key>> + class hash_map : public std::tr1::unordered_map<Key,T,Hash,Pred,Allocator<std::pair<const Key,T>>> + { + public: + // Typedefs + typedef std::pair<const Key, T> value_type; + typedef Allocator<value_type> allocator_type; + typedef std::tr1::unordered_map<Key,T,Hash,Pred,allocator_type> parent_type; + typedef typename allocator_type::size_type size_type; + typedef Key key_type; + typedef T mapped_type; + typedef Hash hasher; + typedef Pred key_equal; + + /*! Default constructor */ + INLINE explicit hash_map(size_type n = 3, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()) : + parent_type(n, hf, eql, a) {} + /*! Iteration constructor */ + template <class InputIterator> + INLINE hash_map(InputIterator first, + InputIterator last, + size_type n = 3, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()) : + parent_type(first,last,n,hf,eql,a) {} + /*! Copy constructor */ + INLINE hash_map(const hash_map &other) : parent_type(other) {} + PF_CLASS(hash_map); + }; +} /* namespace pf */ + +#endif /* __PF_HASH_MAP_HPP__ */ + diff --git a/backend/src/sys/intrinsics.hpp b/backend/src/sys/intrinsics.hpp new file mode 100644 index 00000000..99f55527 --- /dev/null +++ b/backend/src/sys/intrinsics.hpp @@ -0,0 +1,210 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_INTRINSICS_H__ +#define __PF_INTRINSICS_H__ + +#include "sys/platform.hpp" +#include <xmmintrin.h> +#include <emmintrin.h> + +#if defined(__MSVC__) + +#include <intrin.h> + +#define PF_COMPILER_WRITE_BARRIER _WriteBarrier() +#define PF_COMPILER_READ_WRITE_BARRIER _ReadWriteBarrier() + +#if _MSC_VER >= 1400 +#pragma intrinsic(_ReadBarrier) +#define PF_COMPILER_READ_BARRIER _ReadBarrier() +#else +#define PF_COMPILER_READ_BARRIER _ReadWriteBarrier() +#endif /* _MSC_VER >= 1400 */ + +INLINE int __bsf(int v) { + unsigned long r = 0; _BitScanForward(&r,v); return r; +} + +INLINE int __bsr(int v) { + unsigned long r = 0; _BitScanReverse(&r,v); return r; +} + +INLINE int __btc(int v, int i) { + long r = v; _bittestandcomplement(&r,i); return r; +} + +INLINE int __bts(int v, int i) { + long r = v; _bittestandset(&r,i); return r; +} + +INLINE int __btr(int v, int i) { + long r = v; _bittestandreset(&r,i); return r; +} + +INLINE void memoryFence(void) { _mm_mfence(); } + +#if defined(__X86_64__) && !defined(__INTEL_COMPILER) + +INLINE size_t __bsf(size_t v) { + unsigned long r = 0; _BitScanForward64(&r,v); return r; +} + +INLINE size_t __bsr(size_t v) { + unsigned long r = 0; _BitScanReverse64(&r,v); return r; +} + +INLINE size_t __btc(size_t v, size_t i) { + __int64 r = v; _bittestandcomplement64(&r,i); return r; +} + +INLINE size_t __bts(size_t v, size_t i) { + __int64 r = v; _bittestandset64(&r,i); return r; +} + +INLINE size_t __btr(size_t v, size_t i) { + __int64 r = v; _bittestandreset64(&r,i); return r; +} + +#endif /* defined(__X86_64__) && !defined(__INTEL_COMPILER) */ + +typedef int32 atomic32_t; + +INLINE int32 atomic_add(volatile int32* m, const int32 v) { + return _InterlockedExchangeAdd((volatile long*)m,v); +} + +INLINE int32 atomic_cmpxchg(volatile int32* m, const int32 v, const int32 c) { + return _InterlockedCompareExchange((volatile long*)m,v,c); +} + +#if defined(__X86_64__) + +typedef int64 atomic_t; + +INLINE int64 atomic_add(volatile int64* m, const int64 v) { + return _InterlockedExchangeAdd64(m,v); +} + +INLINE int64 atomic_cmpxchg(volatile int64* m, const int64 v, const int64 c) { + return _InterlockedCompareExchange64(m,v,c); +} + +#else + +typedef int32 atomic_t; + +#endif /* defined(__X86_64__) */ + +#else + +INLINE unsigned int __popcnt(unsigned int in) { + int r = 0; asm ("popcnt %1,%0" : "=r"(r) : "r"(in)); return r; +} + +INLINE int __bsf(int v) { + int r = 0; asm ("bsf %1,%0" : "=r"(r) : "r"(v)); return r; +} + +INLINE int __bsr(int v) { + int r = 0; asm ("bsr %1,%0" : "=r"(r) : "r"(v)); return r; +} + +INLINE int __btc(int v, int i) { + int r = 0; asm ("btc %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r; +} + +INLINE int __bts(int v, int i) { + int r = 0; asm ("bts %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r; +} + +INLINE int __btr(int v, int i) { + int r = 0; asm ("btr %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r; +} + +INLINE size_t __bsf(size_t v) { + size_t r = 0; asm ("bsf %1,%0" : "=r"(r) : "r"(v)); return r; +} + +INLINE size_t __bsr(size_t v) { + size_t r = 0; asm ("bsr %1,%0" : "=r"(r) : "r"(v)); return r; +} + +INLINE size_t __btc(size_t v, size_t i) { + size_t r = 0; asm ("btc %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r; +} + +INLINE size_t __bts(size_t v, size_t i) { + size_t r = 0; asm ("bts %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r; +} + +INLINE size_t __btr(size_t v, size_t i) { + size_t r = 0; asm ("btr %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r; +} + +INLINE void memoryFence(void) { _mm_mfence(); } + +typedef int32 atomic32_t; + +INLINE int32 atomic_add(int32 volatile* value, int32 input) +{ asm volatile("lock xadd %0,%1" : "+r" (input), "+m" (*value) : "r" (input), "m" (*value)); return input; } + +INLINE int32 atomic_cmpxchg(int32 volatile* value, const int32 input, int32 comparand) +{ asm volatile("lock cmpxchg %2,%0" : "=m" (*value), "=a" (comparand) : "r" (input), "m" (*value), "a" (comparand) : "flags"); return comparand; } + +#if defined(__X86_64__) + + typedef int64 atomic_t; + + INLINE int64 atomic_add(int64 volatile* value, int64 input) + { asm volatile("lock xaddq %0,%1" : "+r" (input), "+m" (*value) : "r" (input), "m" (*value)); return input; } + + INLINE int64 atomic_cmpxchg(int64 volatile* value, const int64 input, int64 comparand) + { asm volatile("lock cmpxchgq %2,%0" : "+m" (*value), "+a" (comparand) : "r" (input), "m" (*value), "r" (comparand) : "flags"); return comparand; } + +#else + + typedef int32 atomic_t; + +#endif /* defined(__X86_64__) */ + +#define PF_COMPILER_READ_WRITE_BARRIER asm volatile("" ::: "memory"); +#define PF_COMPILER_WRITE_BARRIER PF_COMPILER_READ_WRITE_BARRIER +#define PF_COMPILER_READ_BARRIER PF_COMPILER_READ_WRITE_BARRIER + +#endif /* __MSVC__ */ + +template <typename T> +INLINE T __load_acquire(volatile T *ptr) +{ + PF_COMPILER_READ_WRITE_BARRIER; + T x = *ptr; // for x86, load == load_acquire + PF_COMPILER_READ_WRITE_BARRIER; + return x; +} + +template <typename T> +INLINE void __store_release(volatile T *ptr, T x) +{ + PF_COMPILER_READ_WRITE_BARRIER; + *ptr = x; // for x86, store == store_release + PF_COMPILER_READ_WRITE_BARRIER; +} +#endif /* __PF_INTRINSICS_H__ */ + diff --git a/backend/src/sys/library.cpp b/backend/src/sys/library.cpp new file mode 100644 index 00000000..815bd592 --- /dev/null +++ b/backend/src/sys/library.cpp @@ -0,0 +1,91 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "sys/library.hpp" +#include "sys/sysinfo.hpp" +#include "sys/filename.hpp" + +//////////////////////////////////////////////////////////////////////////////// +/// Windows Platform +//////////////////////////////////////////////////////////////////////////////// + +#if defined(__WIN32__) + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +namespace pf +{ + /* opens a shared library */ + lib_t openLibrary(const std::string& file) + { + std::string fullName = file+".dll"; + HMODULE handle = LoadLibraryA(fullName.c_str()); + if (handle) return lib_t(handle); + handle = LoadLibrary((getExecutableFileName() + fullName).c_str()); + return lib_t(handle); + } + + /* returns address of a symbol from the library */ + void* getSymbol(lib_t lib, const std::string& sym) { + return (void*) GetProcAddress(HMODULE(lib),sym.c_str()); + } + + /* closes the shared library */ + void closeLibrary(lib_t lib) { + FreeLibrary(HMODULE(lib)); + } +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Unix Platform +//////////////////////////////////////////////////////////////////////////////// + +#if defined(__UNIX__) + +#include <dlfcn.h> + +namespace pf +{ + /* opens a shared library */ + lib_t openLibrary(const std::string& file) + { +#if defined(__MACOSX__) + std::string fullName = "lib"+file+".dylib"; +#else + std::string fullName = "lib"+file+".so"; +#endif + void* lib = dlopen(fullName.c_str(),RTLD_NOW); + if (lib) return lib_t(lib); + lib = dlopen((getExecutableFileName() + fullName).c_str(),RTLD_NOW); + return lib_t(lib); + } + + /* returns address of a symbol from the library */ + void* getSymbol(lib_t lib, const std::string& sym) { + return dlsym(lib,sym.c_str()); + } + + /* closes the shared library */ + void closeLibrary(lib_t lib) { + dlclose(lib); + } +} +#endif diff --git a/backend/src/sys/library.hpp b/backend/src/sys/library.hpp new file mode 100644 index 00000000..8dcb1a93 --- /dev/null +++ b/backend/src/sys/library.hpp @@ -0,0 +1,40 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_LIBRARY_HPP__ +#define __PF_LIBRARY_HPP__ + +#include <string> + +#include "sys/platform.hpp" + +namespace pf +{ + /*! type for shared library */ + typedef struct opaque_lib_t* lib_t; + /*! loads a shared library */ + lib_t openLibrary(const std::string& file); + /*! returns address of a symbol from the library */ + void* getSymbol(lib_t lib, const std::string& sym); + /*! unloads a shared library */ + void closeLibrary(lib_t lib); +} /* namespace pf */ + +#endif /* __PF_LIBRARY_HPP__ */ + diff --git a/backend/src/sys/list.hpp b/backend/src/sys/list.hpp new file mode 100644 index 00000000..6f479d28 --- /dev/null +++ b/backend/src/sys/list.hpp @@ -0,0 +1,60 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_LIST_HPP__ +#define __PF_LIST_HPP__ + +#include "sys/platform.hpp" +#include <list> + +namespace pf +{ + /*! Use custom allocator instead of std one */ + template <typename T> + class list : public std::list<T, Allocator<T>> + { + public: + // Typedefs + typedef T value_type; + typedef Allocator<value_type> allocator_type; + typedef std::list<T, allocator_type> parent_type; + typedef typename allocator_type::size_type size_type; + + /*! Default constructor */ + INLINE explicit list(const allocator_type &a = allocator_type()) : + parent_type(a) {} + /*! Repetitive constructor */ + INLINE explicit list(size_type n, + const T &value = T(), + const allocator_type &a = allocator_type()) : + parent_type(n, value, a) {} + /*! Iteration constructor */ + template <class InputIterator> + INLINE list(InputIterator first, + InputIterator last, + const allocator_type &a = allocator_type()) : + parent_type(first, last, a) {} + /*! Copy constructor */ + INLINE list(const list &x) : parent_type(x) {} + PF_CLASS(list); + }; +} /* namespace pf */ + +#endif /* __PF_LIST_HPP__ */ + diff --git a/backend/src/sys/logging.cpp b/backend/src/sys/logging.cpp new file mode 100644 index 00000000..6f4c8401 --- /dev/null +++ b/backend/src/sys/logging.cpp @@ -0,0 +1,87 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "sys/logging.hpp" +#include "sys/filename.hpp" + +namespace pf +{ + LoggerStream::LoggerStream(void) : next(NULL) {} + LoggerStream::~LoggerStream(void) {} + + LoggerBuffer::LoggerBuffer(void) : logger(NULL) {} + + LoggerBuffer& LoggerBuffer::operator<< (LoggerFlushTy) { + logger->output(ss.str()); + ss.str(""); + return *this; + } + + LoggerBuffer& LoggerBuffer::operator<< (const LoggerInfo &info) { + FileName fileName(info.file); + return *this << fileName.base() << " at " << info.function << " line " << info.line; + } + + Logger::Logger(void) : streams(NULL) { + const uint32 threadNum = 1; + this->buffers = PF_NEW_ARRAY(LoggerBuffer, threadNum); + for (uint32 i = 0; i < threadNum; ++i) this->buffers[i].logger = this; + this->startTime = getSeconds(); + } + + Logger::~Logger(void) { + FATAL_IF(streams != NULL, "Remove all streams before deleting the logger"); + PF_DELETE_ARRAY(buffers); + } + + void Logger::output(const std::string &str) { + Lock<MutexSys> lock(mutex); + LoggerStream *stream = this->streams; + while (stream) { + *stream << str; + stream = stream->next; + } + } + + void Logger::insert(LoggerStream &stream) { + Lock<MutexSys> lock(mutex); + stream.next = this->streams; + this->streams = &stream; + } + + void Logger::remove(LoggerStream &stream) { + Lock<MutexSys> lock(mutex); + LoggerStream *curr = this->streams; + LoggerStream *pred = NULL; + while (curr) { + if (curr == &stream) + break; + pred = curr; + curr = curr->next; + } + FATAL_IF (curr == NULL, "Unable to find the given stream"); + if (pred) + pred->next = curr->next; + else + this->streams = curr->next; + } + + Logger *logger = NULL; +} /* namespace pf */ + diff --git a/backend/src/sys/logging.hpp b/backend/src/sys/logging.hpp new file mode 100644 index 00000000..ae69e321 --- /dev/null +++ b/backend/src/sys/logging.hpp @@ -0,0 +1,141 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_LOGGING_HPP__ +#define __PF_LOGGING_HPP__ + +#include "sys/mutex.hpp" +#include "sys/platform.hpp" +#include <sstream> +#include <iomanip> + +namespace pf +{ + class Logger; + class LoggerBuffer; + class LoggerStream; + + /*! A logger stream is one way to output a string. It can be a file, + * stdout, the in-game console and so on... + */ + class LoggerStream + { + public: + LoggerStream(void); + virtual ~LoggerStream(void); + virtual LoggerStream& operator<< (const std::string &str) = 0; + private: + friend class Logger; + LoggerStream *next; //!< We chain the logger elements together + }; + + /*! Helper and proxy structures to display various information */ + static struct LoggerFlushTy { } loggerFlush MAYBE_UNUSED; + struct LoggerInfo { + INLINE LoggerInfo(const char *file, const char *function, int line) : + file(file), function(function), line(line) {} + const char *file, *function; + int line; + PF_CLASS(LoggerInfo); + }; + + /*! Used to lazily create strings from the user defined logs. When destroyed + * or flushed, it displays everything in one piece + */ + class LoggerBuffer + { + public: + template <typename T> LoggerBuffer& operator<< (const T &x) { + ss << x; + return *this; + } + LoggerBuffer& operator<< (LoggerFlushTy); + LoggerBuffer& operator<< (const LoggerInfo&); + /*! Output the info a nice format */ + LoggerBuffer& info(const char *file, const char *function, int line); + private: + friend class Logger; + LoggerBuffer(void); + Logger *logger; //!< The logger that created this buffer + std::stringstream ss; //!< Stores all the user strings + PF_CLASS(LoggerBuffer); + }; + + /*! Central class to log anything from the engine */ + class Logger + { + public: + Logger(void); + ~Logger(void); + /*! Output the string into all the attached streams */ + void output(const std::string &str); + template <typename T> LoggerBuffer& operator<< (const T &x) { + const uint32 bufferID = 0; + LoggerBuffer &buffer = buffers[bufferID]; + buffer << "[" << "thread " << std::setw(2) << bufferID << "] "; + buffer << "[" << std::setw(12) << std::fixed << getSeconds() - startTime << "s] " << x; + return buffer; + } + void insert(LoggerStream &stream); + void remove(LoggerStream &stream); + private: + MutexSys mutex; //!< To insert / remove streams and output strings + LoggerStream *streams; //!< All the output streams + LoggerBuffer *buffers; //!< One buffer per thread + double startTime; //!< When the logger has been created + PF_CLASS(Logger); + }; + + /*! We have one logger for the application */ + extern Logger *logger; + +} /* namespace pf */ + +/*! Macros to handle logging information in the code */ +#define PF_LOG_HERE LoggerInfo(__FILE__, __FUNCTION__, __LINE__) +#define PF_INFO " ######## " << PF_LOG_HERE + +/*! Verbose macros: they add logging position and thread ID */ +#define PF_WARNING_V(MSG) do { \ + if (logger) *logger << "WARNING " << MSG << PF_INFO << "\n" << loggerFlush; \ +} while (0) + +#define PF_ERROR_V(MSG) do { \ + if (logger) *logger << "ERROR " << MSG << PF_INFO << "\n" << loggerFlush; \ +} while (0) + +#define PF_MSG_V(MSG) do { \ + if (logger) *logger << MSG << PF_INFO << "\n" << loggerFlush; \ +} while (0) + +/*! Regular macros: just the user message */ +#define PF_WARNING(MSG) do { \ + if (logger) *logger << "WARNING " << MSG << "\n" << loggerFlush; \ +} while (0) + +#define PF_ERROR(MSG) do { \ + if (logger) *logger << "ERROR " << MSG << "\n" << loggerFlush; \ +} while (0) + +#define PF_MSG(MSG) do { \ + if (logger) *logger << MSG << "\n" << loggerFlush; \ +} while (0) + +#endif /* __PF_LOGGING_HPP__ */ + diff --git a/backend/src/sys/map.hpp b/backend/src/sys/map.hpp new file mode 100644 index 00000000..c673b86f --- /dev/null +++ b/backend/src/sys/map.hpp @@ -0,0 +1,63 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_MAP_HPP__ +#define __PF_MAP_HPP__ + +#include "sys/platform.hpp" +#include <map> + +namespace pf +{ + /*! Use custom allocator instead of std one */ + template<class Key, class T, class Pred = std::less<Key>> + class map : public std::map<Key,T,Pred,Allocator<std::pair<const Key, T>>> + { + public: + // Typedefs + typedef std::pair<const Key, T> value_type; + typedef Allocator<value_type> allocator_type; + typedef std::map<Key,T,Pred,allocator_type> parent_type; + typedef Key key_type; + typedef T mapped_type; + typedef Pred key_compare; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + + /*! Default constructor */ + INLINE map(const key_compare &comp = key_compare(), + const allocator_type &a = allocator_type()) : + parent_type(comp, a) {} + /*! Iteration constructor */ + template<class InputIterator> + INLINE map(InputIterator first, + InputIterator last, + const key_compare &comp = key_compare(), + const allocator_type& a = allocator_type()) : + parent_type(first, last, comp, a) {} + /*! Copy constructor */ + INLINE map(const map& x) : parent_type(x) {} + PF_CLASS(map); + }; +} /* namespace pf */ + +#endif /* __PF_MAP_HPP__ */ + diff --git a/backend/src/sys/mutex.cpp b/backend/src/sys/mutex.cpp new file mode 100644 index 00000000..590ad5d4 --- /dev/null +++ b/backend/src/sys/mutex.cpp @@ -0,0 +1,49 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "sys/mutex.hpp" + +#if defined(__WIN32__) + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +namespace pf +{ + /*! system mutex using windows API */ + MutexSys::MutexSys( void ) { mutex = new CRITICAL_SECTION; InitializeCriticalSection((CRITICAL_SECTION*)mutex); } + MutexSys::~MutexSys( void ) { DeleteCriticalSection((CRITICAL_SECTION*)mutex); delete ((CRITICAL_SECTION*)mutex); } + void MutexSys::lock( void ) { EnterCriticalSection((CRITICAL_SECTION*)mutex); } + void MutexSys::unlock( void ) { LeaveCriticalSection((CRITICAL_SECTION*)mutex); } +} +#endif + +#if defined(__UNIX__) +#include <pthread.h> + +namespace pf +{ + /*! system mutex using pthreads */ + MutexSys::MutexSys( void ) { mutex = new pthread_mutex_t; pthread_mutex_init((pthread_mutex_t*)mutex, NULL); } + MutexSys::~MutexSys( void ) { pthread_mutex_destroy((pthread_mutex_t*)mutex); delete ((pthread_mutex_t*)mutex); } + void MutexSys::lock( void ) { pthread_mutex_lock((pthread_mutex_t*)mutex); } + void MutexSys::unlock( void ) { pthread_mutex_unlock((pthread_mutex_t*)mutex); } +} +#endif + diff --git a/backend/src/sys/mutex.hpp b/backend/src/sys/mutex.hpp new file mode 100644 index 00000000..b29b3c88 --- /dev/null +++ b/backend/src/sys/mutex.hpp @@ -0,0 +1,75 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_MUTEX_H__ +#define __PF_MUTEX_H__ + +#include "platform.hpp" +#include "atomic.hpp" +#include <xmmintrin.h> + +namespace pf +{ + class MutexSys { + friend class ConditionSys; + public: + MutexSys(void); + ~MutexSys(void); + void lock(void); + void unlock(void); + protected: + void* mutex; + MutexSys(const MutexSys&); // don't implement + MutexSys& operator= (const MutexSys&); // don't implement + PF_CLASS(MutexSys); + }; + + /*! active mutex */ + class MutexActive { + public: + INLINE MutexActive(void) : $lock(LOCK_IS_FREE) {} + INLINE void lock(void) { + PF_COMPILER_READ_BARRIER; + while (cmpxchg($lock, LOCK_IS_TAKEN, LOCK_IS_FREE) != LOCK_IS_FREE) + _mm_pause(); + PF_COMPILER_READ_BARRIER; + } + INLINE void unlock(void) { $lock.storeRelease(LOCK_IS_FREE); } + protected: + enum ${ LOCK_IS_FREE = 0, LOCK_IS_TAKEN = 1 }; + Atomic $lock; + MutexActive(const MutexActive&); // don't implement + MutexActive& operator=(const MutexActive&); // don't implement + PF_CLASS(MutexActive); + }; + + /*! safe mutex lock and unlock helper */ + template<typename Mutex> class Lock { + public: + Lock (Mutex& mutex) : mutex(mutex) { mutex.lock(); } + ~Lock() { mutex.unlock(); } + protected: + Mutex& mutex; + Lock(const Lock&); // don't implement + Lock& operator= (const Lock&); // don't implement + PF_CLASS(Lock); + }; +} + +#endif diff --git a/backend/src/sys/platform.cpp b/backend/src/sys/platform.cpp new file mode 100644 index 00000000..96fab95a --- /dev/null +++ b/backend/src/sys/platform.cpp @@ -0,0 +1,79 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "sys/platform.hpp" +#include "sys/intrinsics.hpp" +#include <string> + +//////////////////////////////////////////////////////////////////////////////// +/// Windows Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __WIN32__ + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +namespace pf +{ + double getSeconds() { + LARGE_INTEGER freq, val; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&val); + return (double)val.QuadPart / (double)freq.QuadPart; + } + + void FATAL(const std::string &msg) { + std::cerr << msg << std::endl; + MessageBox(NULL, msg.c_str(), "Fatal Error", MB_OK | MB_ICONEXCLAMATION); + PF_ASSERT(0); +#ifdef __GNUC__ + exit(-1); +#else + _exit(-1); +#endif /* __GNUC__ */ + } + +} /* namespace pf */ +#endif /* __WIN32__ */ + +//////////////////////////////////////////////////////////////////////////////// +/// Unix Platform +//////////////////////////////////////////////////////////////////////////////// + +#if defined(__UNIX__) + +#include <sys/time.h> + +namespace pf +{ + double getSeconds() { + struct timeval tp; gettimeofday(&tp,NULL); + return double(tp.tv_sec) + double(tp.tv_usec)/1E6; + } + + void FATAL(const std::string &msg) { + std::cerr << msg << std::endl; + PF_ASSERT(0); + _exit(-1); + } +} /* namespace pf */ + +#endif /* __UNIX__ */ + diff --git a/backend/src/sys/platform.hpp b/backend/src/sys/platform.hpp new file mode 100644 index 00000000..ecd205fb --- /dev/null +++ b/backend/src/sys/platform.hpp @@ -0,0 +1,373 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_PLATFORM_HPP__ +#define __PF_PLATFORM_HPP__ +#include <cstddef> +#include <cstdlib> +#include <cstdio> +#include <iostream> +#include <cassert> + +//////////////////////////////////////////////////////////////////////////////// +/// CPU architecture +//////////////////////////////////////////////////////////////////////////////// + +/* detect 32 or 64 platform */ +#if defined(__x86_64__) || defined(__ia64__) || defined(_M_X64) +#define __X86_64__ +#else +#define __X86__ +#endif + +/* We require SSE ... */ +#ifndef __SSE__ +#define __SSE__ +#endif + +/* ... and SSE2 */ +#ifndef __SSE2__ +#define __SSE2__ +#endif + +#if defined(_INCLUDED_IMM) +// #define __AVX__ +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1600) && !defined(__INTEL_COMPILER) || defined(_DEBUG) && defined(_WIN32) +#define __NO_AVX__ +#endif + +#if defined(_MSC_VER) && !defined(__SSE4_2__) +// #define __SSE4_2__ //! activates SSE4.2 support +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Operating system +//////////////////////////////////////////////////////////////////////////////// + +/* detect Linux platform */ +#if defined(linux) || defined(__linux__) || defined(__LINUX__) +# if !defined(__LINUX__) +# define __LINUX__ +# endif +# if !defined(__UNIX__) +# define __UNIX__ +# endif +#endif + +/* detect FreeBSD platform */ +#if defined(__FreeBSD__) || defined(__FREEBSD__) +# if !defined(__FREEBSD__) +# define __FREEBSD__ +# endif +# if !defined(__UNIX__) +# define __UNIX__ +# endif +#endif + +/* detect Windows 95/98/NT/2000/XP/Vista/7 platform */ +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)) && !defined(__CYGWIN__) +# if !defined(__WIN32__) +# define __WIN32__ +# endif +#endif + +/* detect Cygwin platform */ +#if defined(__CYGWIN__) +# if !defined(__UNIX__) +# define __UNIX__ +# endif +#endif + +/* detect MAC OS X platform */ +#if defined(__APPLE__) || defined(MACOSX) || defined(__MACOSX__) +# if !defined(__MACOSX__) +# define __MACOSX__ +# endif +# if !defined(__UNIX__) +# define __UNIX__ +# endif +#endif + +/* try to detect other Unix systems */ +#if defined(__unix__) || defined (unix) || defined(__unix) || defined(_unix) +# if !defined(__UNIX__) +# define __UNIX__ +# endif +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Compiler +//////////////////////////////////////////////////////////////////////////////// + +/*! GCC compiler */ +#ifdef __GNUC__ +// #define __GNUC__ +#endif + +/*! Intel compiler */ +#ifdef __INTEL_COMPILER +#define __ICC__ +#endif + +/*! Visual C compiler */ +#ifdef _MSC_VER +#define __MSVC__ +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Makros +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __WIN32__ +#define __dllexport extern "C" __declspec(dllexport) +#define __dllimport extern "C" __declspec(dllimport) +#else +#define __dllexport extern "C" +#define __dllimport extern "C" +#endif + +#ifdef __MSVC__ +#undef NOINLINE +#define NOINLINE __declspec(noinline) +#define INLINE __forceinline +#define RESTRICT __restrict +#define THREAD __declspec(thread) +#define ALIGNED(...) __declspec(align(__VA_ARGS__)) +//#define __FUNCTION__ __FUNCTION__ +#define debugbreak() __debugbreak() +#else +#undef NOINLINE +#undef INLINE +#define NOINLINE __attribute__((noinline)) +#define INLINE inline __attribute__((always_inline)) +#define RESTRICT __restrict +#define THREAD __thread +#define ALIGNED(...) __attribute__((aligned(__VA_ARGS__))) +#define __FUNCTION__ __PRETTY_FUNCTION__ +#define debugbreak() asm ("int $3") +#endif + +/*! Modern x86 processors */ +#define CACHE_LINE 64 +#define CACHE_LINE_ALIGNED ALIGNED(CACHE_LINE) + +#ifdef __GNUC__ + #define MAYBE_UNUSED __attribute__((used)) +#else + #define MAYBE_UNUSED +#endif + +#if defined(_MSC_VER) +#define __builtin_expect(expr,b) expr +#endif + +/*! Debug syntactic sugar */ +#ifdef NDEBUG +#define IF_DEBUG(EXPR) +#else +#define IF_DEBUG(EXPR) EXPR +#endif /* NDEBUG */ + +/*! Debug printing macros */ +#define STRING(x) #x +#define PING std::cout << __FILE__ << " (" << __LINE__ << "): " << __FUNCTION__ << std::endl +#define PRINT(x) std::cout << STRING(x) << " = " << (x) << std::endl + +/*! Branch hint */ +#define LIKELY(x) __builtin_expect(!!(x),1) +#define UNLIKELY(x) __builtin_expect((x),0) + +/*! Stringify macros */ +#define JOIN(X, Y) _DO_JOIN(X, Y) +#define _DO_JOIN(X, Y) _DO_JOIN2(X, Y) +#define _DO_JOIN2(X, Y) X##Y + +/*! Run-time assertion */ +#ifndef NDEBUG +#define PF_ASSERT(EXPR) do { \ + if (UNLIKELY(!(EXPR))) assert(EXPR); \ +} while (0) +#else +#define PF_ASSERT(EXPR) do { } while (0) +#endif + +/*! Compile-time assertion */ +#define STATIC_ASSERT(value) \ + struct JOIN(__,JOIN(__,__LINE__)) { int x[(value) ? 1 : -1]; } + +/*! Fatal error macros */ +#define NOT_IMPLEMENTED FATAL ("Not implemented") +#define FATAL_IF(COND, MSG) \ +do { \ + if(UNLIKELY(COND)) FATAL(MSG); \ +} while (0) + +/* Safe deletion macros */ +#define PF_SAFE_DELETE_ARRAY(x) do { if (x != NULL) PF_DELETE_ARRAY(x); } while (0) +#define PF_SAFE_DELETE(x) do { if (x != NULL) PF_DELETE(x); } while (0) + +/* Number of elements in an array */ +#define ARRAY_ELEM_NUM(x) (sizeof(x) / sizeof(x[0])) + +/* Align X on A */ +#define ALIGN(X,A) (((X) % (A)) ? ((X) + (A) - ((X) % (A))) : (X)) + +/*! Produce a string from the macro locatiom */ +#define HERE (STRING(__LINE__) "@" __FILE__) + +/*! Portable AlignOf */ +template <typename T> +struct AlignOf +{ + struct Helper { char x; T t; }; + static const size_t value = offsetof(Helper, t); +}; + +//////////////////////////////////////////////////////////////////////////////// +/// Visibility parameters (DLL export and so on) +//////////////////////////////////////////////////////////////////////////////// +#if defined __WIN32__ + #if defined __GNUC__ + #define PF_EXPORT_SYMBOL __attribute__ ((dllexport)) + #define PF_IMPORT_SYMBOL __attribute__ ((dllimport)) + #else + #define PF_IMPORT_SYMBOL __declspec(dllimport) + #define PF_EXPORT_SYMBOL __declspec(dllexport) + #endif /* __GNUC__ */ +#else + #define PF_EXPORT_SYMBOL __attribute__ ((visibility ("default"))) + #define PF_IMPORT_SYMBOL +#endif /* __WIN32__ */ + +//////////////////////////////////////////////////////////////////////////////// +/// Basic Types +//////////////////////////////////////////////////////////////////////////////// + +#if defined(__MSVC__) +typedef __int64 int64; +typedef unsigned __int64 uint64; +typedef __int32 int32; +typedef unsigned __int32 uint32; +typedef __int16 int16; +typedef unsigned __int16 uint16; +typedef __int8 int8; +typedef unsigned __int8 uint8; +#else +typedef long long int64; +typedef unsigned long long uint64; +typedef int int32; +typedef unsigned int uint32; +typedef short int16; +typedef unsigned short uint16; +typedef char int8; +typedef unsigned char uint8; +#endif + +#if defined(__X86_64__) +typedef int64 index_t; +#else +typedef int32 index_t; +#endif + +/*! To protect some classes from being copied */ +class NonCopyable +{ +protected: + INLINE NonCopyable(void) {} + INLINE ~NonCopyable(void) {} +private: + INLINE NonCopyable(const NonCopyable&) {} + INLINE NonCopyable& operator= (const NonCopyable&) {return *this;} +}; + +//////////////////////////////////////////////////////////////////////////////// +/// Disable some compiler warnings +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __ICC__ +#pragma warning(disable:265) // floating-point operation result is out of range +#pragma warning(disable:383) // value copied to temporary, reference to temporary used +#pragma warning(disable:869) // parameter was never referenced +#pragma warning(disable:981) // operands are evaluated in unspecified order +#pragma warning(disable:1418) // external function definition with no prior declaration +#pragma warning(disable:1419) // external declaration in primary source file +#pragma warning(disable:1572) // floating-point equality and inequality comparisons are unreliable +#pragma warning(disable:1125) // virtual function override intended? +#endif /* __ICC__ */ + +//////////////////////////////////////////////////////////////////////////////// +/// Default Includes and Functions +//////////////////////////////////////////////////////////////////////////////// + +#include "sys/constants.hpp" +#include "sys/alloc.hpp" + +namespace pf +{ + /*! selects */ + INLINE bool select(bool s, bool t , bool f) { return s ? t : f; } + INLINE int select(bool s, int t, int f) { return s ? t : f; } + INLINE float select(bool s, float t, float f) { return s ? t : f; } + + /*! Fatal error function */ + void FATAL(const std::string&); + + /*! Return the next power of 2 */ + INLINE uint32 nextHighestPowerOf2(uint32 x) { + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return ++x; + } + + INLINE uint32 logi2(uint32 x) { + uint32 r = 0; + while(x >>= 1) r++; + return r; + } + + template<uint32 N> + INLINE uint32 isPowerOf(uint32 i) { + while (i > 1) { + if (i%N) return false; + i = i/N; + } + return true; + } + template<> INLINE uint32 isPowerOf<2>(uint32 i) { return ((i-1)&i) == 0; } + + /*! random functions */ + template<typename T> T random() { return T(0); } + template<> INLINE int random() { return int(rand()); } + template<> INLINE uint32 random() { return uint32(rand()); } + template<> INLINE float random() { return random<uint32>()/float(RAND_MAX); } + template<> INLINE double random() { return random<uint32>()/double(RAND_MAX); } + + /** returns performance counter in seconds */ + double getSeconds(); + +} /* namespace pf */ + +#endif /* __PF_PLATFORM_HPP__ */ + diff --git a/backend/src/sys/ref.hpp b/backend/src/sys/ref.hpp new file mode 100644 index 00000000..1672f543 --- /dev/null +++ b/backend/src/sys/ref.hpp @@ -0,0 +1,99 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_REF_HPP__ +#define __PF_REF_HPP__ + +#include "sys/atomic.hpp" +#include "sys/alloc.hpp" + +namespace pf +{ + class RefCount + { + public: + RefCount() : refCounter(0) {} + virtual ~RefCount() {} + INLINE void refInc() { refCounter++; } + INLINE bool refDec() { return !(--refCounter); } + Atomic32 refCounter; + }; + + //////////////////////////////////////////////////////////////////////////////// + /// Reference to single object + //////////////////////////////////////////////////////////////////////////////// + + template<typename Type> + class Ref { + public: + Type* const ptr; + + //////////////////////////////////////////////////////////////////////////////// + /// Constructors, Assignment & Cast Operators + //////////////////////////////////////////////////////////////////////////////// + + INLINE Ref(void) : ptr(NULL) {} + INLINE Ref(NullTy) : ptr(NULL) {} + INLINE Ref(const Ref& input) : ptr(input.ptr) { if ( ptr ) ptr->refInc(); } + INLINE Ref(Type* const input) : ptr(input) { if (ptr) ptr->refInc(); } + INLINE ~Ref(void) { if (ptr && ptr->refDec()) PF_DELETE(ptr); } + + INLINE Ref& operator= (const Ref &input) { + if (input.ptr) input.ptr->refInc(); + if (ptr && ptr->refDec()) PF_DELETE(ptr); + *(Type**)&ptr = input.ptr; + return *this; + } + + INLINE Ref& operator= (NullTy) { + if (ptr && ptr->refDec()) DELETE(ptr); + *(Type**)&ptr = NULL; + return *this; + } + + INLINE operator bool(void) const { return ptr != NULL; } + INLINE operator Type*(void) const { return ptr; } + + //////////////////////////////////////////////////////////////////////////////// + /// Properties + //////////////////////////////////////////////////////////////////////////////// + + INLINE const Type& operator* (void) const { return *ptr; } + INLINE const Type* operator-> (void) const { return ptr; } + INLINE Type& operator* (void) { return *ptr; } + INLINE Type* operator-> (void) { return ptr; } + + template<typename TypeOut> + INLINE Ref<TypeOut> cast() { return Ref<TypeOut>(static_cast<TypeOut*>(ptr)); } + template<typename TypeOut> + INLINE const Ref<TypeOut> cast() const { return Ref<TypeOut>(static_cast<TypeOut*>(ptr)); } + PF_CLASS(Ref); + }; + + template<typename Type> INLINE bool operator< ( const Ref<Type>& a, const Ref<Type>& b ) { return a.ptr < b.ptr ; } + template<typename Type> INLINE bool operator== ( const Ref<Type>& a, NullTy ) { return a.ptr == NULL ; } + template<typename Type> INLINE bool operator== ( NullTy , const Ref<Type>& b ) { return NULL == b.ptr ; } + template<typename Type> INLINE bool operator== ( const Ref<Type>& a, const Ref<Type>& b ) { return a.ptr == b.ptr ; } + template<typename Type> INLINE bool operator!= ( const Ref<Type>& a, NullTy ) { return a.ptr != NULL ; } + template<typename Type> INLINE bool operator!= ( NullTy , const Ref<Type>& b ) { return NULL != b.ptr ; } + template<typename Type> INLINE bool operator!= ( const Ref<Type>& a, const Ref<Type>& b ) { return a.ptr != b.ptr ; } +} + +#endif /* __PF_REF_HPP__ */ + diff --git a/backend/src/sys/set.hpp b/backend/src/sys/set.hpp new file mode 100644 index 00000000..efaf7ed3 --- /dev/null +++ b/backend/src/sys/set.hpp @@ -0,0 +1,59 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_SET_HPP__ +#define __PF_SET_HPP__ + +#include "sys/platform.hpp" +#include <set> + +namespace pf +{ + /*! Add our custom allocator to std::set */ + template<class Key, class Pred = std::less<Key>> + class set : public std::set<Key,Pred,Allocator<Key>> + { + public: + // Typedefs + typedef Key value_type; + typedef Allocator<value_type> allocator_type; + typedef std::set<Key,Pred,Allocator<Key>> parent_type; + typedef Key key_type; + typedef Pred key_compare; + + /*! Default constructor */ + INLINE set(const key_compare &comp = key_compare(), + const allocator_type &a = allocator_type()) : + parent_type(comp, a) {} + /*! Iteration constructor */ + template<class InputIterator> + INLINE set(InputIterator first, + InputIterator last, + const key_compare &comp = key_compare(), + const allocator_type& a = allocator_type()) : + parent_type(first, last, comp, a) {} + /*! Copy constructor */ + INLINE set(const set& x) : parent_type(x) {} + PF_CLASS(set); + }; + +} /* namespace pf */ + +#endif /* __PF_SET_HPP__ */ + diff --git a/backend/src/sys/string.cpp b/backend/src/sys/string.cpp new file mode 100644 index 00000000..093bb267 --- /dev/null +++ b/backend/src/sys/string.cpp @@ -0,0 +1,130 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "sys/string.hpp" +#include "sys/filename.hpp" + +#include <cstdio> +#include <cctype> +#include <istream> +#include <fstream> +#include <algorithm> + +namespace std +{ + char to_lower(char c) { return char(tolower(int(c))); } + char to_upper(char c) { return char(toupper(int(c))); } + string strlwr(const string& s) { + string dst(s); + std::transform(dst.begin(), dst.end(), dst.begin(), to_lower); + return dst; + } + string strupr(const string& s) { + string dst(s); + std::transform(dst.begin(), dst.end(), dst.begin(), to_upper); + return dst; + } + +} +namespace pf +{ + /* $Id: strtok_r.c,v 1.1 2003/12/03 15:22:23 chris_reid Exp $ */ + /* + * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Hgskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + char* tokenize(char *s1, const char *s2, char **lasts) + { + char *ret; + + if (s1 == NULL) + s1 = *lasts; + while(*s1 && strchr(s2, *s1)) + ++s1; + if(*s1 == '\0') + return NULL; + ret = s1; + while(*s1 && !strchr(s2, *s1)) + ++s1; + if(*s1) + *s1++ = '\0'; + *lasts = s1; + return ret; + } + + bool strequal(const char *s1, const char *s2) { + if (strcmp(s1, s2) == 0) return true; + return false; + } + + bool contains(const char *haystack, const char *needle) { + if (strstr(haystack, needle) == NULL) return false; + return true; + } + + std::string loadFile(const FileName &path) + { + std::ifstream stream(path.c_str(), std::istream::in); + if (stream.is_open() == false) + return std::string(); + std::string str = loadFile(stream); + stream.close(); + return str; + } + + std::string loadFile(std::ifstream &stream) + { + PF_ASSERT(stream.is_open()); + std::string line; + std::stringstream text; + while (std::getline(stream, line)) + text << "\n" << line; + stream.close(); + return text.str(); + } +} + diff --git a/backend/src/sys/string.hpp b/backend/src/sys/string.hpp new file mode 100644 index 00000000..04479667 --- /dev/null +++ b/backend/src/sys/string.hpp @@ -0,0 +1,53 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_STRING_H__ +#define __PF_STRING_H__ + +#include "sys/platform.hpp" +#include "sys/filename.hpp" + +#include <cstring> +#include <string> +#include <sstream> +#include <fstream> + +namespace std +{ + string strlwr(const string& s); + string strupr(const string& s); + + template<typename T> INLINE string stringOf(const T& v) { + stringstream s; s << v; return s.str(); + } +} +namespace pf +{ + /*! Compare two strings */ + bool strequal(const char *s1, const char *s2); + /*! Say if needle is in haystack */ + bool contains(const char *haystack, const char *needle); + /*! Tokenize a string (like strtok_r does) */ + char* tokenize(char *s1, const char *s2, char **lasts); + /*! Load a file from its path and copies it into a string */ + std::string loadFile(const FileName &path); + /*! Load a file from a stream and copies it into a string */ + std::string loadFile(std::ifstream &stream); +} +#endif diff --git a/backend/src/sys/sysinfo.cpp b/backend/src/sys/sysinfo.cpp new file mode 100644 index 00000000..15a56095 --- /dev/null +++ b/backend/src/sys/sysinfo.cpp @@ -0,0 +1,148 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "sys/sysinfo.hpp" + +//////////////////////////////////////////////////////////////////////////////// +/// All Platforms +//////////////////////////////////////////////////////////////////////////////// + +namespace pf +{ + /* return platform name */ + std::string getPlatformName() { +#if defined(__LINUX__) && !defined(__X86_64__) + return "Linux (32bit)"; +#elif defined(__LINUX__) && defined(__X86_64__) + return "Linux (64bit)"; +#elif defined(__FREEBSD__) && !defined(__X86_64__) + return "FreeBSD (32bit)"; +#elif defined(__FREEBSD__) && defined(__X86_64__) + return "FreeBSD (64bit)"; +#elif defined(__CYGWIN__) && !defined(__X86_64__) + return "Cygwin (32bit)"; +#elif defined(__CYGWIN__) && defined(__X86_64__) + return "Cygwin (64bit)"; +#elif defined(__WIN32__) && !defined(__X86_64__) + return "Windows (32bit)"; +#elif defined(__WIN32__) && defined(__X86_64__) + return "Windows (64bit)"; +#elif defined(__MACOSX__) && !defined(__X86_64__) + return "MacOS (32bit)"; +#elif defined(__MACOSX__) && defined(__X86_64__) + return "MacOS (64bit)"; +#elif defined(__UNIX__) && !defined(__X86_64__) + return "Unix (32bit)"; +#elif defined(__UNIX__) && defined(__X86_64__) + return "Unix (64bit)"; +#else + return "Unknown"; +#endif + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Windows Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __WIN32__ + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +namespace pf +{ + /* get the full path to the running executable */ + std::string getExecutableFileName() { + char filename[1024]; + if (!GetModuleFileName(NULL, filename, sizeof(filename))) return std::string(); + return std::string(filename); + } + + /* return the number of logical threads of the system */ + int getNumberOfLogicalThreads() { + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; + } +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Linux Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __LINUX__ + +#include <stdio.h> +#include <unistd.h> + +namespace pf +{ + /* get the full path to the running executable */ + std::string getExecutableFileName() { + char pid[32]; sprintf(pid, "/proc/%d/exe", getpid()); + char buf[1024]; + int bytes = readlink(pid, buf, sizeof(buf)-1); + if (bytes != -1) buf[bytes] = '\0'; + return std::string(buf); + } +} + +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// MacOS Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __MACOSX__ + +#include <mach-o/dyld.h> + +namespace pf +{ + /* get the full path to the running executable */ + std::string getExecutableFileName() + { + char buf[1024]; + uint32_t size = sizeof(buf); + if (_NSGetExecutablePath(buf, &size) != 0) return std::string(); + return std::string(buf); + } +} + +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Unix Platform +//////////////////////////////////////////////////////////////////////////////// + +#if defined(__UNIX__) + +#include <unistd.h> + +namespace pf +{ + /* return the number of logical threads of the system */ + int getNumberOfLogicalThreads() { + return sysconf(_SC_NPROCESSORS_CONF); + } +} +#endif + diff --git a/backend/src/sys/sysinfo.hpp b/backend/src/sys/sysinfo.hpp new file mode 100644 index 00000000..5679ddb0 --- /dev/null +++ b/backend/src/sys/sysinfo.hpp @@ -0,0 +1,37 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_SYSINFO_H__ +#define __PF_SYSINFO_H__ + +#include "sys/platform.hpp" + +#include <string> + +namespace pf +{ + /*! get the full path to the running executable */ + std::string getExecutableFileName(); + /*! return platform name */ + std::string getPlatformName(); + /*! return the number of logical threads of the system */ + int getNumberOfLogicalThreads(); +} + +#endif diff --git a/backend/src/sys/thread.cpp b/backend/src/sys/thread.cpp new file mode 100644 index 00000000..12503ce3 --- /dev/null +++ b/backend/src/sys/thread.cpp @@ -0,0 +1,213 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include <iostream> + +#include "sys/thread.hpp" +#include "sys/sysinfo.hpp" + +//////////////////////////////////////////////////////////////////////////////// +/// Windows Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __WIN32__ + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +namespace pf +{ + /*! creates a hardware thread running on specific core */ + thread_t createThread(thread_func f, void* arg, size_t stack_size, int affinity) + { + HANDLE handle = CreateThread(NULL,stack_size,(LPTHREAD_START_ROUTINE)f,arg,0,NULL); + if (handle == NULL) + FATAL("createThread error"); + if (affinity < 0) return thread_t(handle); + + // set thread affinity + int thread = affinity % 64; + SetThreadAffinityMask(handle, DWORD_PTR(1L << thread)); + + return thread_t(handle); + } + + void setAffinity(int affinity) { + if (affinity >= 0) SetThreadAffinityMask(GetCurrentThread(), DWORD_PTR(1L << affinity)); + } + + void yield(int time) { Sleep(time); } + + void join(thread_t tid) { + WaitForSingleObject(HANDLE(tid), INFINITE); + CloseHandle(HANDLE(tid)); + } + + void destroyThread(thread_t tid) { + TerminateThread(HANDLE(tid),0); + CloseHandle(HANDLE(tid)); + } + + tls_t createTls() { return tls_t(TlsAlloc()); } + + void setTls(tls_t tls, void* const ptr) { + TlsSetValue(DWORD(size_t(tls)), ptr); + } + + void* getTls(tls_t tls) { + return TlsGetValue(DWORD(size_t(tls))); + } + + void destroyTls(tls_t tls) { + TlsFree(DWORD(size_t(tls))); + } +} + +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Linux Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __LINUX__ +namespace pf +{ + /*! set affinity of the calling thread */ + void setAffinity(int affinity) + { + int wrap = getNumberOfLogicalThreads()/2; + affinity = (affinity/2) + wrap*(affinity%2); + if (affinity >= 0 && affinity < 64*64) { + union { uint64 u; cpu_set_t set; } mask[64]; + for (size_t i=0; i<64; i++) mask[i].u = 0; + mask[affinity/64].u= uint64(1) << (affinity % 64); + if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask[0].set) < 0) + std::cerr << "Thread: cannot set affinity" << std::endl; + } + } +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// MacOSX Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __MACOSX__ + +#include <mach/thread_act.h> +#include <mach/thread_policy.h> +#include <mach/mach_init.h> + +namespace pf +{ + /*! set affinity of the calling thread */ + void setAffinity(int affinity) + { + if (affinity >= 0) { + thread_affinity_policy ap; + ap.affinity_tag = affinity; + if (thread_policy_set(mach_thread_self(),THREAD_AFFINITY_POLICY,(integer_t*)&ap,THREAD_AFFINITY_POLICY_COUNT) != KERN_SUCCESS) + std::cerr << "Thread: cannot set affinity" << std::endl; + } + } +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// Unix Platform +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __UNIX__ + +#include <pthread.h> +#include <sched.h> + +namespace pf +{ + struct ThreadStartupData { + int affinity; + thread_func f; + void* arg; + }; + + static void* threadStartup(ThreadStartupData* parg) + { + ThreadStartupData arg = *parg; PF_DELETE(parg); parg = NULL; + setAffinity(arg.affinity); + arg.f(arg.arg); + return NULL; + } + + thread_t createThread(thread_func f, void* arg, size_t stack_size, int affinity) + { + pthread_attr_t attr; + pthread_attr_init(&attr); + if (stack_size > 0) pthread_attr_setstacksize (&attr, stack_size); + + pthread_t* tid = PF_NEW(pthread_t); + ThreadStartupData* startup = PF_NEW(ThreadStartupData); + startup->f = f; + startup->arg = arg; + startup->affinity = affinity; + + if (pthread_create(tid,&attr,(void*(*)(void*))threadStartup,startup) != 0) + FATAL("Thread creation error"); + + return thread_t(tid); + } + + void yield(int time) { + if (time == 0) sched_yield(); + else usleep(time * 1000); + } + + void join(thread_t tid) { + if (pthread_join(*(pthread_t*)tid, NULL) != 0) + FATAL("pthread_join error"); + PF_DELETE((pthread_t*)tid); + } + + void destroyThread(thread_t tid) { + pthread_cancel(*(pthread_t*)tid); + PF_DELETE((pthread_t*)tid); + } + + tls_t createTls() { + pthread_key_t* key = PF_NEW(pthread_key_t); + if (pthread_key_create(key,NULL) != 0) + FATAL("pthread_key_create error"); + return tls_t(key); + } + + void* getTls(tls_t tls) { + return pthread_getspecific(*(pthread_key_t*)tls); + } + + void setTls(tls_t tls, void* const ptr) { + if (pthread_setspecific(*(pthread_key_t*)tls, ptr) != 0) + FATAL("pthread_setspecific error"); + } + + void destroyTls(tls_t tls) { + if (pthread_key_delete(*(pthread_key_t*)tls) != 0) + FATAL("pthread_key_delete error"); + PF_DELETE((pthread_key_t*)tls); + } +} +#endif diff --git a/backend/src/sys/thread.hpp b/backend/src/sys/thread.hpp new file mode 100644 index 00000000..0611ef72 --- /dev/null +++ b/backend/src/sys/thread.hpp @@ -0,0 +1,54 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_THREAD_HPP__ +#define __PF_THREAD_HPP__ + +#include "sys/platform.hpp" + +namespace pf +{ + /*! Type for thread */ + typedef struct opaque_thread_t* thread_t; + /*! Signature of thread start function */ + typedef void (*thread_func)(void*); + /*! Creates a hardware thread running on specific logical thread */ + thread_t createThread(thread_func f, void* arg, size_t stack_size = 0, int affinity = -1); + /*! Set affinity of the calling thread */ + void setAffinity(int affinity); + /*! The thread calling this function gets yielded for a number of seconds */ + void yield(int time = 0); + /*! Waits until the given thread has terminated */ + void join(thread_t tid); + /*! Destroy handle of a thread */ + void destroyThread(thread_t tid); + /*! Type for handle to thread local storage */ + typedef struct opaque_tls_t* tls_t; + /*! Creates thread local storage */ + tls_t createTls(); + /*! Set the thread local storage pointer */ + void setTls(tls_t tls, void* const ptr); + /*! Return the thread local storage pointer */ + void* getTls(tls_t tls); + /*! Destroys thread local storage identifier */ + void destroyTls(tls_t tls); +} + +#endif /* __PF_THREAD_HPP__ */ + diff --git a/backend/src/sys/vector.hpp b/backend/src/sys/vector.hpp new file mode 100644 index 00000000..a100770d --- /dev/null +++ b/backend/src/sys/vector.hpp @@ -0,0 +1,72 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_VECTOR_HPP__ +#define __PF_VECTOR_HPP__ + +#include "sys/platform.hpp" +#include <vector> + +namespace pf +{ + /*! Add bound checks to the standard vector class and use the internal + * allocator + */ + template<class T> + class vector : public std::vector<T, Allocator<T>> + { + public: + // Typedefs + typedef std::vector<T, Allocator<T>> parent_type; + typedef Allocator<T> allocator_type; + typedef typename allocator_type::size_type size_type; + typedef typename parent_type::iterator iterator; + + /*! Default constructor */ + INLINE explicit vector(const allocator_type &a = allocator_type()) : + parent_type(a) {} + /*! Copy constructor */ + INLINE vector(const vector &x) : parent_type(x) {} + /*! Repetitive sequence constructor */ + INLINE explicit vector(size_type n, + const T& value= T(), + const allocator_type &a = allocator_type()) : + parent_type(n, value, a) {} + /*! Iteration constructor */ + template <class InputIterator> + INLINE vector(InputIterator first, + InputIterator last, + const allocator_type &a = allocator_type()) : + parent_type(first, last, a) {} + /*! Get element at position index (with a bound check) */ + T &operator[] (size_t index) { + PF_ASSERT(index < this->size()); + return parent_type::operator[] (index); + } + /*! Get element at position index (with a bound check) */ + const T &operator[] (size_t index) const { + PF_ASSERT(index < this->size()); + return parent_type::operator[] (index); + } + PF_CLASS(vector); + }; +} /* namespace pf */ + +#endif /* __PF_VECTOR_HPP__ */ + diff --git a/backend/src/utest/utest.cpp b/backend/src/utest/utest.cpp new file mode 100644 index 00000000..8fca9682 --- /dev/null +++ b/backend/src/utest/utest.cpp @@ -0,0 +1,57 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "utest.hpp" +#include "sys/string.hpp" + +namespace pf +{ + std::vector<UTest> *UTest::utestList = NULL; + void releaseUTestList(void) { if (UTest::utestList) delete UTest::utestList; } + + UTest::UTest(Function fn, const char *name) : fn(fn), name(name) { + if (utestList == NULL) { + utestList = new std::vector<UTest>; + atexit(releaseUTestList); + } + utestList->push_back(*this); + } + + UTest::UTest(void) : fn(NULL), name(NULL) {} + + void UTest::run(const char *name) { + if (name == NULL) return; + if (utestList == NULL) return; + for (size_t i = 0; i < utestList->size(); ++i) { + const UTest &utest = (*utestList)[i]; + if (utest.name == NULL || utest.fn == NULL) continue; + if (strequal(utest.name, name)) (utest.fn)(); + } + } + + void UTest::runAll(void) { + if (utestList == NULL) return; + for (size_t i = 0; i < utestList->size(); ++i) { + const UTest &utest = (*utestList)[i]; + if (utest.fn == NULL) continue; + (utest.fn)(); + } + } +} /* namespace pf */ + diff --git a/backend/src/utest/utest.hpp b/backend/src/utest/utest.hpp new file mode 100644 index 00000000..fea1bbcd --- /dev/null +++ b/backend/src/utest/utest.hpp @@ -0,0 +1,53 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#ifndef __PF_UTEST_HPP__ +#define __PF_UTEST_HPP__ + +#include <vector> + +namespace pf +{ + /*! Quick and dirty Unit test system with registration */ + struct UTest + { + /*! A unit test function to run */ + typedef void (*Function) (void); + /*! Empty test */ + UTest(void); + /*! Build a new unit test and append it to the unit test list */ + UTest(Function fn, const char *name); + /*! Function to execute */ + Function fn; + /*! Name of the test */ + const char *name; + /*! The tests that are registered */ + static std::vector<UTest> *utestList; + /*! Run the test with the given name */ + static void run(const char *name); + /*! Run all the tests */ + static void runAll(void); + }; +} /* namespace pf */ + +/*! Register a new unit test */ +#define UTEST_REGISTER(FN) static const pf::UTest __##NAME##__(FN, #FN); + +#endif /* __PF_UTEST_HPP__ */ + diff --git a/backend/src/utest/utest_console.cpp b/backend/src/utest/utest_console.cpp new file mode 100644 index 00000000..51075944 --- /dev/null +++ b/backend/src/utest/utest_console.cpp @@ -0,0 +1,95 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "utest/utest.hpp" +#include "sys/command.hpp" +#include "sys/console.hpp" +#include "sys/logging.hpp" +#include "sys/windowing.hpp" +#include "sys/script.hpp" +#include <string> + +namespace pf +{ + /*! Output everything in the terminal */ + class UTestConsoleDisplay : public ConsoleDisplay + { + public: + UTestConsoleDisplay (void) { + last = lastBlink = getSeconds(); + cursor = 0; + } + virtual void line(Console &console, const std::string &line) { + const double curr = getSeconds(); + std::string patched = line; + if (curr - lastBlink > .5) { + cursor ^= 1; + lastBlink = curr; + } + const uint32 pos = console.cursorPosition(); + if (cursor) { + if (pos >= patched.size()) + patched.push_back('_'); + else + patched[pos] = '_'; + } + if (curr - last > 0.02) { + std::cout << '\r' << "> " << patched; + for (int i = 0; i < 80; ++i) std::cout << ' '; + std::cout << '\r'; + fflush(stdout); + last = curr; + } + } + virtual void out(Console &console, const std::string &str) { + std::cout << str << std::endl; + } + double last; + double lastBlink; + uint32 cursor; + }; +} /* namespace pf */ + +void utest_console(void) +{ + using namespace pf; + WinOpen(640, 480); + ScriptSystem *scriptSystem = LuaScriptSystemCreate(); + CommandSystemStart(*scriptSystem); + UTestConsoleDisplay *display = PF_NEW(UTestConsoleDisplay); + Console *console = ConsoleNew(*scriptSystem, *display); + console->addCompletion("while"); + console->addCompletion("whilewhile"); + for (;;) { + Ref<InputControl> input = PF_NEW(InputControl); + input->processEvents(); + if (input->getKey(PF_KEY_ASCII_ESC)) + break; + console->update(*input); + WinSwapBuffers(); + } + CommandSystemEnd(); + PF_DELETE(console); + PF_DELETE(scriptSystem); + PF_DELETE(display); + WinClose(); +} + +UTEST_REGISTER(utest_console); + diff --git a/backend/src/utest/utest_font.cpp b/backend/src/utest/utest_font.cpp new file mode 100644 index 00000000..d6b0fa9f --- /dev/null +++ b/backend/src/utest/utest_font.cpp @@ -0,0 +1,41 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "renderer/font.hpp" +#include "sys/default_path.hpp" +#include "utest/utest.hpp" + +#include <string> + +using namespace pf; +static const std::string fontName = "font.fnt"; + +void utest_font(void) +{ + Font font; + size_t i = 0; + for (; i < defaultPathNum; ++i) { + const FileName path(std::string(defaultPath[i]) + fontName); + if (font.load(path)) break; + } + PF_ASSERT(i < defaultPathNum); +} + +UTEST_REGISTER(utest_font); + diff --git a/backend/src/utest/utest_lua.cpp b/backend/src/utest/utest_lua.cpp new file mode 100644 index 00000000..289ef7f3 --- /dev/null +++ b/backend/src/utest/utest_lua.cpp @@ -0,0 +1,58 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "sys/script.hpp" +#include "sys/command.hpp" +#include "sys/logging.hpp" +#include "sys/tasking.hpp" +#include "utest/utest.hpp" + +using namespace pf; + +VARI(coucou, 0, 2, 3, "coucou"); +VARS(player0, "ben", "player name"); + +#define _RUN_SCRIPT(STR, RUN_MODE) do {\ + ScriptStatus status;\ + scriptSystem->RUN_MODE(STR, status);\ + if (!status.success) PF_ERROR(status.msg);\ +} while (0) +#define RUN(STR) _RUN_SCRIPT(STR,run) +#define RUN_NON_PROTECTED(STR) _RUN_SCRIPT(STR,runNonProtected) + +void utest_lua(void) +{ + ScriptSystem *scriptSystem = LuaScriptSystemCreate(); + ScriptStatus status; + scriptSystem->run("local x = 0", status); + CommandSystemStart(*scriptSystem); + + // Run some code. This may modify console variables + RUN("cv.coucou = 1"); + RUN_NON_PROTECTED("print(pf.cv.coucou)"); + RUN("cv.player0 = \"hop\""); + RUN_NON_PROTECTED("print(pf.cv.player0)"); + if (coucou() == 1) PF_MSG("coucou is equal to 1"); + + CommandSystemEnd(); + PF_DELETE(scriptSystem); +} + +UTEST_REGISTER(utest_lua) + diff --git a/backend/src/utest/utest_rt.cpp b/backend/src/utest/utest_rt.cpp new file mode 100644 index 00000000..cf2db0ab --- /dev/null +++ b/backend/src/utest/utest_rt.cpp @@ -0,0 +1,193 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "renderer/renderer_obj.hpp" +#include "renderer/renderer.hpp" +#include "rt/bvh2_traverser.hpp" +#include "rt/bvh2.hpp" +#include "rt/rt_triangle.hpp" +#include "rt/rt_camera.hpp" +#include "models/obj.hpp" +#include "game/camera.hpp" +#include "image/stb_image.hpp" + +#include "sys/alloc.hpp" +#include "sys/tasking.hpp" +#include "sys/tasking_utility.hpp" +#include "sys/logging.hpp" +#include "sys/default_path.hpp" + +#include "utest/utest.hpp" + +#include <cstring> +#include <GL/freeglut.h> +#include <cstdio> +#include <iostream> + +namespace pf +{ + static Ref<Intersector> intersector = NULL; + static const int CAMW = 1024, CAMH = 1024; + + static const FileName objName("f000.obj"); + //static const FileName objName("arabic_city_II.obj"); + //static const FileName objName("conference.obj"); + //static const FileName objName("sibenik.obj"); + //static const FileName objName("sponza.obj"); + + static RTTriangle *ObjComputeTriangle(const Obj &obj) { + RTTriangle *tris = PF_NEW_ARRAY(RTTriangle, obj.triNum); + for (size_t i = 0; i < obj.triNum; ++i) { + const vec3f &v0 = obj.vert[obj.tri[i].v[0]].p; + const vec3f &v1 = obj.vert[obj.tri[i].v[1]].p; + const vec3f &v2 = obj.vert[obj.tri[i].v[2]].p; + tris[i] = RTTriangle(v0,v1,v2); + } + return tris; + } + + /*! Task set that computes a frame buffer with ray tracing */ + template <bool singleRay> + class TaskRayTrace : public TaskSet + { + public: + INLINE TaskRayTrace(const Intersector &intersector, + const RTCamera &cam, + const uint32 *c, + uint32 *rgba, + uint32 w, uint32 jobNum) : + TaskSet(jobNum, "TaskRayTrace"), + intersector(intersector), cam(cam), c(c), rgba(rgba), + w(w), h(jobNum * RayPacket::height) {} + + virtual void run(size_t jobID) + { + if (singleRay) { + RTCameraRayGen gen; + cam.createGenerator(gen, w, h); + for (uint32 row = 0; row < RayPacket::height; ++row) { + const uint32 y = row + jobID * RayPacket::height; + for (uint32 x = 0; x < w; ++x) { + Ray ray; + Hit hit; + gen.generate(ray, x, y); + intersector.traverse(ray, hit); + rgba[x + y*w] = hit ? c[hit.id0] : 0u; + } + } + } else { + RTCameraPacketGen gen; + cam.createGenerator(gen, w, h); + const uint32 y = jobID * RayPacket::height; + for (uint32 x = 0; x < w; x += RayPacket::width) { + RayPacket pckt; + PacketHit hit; + gen.generate(pckt, x, y); + intersector.traverse(pckt, hit); + const int32 *IDs = (const int32 *) &hit.id0[0][0]; + uint32 curr = 0; + for (uint32 j = 0; j < pckt.height; ++j) { + for (uint32 i = 0; i < pckt.width; ++i, ++curr) { + const uint32 offset = x + i + (y + j) * w; + rgba[offset] = IDs[curr] != -1 ? c[IDs[curr]] : 0u; + } + } + } + } + } + + const Intersector &intersector; //!< To traverse the scene + const RTCamera &cam; //!< Parameterize the view + const uint32 *c; //!< One color per triangle + uint32 *rgba; //!< Frame buffer + uint32 w, h; //!< Frame buffer dimensions + }; + + /*! Ray trace the loaded scene */ + template <bool singleRay> + static void rayTrace(int w, int h, const uint32 *c) { + FPSCamera fpsCam; + const RTCamera cam(fpsCam.org, fpsCam.up, fpsCam.view, fpsCam.fov, fpsCam.ratio); + uint32 *rgba = PF_NEW_ARRAY(uint32, w * h); + std::memset(rgba, 0, sizeof(uint32) * w * h); + PF_COMPILER_READ_WRITE_BARRIER; + const double t = getSeconds(); + Task *rayTask = PF_NEW(TaskRayTrace<singleRay>, *intersector, + cam, c, rgba, w, h/RayPacket::height); + Task *returnToMain = PF_NEW(TaskInterruptMain); + rayTask->starts(returnToMain); + rayTask->scheduled(); + returnToMain->scheduled(); + TaskingSystemEnter(); + const double dt = getSeconds() - t; + PF_MSG_V(dt * 1000. << " msec - " << CAMW * CAMH / dt << " rays/s"); + if (singleRay) + stbi_write_bmp("single.bmp", w, h, 4, rgba); + else + stbi_write_bmp("packet.bmp", w, h, 4, rgba); + PF_DELETE_ARRAY(rgba); + } + + static void RTStart(void) + { + Obj obj; + size_t path = 0; + for (path = 0; path < defaultPathNum; ++path) + if (obj.load(FileName(defaultPath[path]) + objName)) { + PF_MSG_V("Obj: " << objName << " loaded from " << defaultPath[path]); + break; + } + if (path == defaultPathNum) + PF_WARNING_V("Obj: " << objName << " not found"); + + // Build the BVH + RTTriangle *tris = ObjComputeTriangle(obj); + Ref<BVH2<RTTriangle>> bvh = PF_NEW(BVH2<RTTriangle>); + buildBVH2(tris, obj.triNum, *bvh); + PF_DELETE_ARRAY(tris); + + // Now we have an intersector on the triangle soup + intersector = PF_NEW(BVH2Traverser<RTTriangle>, bvh); + + // Compute some triangle color + uint32 *c = PF_NEW_ARRAY(uint32, bvh->primNum); + for (uint32 i = 0; i < bvh->primNum; ++i) { + c[i] = rand(); + c[i] |= 0xff000000; + } + + // Ray trace now + PF_MSG_V("Packet ray tracing"); + for (int i = 0; i < 16; ++i) rayTrace<false>(CAMW, CAMH, c); + PF_MSG_V("Single ray tracing"); + for (int i = 0; i < 16; ++i) rayTrace<true>(CAMW, CAMH, c); + PF_DELETE_ARRAY(c); + } + + static void RTEnd(void) { intersector = NULL; } +} + +void utest_rt(void) +{ + using namespace pf; + RTStart(); + RTEnd(); +} + +UTEST_REGISTER(utest_rt); diff --git a/backend/src/utest/utest_tasking.cpp b/backend/src/utest/utest_tasking.cpp new file mode 100644 index 00000000..419c3d73 --- /dev/null +++ b/backend/src/utest/utest_tasking.cpp @@ -0,0 +1,653 @@ +/* + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Benjamin Segovia <benjamin.segovia@intel.com> + */ + +#include "sys/tasking.hpp" +#include "sys/tasking_utility.hpp" +#include "sys/ref.hpp" +#include "sys/thread.hpp" +#include "sys/mutex.hpp" +#include "sys/sysinfo.hpp" +#include "math/random.hpp" + +#include "utest/utest.hpp" + +#define START_UTEST(TEST_NAME) \ +void TEST_NAME(void) \ +{ \ + std::cout << std::endl << "starting " << \ + #TEST_NAME << std::endl; + +#define END_UTEST(TEST_NAME) \ + std::cout << "ending " << #TEST_NAME << std::endl; \ +} + +using namespace pf; + +/////////////////////////////////////////////////////////////////////////////// +// Very simple test which basically does nothing +/////////////////////////////////////////////////////////////////////////////// +class TaskDone : public Task { +public: + virtual Task* run(void) { + TaskingSystemInterruptMain(); + return NULL; + } +}; + +START_UTEST(TestDummy) + Task *done = PF_NEW(TaskDone); + Task *nothing = PF_NEW(TaskDummy); + nothing->starts(done); + done->scheduled(); + nothing->scheduled(); + TaskingSystemEnter(); +END_UTEST(TestDummy) + +/////////////////////////////////////////////////////////////////////////////// +// Simplest taskset test. An array is filled by each worker +/////////////////////////////////////////////////////////////////////////////// +class TaskSetSimple : public TaskSet { +public: + INLINE TaskSetSimple(size_t elemNum, uint32 *array_) : + TaskSet(elemNum), array(array_) {} + virtual void run(size_t elemID) { array[elemID] = 1u; } + uint32 *array; +}; + +START_UTEST(TestTaskSet) + const size_t elemNum = 1 << 20; + uint32 *array = PF_NEW_ARRAY(uint32, elemNum); + for (size_t i = 0; i < elemNum; ++i) array[i] = 0; + double t = getSeconds(); + Task *done = PF_NEW(TaskDone); + Task *taskSet = PF_NEW(TaskSetSimple, elemNum, array); + taskSet->starts(done); + done->scheduled(); + taskSet->scheduled(); + TaskingSystemEnter(); + t = getSeconds() - t; + std::cout << t * 1000. << " ms" << std::endl; + for (size_t i = 0; i < elemNum; ++i) + FATAL_IF(array[i] == 0, "TestTaskSet failed"); + PF_DELETE_ARRAY(array); +END_UTEST(TestTaskSet) + +/////////////////////////////////////////////////////////////////////////////// +// We create a binary tree of tasks here. Each task spawn a two children upto a +// given maximum level. Then, a atomic value is updated per leaf. In that test, +// all tasks complete the ROOT directly +/////////////////////////////////////////////////////////////////////////////// +enum { maxLevel = 20u }; + +/*! One node task per node in the tree. Task completes the root */ +class TaskNode : public Task { +public: + INLINE TaskNode(Atomic &value_, uint32 lvl_, Task *root_=NULL) : + value(value_), lvl(lvl_) { + this->root = root_ == NULL ? this : root_; + } + virtual Task* run(void); + Atomic &value; + Task *root; + uint32 lvl; +}; + +Task* TaskNode::run(void) { + if (this->lvl == maxLevel) + this->value++; + else { + Task *left = PF_NEW(TaskNode, this->value, this->lvl+1, this->root); + Task *right = PF_NEW(TaskNode, this->value, this->lvl+1, this->root); + left->ends(this->root); + right->ends(this->root); + left->scheduled(); + right->scheduled(); + } + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +// Same as TaskNode but we use a continuation passing style strategy to improve +// the system throughtput +/////////////////////////////////////////////////////////////////////////////// + +/*! One node task per node in the tree. Task completes the root */ +class TaskNodeOpt : public Task { +public: + INLINE TaskNodeOpt(Atomic &value_, uint32 lvl_, Task *root_=NULL) : + value(value_), lvl(lvl_) { + this->root = root_ == NULL ? this : root_; + } + virtual Task* run(void); + Atomic &value; + Task *root; + uint32 lvl; +}; + +Task* TaskNodeOpt::run(void) { + if (this->lvl == maxLevel) { + this->value++; + return NULL; + } else { + Task *left = PF_NEW(TaskNode, this->value, this->lvl+1, this->root); + Task *right = PF_NEW(TaskNode, this->value, this->lvl+1, this->root); + left->ends(this->root); + right->ends(this->root); + left->scheduled(); + return right; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Same as TaskNode but here each task completes its parent task directly. This +// stresses the completion system but strongly limits cache line contention +/////////////////////////////////////////////////////////////////////////////// + +/*! One node task per node in the tree. Task completes its parent */ +class TaskCascadeNode : public Task { +public: + INLINE TaskCascadeNode(Atomic &value_, uint32 lvl_, Task *root_=NULL) : + value(value_), lvl(lvl_) {} + virtual Task* run(void); + Atomic &value; + uint32 lvl; +}; + +Task *TaskCascadeNode::run(void) { + if (this->lvl == maxLevel) + this->value++; + else { + Task *left = PF_NEW(TaskCascadeNode, this->value, this->lvl+1); + Task *right = PF_NEW(TaskCascadeNode, this->value, this->lvl+1); + left->ends(this); + right->ends(this); + left->scheduled(); + right->scheduled(); + } + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +// Same as TaskCascadeNode but with continuation passing style tasks +/////////////////////////////////////////////////////////////////////////////// +class TaskCascadeNodeOpt : public Task { +public: + INLINE TaskCascadeNodeOpt(Atomic &value_, uint32 lvl_, Task *root_=NULL) : + value(value_), lvl(lvl_) {} + virtual Task* run(void); + Atomic &value; + uint32 lvl; +}; + +Task *TaskCascadeNodeOpt::run(void) { + if (this->lvl == maxLevel) { + this->value++; + return NULL; + } else { + Task *left = PF_NEW(TaskCascadeNode, this->value, this->lvl+1); + Task *right = PF_NEW(TaskCascadeNode, this->value, this->lvl+1); + left->ends(this); + right->ends(this); + left->scheduled(); + return right; + } +} + +/*! For all tree tests */ +template<typename NodeType> +START_UTEST(TestTree) + Atomic value(0u); + std::cout << "nodeNum = " << (2 << maxLevel) - 1 << std::endl; + double t = getSeconds(); + Task *done = PF_NEW(TaskDone); + Task *root = PF_NEW(NodeType, value, 0); + root->starts(done); + done->scheduled(); + root->scheduled(); + TaskingSystemEnter(); + t = getSeconds() - t; + std::cout << t * 1000. << " ms" << std::endl; + FATAL_IF(value != (1 << maxLevel), "TestTree failed"); +END_UTEST(TestTree) + +/////////////////////////////////////////////////////////////////////////////// +// We try to stress the internal allocator here +/////////////////////////////////////////////////////////////////////////////// +class TaskAllocate : public TaskSet { +public: + TaskAllocate(size_t elemNum) : TaskSet(elemNum) {} + virtual void run(size_t elemID); + enum { allocNum = 1 << 10 }; + enum { iterNum = 1 << 5 }; +}; + +void TaskAllocate::run(size_t elemID) { + Task *tasks[allocNum]; + for (int j = 0; j < iterNum; ++j) { + const int taskNum = rand() % allocNum; + for (int i = 0; i < taskNum; ++i) tasks[i] = PF_NEW(TaskDummy); + for (int i = 0; i < taskNum; ++i) PF_DELETE(tasks[i]); + } +} + +START_UTEST(TestAllocator) + Task *done = PF_NEW(TaskDone); + Task *allocate = PF_NEW(TaskAllocate, 1 << 10); + double t = getSeconds(); + allocate->starts(done); + done->scheduled(); + allocate->scheduled(); + TaskingSystemEnter(); + t = getSeconds() - t; + std::cout << t * 1000. << " ms" << std::endl; +END_UTEST(TestAllocator) + +/////////////////////////////////////////////////////////////////////////////// +// We are making the queue full to make the system recurse to empty it +/////////////////////////////////////////////////////////////////////////////// +class TaskFull : public Task { +public: + enum { taskToSpawn = 1u << 16u }; + TaskFull(const char *name, Atomic &counter, int lvl = 0) : + Task(name), counter(counter), lvl(lvl) {} + virtual Task* run(void) { + if (lvl == 0) + for (size_t i = 0; i < taskToSpawn; ++i) { + Task *task = PF_NEW(TaskFull, "TaskFullLvl1", counter, 1); + task->ends(this); + task->scheduled(); + } + else + counter++; + return NULL; + } + Atomic &counter; + int lvl; +}; + +START_UTEST(TestFullQueue) + Atomic counter(0u); + double t = getSeconds(); + Task *done = PF_NEW(TaskDone); + for (size_t i = 0; i < 64; ++i) { + Task *task = PF_NEW(TaskFull, "TaskFull", counter); + task->starts(done); + task->scheduled(); + } + done->scheduled(); + TaskingSystemEnter(); + t = getSeconds() - t; + std::cout << t * 1000. << " ms" << std::endl; + FATAL_IF (counter != 64 * TaskFull::taskToSpawn, "TestFullQueue failed"); +END_UTEST(TestFullQueue) + +/////////////////////////////////////////////////////////////////////////////// +// We spawn a lot of affinity jobs to saturate the affinity queues +/////////////////////////////////////////////////////////////////////////////// +class TaskAffinity : public Task { +public: + enum { taskToSpawn = 2048u }; + TaskAffinity(Task *done, Atomic &counter, int lvl = 0) : + Task("TaskAffinity"), counter(counter), lvl(lvl) {} + virtual Task *run(void) { + if (lvl == 1) + counter++; + else { + const uint32 threadNum = TaskingSystemGetThreadNum(); + for (uint32 i = 0; i < taskToSpawn; ++i) { + Task *task = PF_NEW(TaskAffinity, done.ptr, counter, 1); + task->setAffinity(i % threadNum); + task->ends(this); + task->scheduled(); + } + } + return NULL; + } + Atomic &counter; + Ref<Task> done; + int lvl; +}; + +START_UTEST(TestAffinity) + enum { batchNum = 512 }; + for (int i = 0; i < 8; ++i) { + Atomic counter(0u); + double t = getSeconds(); + Ref<Task> done = PF_NEW(TaskDone); + for (size_t i = 0; i < batchNum; ++i) { + Task *task = PF_NEW(TaskAffinity, done.ptr, counter); + task->starts(done.ptr); + task->scheduled(); + } + done->scheduled(); + TaskingSystemEnter(); + t = getSeconds() - t; + std::cout << t * 1000. << " ms" << std::endl; + std::cout << counter << std::endl; + FATAL_IF (counter != batchNum * TaskAffinity::taskToSpawn, "TestAffinity failed"); + } +END_UTEST(TestAffinity) + +/////////////////////////////////////////////////////////////////////////////// +// Exponential Fibonnaci to stress the task spawning and the completions +/////////////////////////////////////////////////////////////////////////////// +static Atomic fiboNum(0u); +class TaskFiboSpawn : public Task { +public: + TaskFiboSpawn(uint64 rank, uint64 *root = NULL) : + Task("TaskFiboSpawn"), rank(rank), root(root) {fiboNum++;} + virtual Task* run(void); + uint64 rank, sumLeft, sumRight; + uint64 *root; +}; + +class FiboSumTask : public Task { +public: + FiboSumTask(TaskFiboSpawn *fibo) : Task("FiboSumTask"), fibo(fibo) {} + virtual Task* run(void); + TaskFiboSpawn *fibo; +}; + +Task *TaskFiboSpawn::run(void) { + if (rank > 1) { + TaskFiboSpawn *left = PF_NEW(TaskFiboSpawn, rank-1, &this->sumLeft); + TaskFiboSpawn *right = PF_NEW(TaskFiboSpawn, rank-2, &this->sumRight); + FiboSumTask *sum = PF_NEW(FiboSumTask, this); + left->starts(sum); + right->starts(sum); + sum->ends(this); + sum->scheduled(); + left->scheduled(); + return right; + } else if (rank == 1) { + if (root) *root = 1; + return NULL; + } else { + if (root) *root = 0; + return NULL; + } +} + +Task *FiboSumTask::run(void) { + assert(fibo); + if (fibo->root) *fibo->root = fibo->sumLeft + fibo->sumRight; + return NULL; +} + +static uint64 fiboLinear(uint64 rank) +{ + uint64 rn0 = 0, rn1 = 1; + if (rank == 0) return rn0; + if (rank == 1) return rn1; + for (uint64 i = 2; i <= rank; ++i) { + uint64 sum = rn0 + rn1; + rn0 = rn1; + rn1 = sum; + } + return rn1; +} + +START_UTEST(TestFibo) +{ + const uint64 rank = rand() % 32; + uint64 sum; + double t = getSeconds(); + fiboNum = 0u; + Ref<TaskFiboSpawn> fibo = PF_NEW(TaskFiboSpawn, rank, &sum); + Task *done = PF_NEW(TaskDone); + fibo->starts(done); + fibo->scheduled(); + done->scheduled(); + TaskingSystemEnter(); + t = getSeconds() - t; + std::cout << t * 1000. << " ms" << std::endl; + std::cout << "Fibonacci Task Num: "<< fiboNum << std::endl; + FATAL_IF (sum != fiboLinear(rank), "TestFibonacci failed"); +} +END_UTEST(TestFibo) + +/////////////////////////////////////////////////////////////////////////////// +// Task with multiple dependencies +/////////////////////////////////////////////////////////////////////////////// +class TaskMultiTrigger : public Task, + public MultiDependencyPolicy<TaskMultiTrigger> +{ +public: + TaskMultiTrigger(int32 *valueToSet) : valueToSet(valueToSet) {} + virtual Task *run(void) { *valueToSet = 1; return NULL; } +private: + int32 *valueToSet; +}; + +class TaskTriggered : public Task +{ +public: + TaskTriggered(const int32 *valueToRead, Atomic32 &dst) : + valueToRead(valueToRead), dst(dst) {} + virtual Task *run(void) { dst += *valueToRead; return NULL; } +private: + const int32 *valueToRead; + Atomic32 &dst; +}; + +START_UTEST(TestMultiDependency) +{ + static const uint32 multiTaskToSpawn = 512; + static const uint32 triggeredTaskToSpawn = 512; + static const uint32 valueToSetNum = multiTaskToSpawn; + + int32 *toSet = PF_NEW_ARRAY(int32, valueToSetNum); + Atomic32 dst(0); + Task *doneTask = PF_NEW(TaskDone); + for (uint32 i = 0; i < valueToSetNum; ++i) toSet[i] = 0; + for (uint32 i = 0; i < multiTaskToSpawn; ++i) { + Ref<TaskMultiTrigger> task = PF_NEW(TaskMultiTrigger, toSet + i); + for (uint32 j = 0; j < triggeredTaskToSpawn; ++j) { + Ref<Task> triggered = PF_NEW(TaskTriggered, toSet + i, dst); + Ref<Task> dummy = PF_NEW(TaskDummy); + task->multiStarts(dummy); + dummy->starts(triggered); + triggered->starts(doneTask); + triggered->scheduled(); + dummy->scheduled(); + } + task->scheduled(); + } + doneTask->scheduled(); + TaskingSystemEnter(); + PF_DELETE_ARRAY(toSet); + const uint32 result = dst; + std::cout << "result: " << result << std::endl; + FATAL_IF(result != multiTaskToSpawn * triggeredTaskToSpawn, + "MultiDependency failed"); +} +END_UTEST(TestMultiDependency) + +START_UTEST(TestMultiDependencyTwoStage) +{ + static const uint32 multiTaskToSpawn = 512; + static const uint32 triggeredTaskToSpawn = 512; + static const uint32 valueToSetNum = multiTaskToSpawn; + + int32 *toSet = PF_NEW_ARRAY(int32, valueToSetNum); + Atomic32 dst(0); + Task *doneTask = PF_NEW(TaskDone); + for (uint32 i = 0; i < valueToSetNum; ++i) toSet[i] = 0; + for (uint32 i = 0; i < multiTaskToSpawn; ++i) { + Ref<TaskMultiTrigger> task = PF_NEW(TaskMultiTrigger, toSet + i); + for (uint32 j = 0; j < triggeredTaskToSpawn; ++j) { + Ref<Task> triggered = PF_NEW(TaskTriggered, toSet + i, dst); + task->multiStarts(triggered); + triggered->starts(doneTask); + triggered->scheduled(); + } + task->scheduled(); + } + doneTask->scheduled(); + TaskingSystemEnter(); + PF_DELETE_ARRAY(toSet); + const uint32 result = dst; + std::cout << "result: " << result << std::endl; + FATAL_IF(result != multiTaskToSpawn * triggeredTaskToSpawn, + "MultiDependency failed"); +} +END_UTEST(TestMultiDependencyTwoStage) + +START_UTEST(TestMultiDependencyRandomStart) +{ + static const uint32 multiTaskToSpawn = 512; + static const uint32 triggeredTaskToSpawn = 512; + static const uint32 valueToSetNum = multiTaskToSpawn; + static const uint32 repeatNum = 8; + Random rand; + for (uint32 i = 0; i < repeatNum; ++i) { + int32 *toSet = PF_NEW_ARRAY(int32, valueToSetNum); + Atomic32 dst(0); + Ref<Task> doneTask = PF_NEW(TaskDone); + for (uint32 i = 0; i < valueToSetNum; ++i) toSet[i] = 0; + for (uint32 i = 0; i < multiTaskToSpawn; ++i) { + Ref<TaskMultiTrigger> task = PF_NEW(TaskMultiTrigger, toSet + i); + bool isScheduled = false; + for (uint32 j = 0; j < triggeredTaskToSpawn; ++j) { + Ref<Task> triggered = PF_NEW(TaskTriggered, toSet + i, dst); + task->multiStarts(triggered); + triggered->starts(doneTask); + triggered->scheduled(); + if (rand.getFloat() < 0.8 && isScheduled == false) { + task->scheduled(); + isScheduled = true; + } + } + if (isScheduled == false) task->scheduled(); + } + doneTask->scheduled(); + TaskingSystemEnter(); + PF_DELETE_ARRAY(toSet); + const uint32 result = dst; + std::cout << "result: " << result << std::endl; + FATAL_IF(result != multiTaskToSpawn * triggeredTaskToSpawn, + "MultiDependencyRandomStart failed"); + } +} +END_UTEST(TestMultiDependencyRandomStart) + +/////////////////////////////////////////////////////////////////////////////// +// Test tasking lock and unlock +/////////////////////////////////////////////////////////////////////////////// +class TaskLockUnlock : public Task +{ +public: + TaskLockUnlock(int32 *shared) : shared(shared) {} + virtual Task *run(void) { + TaskingSystemLock(); + *shared = *shared + 1; + TaskingSystemUnlock(); + return NULL; + } + int32 *shared; +}; + +START_UTEST(TestLockUnlock) +{ + static const uint32 taskNum = 1024; + int32 shared = 0; + Ref<Task> doneTask = PF_NEW(TaskDone); + for (uint32 i = 0; i < taskNum; ++i) { + Task *updateTask = PF_NEW(TaskLockUnlock, &shared); + updateTask->starts(doneTask); + updateTask->scheduled(); + } + doneTask->scheduled(); + TaskingSystemEnter(); + FATAL_IF(shared != int32(taskNum), "TestLockUnlock failed"); +} +END_UTEST(TestLockUnlock) + +/////////////////////////////////////////////////////////////////////////////// +// Test tasking profiler +/////////////////////////////////////////////////////////////////////////////// +#if PF_TASK_PROFILER +class UTestProfiler : public TaskProfiler +{ +public: + UTestProfiler(void) : + sleepNum(0), wakeUpNum(0), + lockNum(0), unlockNum(0), + runStartNum(0), runEndNum(0), endNum(0) {} + virtual void onSleep(uint32 threadID) {sleepNum++;} + virtual void onWakeUp(uint32 threadID) {wakeUpNum++;} + virtual void onLock(uint32 threadID) {lockNum++;} + virtual void onUnlock(uint32 threadID) {unlockNum++;} + virtual void onRunStart(const char *taskName, uint32 threadID) {runStartNum++;} + virtual void onRunEnd(const char *taskName, uint32 threadID) {runEndNum++;} + virtual void onEnd(const char *taskName, uint32 threadID) {endNum++;} + Atomic sleepNum; + Atomic wakeUpNum; + Atomic lockNum; + Atomic unlockNum; + Atomic runStartNum; + Atomic runEndNum; + Atomic endNum; +}; + +START_UTEST(TestProfiler) +{ + UTestProfiler *profiler = PF_NEW(UTestProfiler); + TaskingSystemSetProfiler(profiler); + TestFibo(); + TestTaskSet(); + TestMultiDependency(); + TestLockUnlock(); +#define OUTPUT_FIELD(FIELD) \ + std::cout << #FIELD ": " << profiler->FIELD << std::endl + OUTPUT_FIELD(sleepNum); + OUTPUT_FIELD(wakeUpNum); + OUTPUT_FIELD(lockNum); + OUTPUT_FIELD(unlockNum); + OUTPUT_FIELD(runStartNum); + OUTPUT_FIELD(runEndNum); + OUTPUT_FIELD(endNum); +#undef OUTPUT_FIELD + TaskingSystemSetProfiler(NULL); + PF_DELETE(profiler); +} +END_UTEST(TestProfiler) +#endif /* PF_TASK_PROFILER */ + +/*! Run all tasking tests */ +void utest_tasking(void) +{ + TestDummy(); + TestTree<TaskNodeOpt>(); + TestTree<TaskNode>(); + TestTree<TaskCascadeNodeOpt>(); + TestTree<TaskCascadeNode>(); + TestTaskSet(); + TestAllocator(); + TestFullQueue(); + TestAffinity(); + TestFibo(); + TestMultiDependency(); + TestMultiDependencyTwoStage(); + TestMultiDependencyRandomStart(); + TestLockUnlock(); + TestProfiler(); +} + +UTEST_REGISTER(utest_tasking); |