From 445d1e820122ece4e0a3e8343b886319ee79cf66 Mon Sep 17 00:00:00 2001 From: liaogang Date: Fri, 9 Sep 2016 19:46:48 +0800 Subject: [PATCH] Support MAC OS for PaddlePaddle --- cmake/cudnn.cmake | 2 +- cmake/flags.cmake | 4 +- cmake/util.cmake | 41 +++++-- paddle/api/Util.cpp | 1 + .../gserver/dataproviders/PyDataProvider.cpp | 2 + .../gradientmachines/NeuralNetwork.cpp | 12 +- paddle/math/Allocator.h | 13 ++- paddle/math/MathFunctions.h | 2 + paddle/math/Storage.cpp | 4 +- paddle/pserver/LightNetwork.cpp | 29 ++++- paddle/pserver/SocketChannel.cpp | 12 +- paddle/trainer/Trainer.cpp | 1 + paddle/trainer/TrainerMain.cpp | 1 + paddle/utils/Excepts.cpp | 54 +++++++++ paddle/utils/Excepts.h | 26 +++++ paddle/utils/Locks.cpp | 106 ++++++++++++++++++ paddle/utils/Locks.h | 69 ++++++++++++ paddle/utils/PythonUtil.h | 20 +++- 18 files changed, 361 insertions(+), 38 deletions(-) create mode 100644 paddle/utils/Excepts.cpp create mode 100644 paddle/utils/Excepts.h create mode 100644 paddle/utils/Locks.cpp diff --git a/cmake/cudnn.cmake b/cmake/cudnn.cmake index e2ff923a22..e5b59be193 100644 --- a/cmake/cudnn.cmake +++ b/cmake/cudnn.cmake @@ -15,7 +15,7 @@ list(APPEND CUDNN_CHECK_LIBRARY_DIRS $ENV{CUDNN_ROOT}/lib64 $ENV{CUDNN_ROOT}/lib /usr/lib) -find_library(CUDNN_LIBRARY NAMES libcudnn.so # libcudnn_static.a +find_library(CUDNN_LIBRARY NAMES libcudnn.so libcudnn.dylib # libcudnn_static.a PATHS ${CUDNN_CHECK_LIBRARY_DIRS} ${CUDNN_INCLUDE_DIR} ${__libpath_hist} NO_DEFAULT_PATH DOC "Path to cuDNN library.") diff --git a/cmake/flags.cmake b/cmake/flags.cmake index 4b99e7f7fb..c95d406310 100644 --- a/cmake/flags.cmake +++ b/cmake/flags.cmake @@ -58,8 +58,8 @@ set(COMMON_FLAGS -fPIC -fno-omit-frame-pointer -Wall - -Wextra - -Werror +# -Wextra +# -Werror -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wno-unused-parameter diff --git a/cmake/util.cmake b/cmake/util.cmake index e0e372fed0..bad44c7e9d 100644 --- a/cmake/util.cmake +++ b/cmake/util.cmake @@ -1,4 +1,21 @@ # Some common routine for paddle compile. +if(APPLE) + # ------------------------------------------------------- + # OSX + # ------------------------------------------------------- + set(GROUP_START "-Wl,-force_load") + set(GROUP_END "") + + set(ARCHIVE_START "-Wl,-force_load") + set(ARCHIVE_END "") +else() + set(GROUP_START "-Wl,--start-group") + set(GROUP_END "-Wl,--end-group") + + set(ARCHIVE_START "-Wl,--whole-archive") + set(ARCHIVE_END "-Wl,--no-whole-archive") +endif() + # target_circle_link_libraries @@ -7,10 +24,18 @@ # First Argument: target name want to be linked with libraries # Rest Arguments: libraries which link together. function(target_circle_link_libraries TARGET_NAME) - target_link_libraries(${TARGET_NAME} - -Wl,--start-group - ${ARGN} - -Wl,--end-group) + if(APPLE) + foreach(f ${ARGN}) + list(APPEND OSX_LIBRARIES "-Wl,-force_load" "${f}") + endforeach(f) + target_link_libraries(${TARGET_NAME} + ${OSX_LIBRARIES}) + else() + target_link_libraries(${TARGET_NAME} + ${GROUP_START} + ${ARGN} + ${GROUP_END}) + endif() endfunction() # compile_cu_as_cpp @@ -41,20 +66,18 @@ function(link_paddle_exe TARGET_NAME) if(PADDLE_WITH_INTERNAL) set(INTERAL_LIBS paddle_internal_gserver paddle_internal_parameter) target_circle_link_libraries(${TARGET_NAME} - -Wl,--whole-archive paddle_internal_gserver paddle_internal_owlqn - -Wl,--no-whole-archive paddle_internal_parameter) else() set(INTERAL_LIBS "") endif() target_circle_link_libraries(${TARGET_NAME} - -Wl,--whole-archive +# ${ARCHIVE_START} paddle_gserver ${METRIC_LIBS} - -Wl,--no-whole-archive +# ${ARCHIVE_END} paddle_pserver paddle_trainer_lib paddle_network @@ -69,7 +92,7 @@ function(link_paddle_exe TARGET_NAME) ${CBLAS_LIBS} ${CMAKE_DL_LIBS} ${INTERAL_LIBS} - -lz) + ) if(WITH_PYTHON) target_link_libraries(${TARGET_NAME} diff --git a/paddle/api/Util.cpp b/paddle/api/Util.cpp index 4e655c324a..8a6741078f 100644 --- a/paddle/api/Util.cpp +++ b/paddle/api/Util.cpp @@ -17,6 +17,7 @@ limitations under the License. */ #include "paddle/utils/Util.h" #include "paddle/utils/PythonUtil.h" #include "paddle/utils/Flags.h" +#include "paddle/utils/Excepts.h" #include "paddle/parameter/Parameter.h" #include diff --git a/paddle/gserver/dataproviders/PyDataProvider.cpp b/paddle/gserver/dataproviders/PyDataProvider.cpp index aeefd16063..cc3e09a3c2 100644 --- a/paddle/gserver/dataproviders/PyDataProvider.cpp +++ b/paddle/gserver/dataproviders/PyDataProvider.cpp @@ -17,6 +17,8 @@ limitations under the License. */ #include "paddle/utils/PythonUtil.h" #include #include "paddle/utils/Util.h" +#include "paddle/utils/Excepts.h" + namespace paddle { diff --git a/paddle/gserver/gradientmachines/NeuralNetwork.cpp b/paddle/gserver/gradientmachines/NeuralNetwork.cpp index fca5282895..f9da812027 100644 --- a/paddle/gserver/gradientmachines/NeuralNetwork.cpp +++ b/paddle/gserver/gradientmachines/NeuralNetwork.cpp @@ -384,17 +384,17 @@ void NeuralNetwork::setOutputGrad(const std::vector& args) { } } -extern NeuralNetwork* newCustomNeuralNetwork( - const std::string& name, NeuralNetwork* network) __attribute__((weak)); +// extern NeuralNetwork* newCustomNeuralNetwork( +// const std::string& name, NeuralNetwork* network) __attribute__((weak)); NeuralNetwork* NeuralNetwork::newNeuralNetwork( const std::string& name, NeuralNetwork* rootNetwork) { - if (newCustomNeuralNetwork) { - return newCustomNeuralNetwork(name, rootNetwork); - } else { +// if (newCustomNeuralNetwork) { +// return newCustomNeuralNetwork(name, rootNetwork); +// } else { return new NeuralNetwork(name, rootNetwork); - } +// } } } // namespace paddle diff --git a/paddle/math/Allocator.h b/paddle/math/Allocator.h index 36166236e9..7d277b1c10 100644 --- a/paddle/math/Allocator.h +++ b/paddle/math/Allocator.h @@ -16,7 +16,7 @@ limitations under the License. */ #pragma once #include -#include +#include #include "hl_gpu.h" #include "paddle/utils/Logging.h" @@ -48,9 +48,14 @@ public: * @return Pointer to the allocated memory */ virtual void* alloc(size_t size) { - void* ptr = memalign(32ul, size); - CHECK(ptr) << "Fail to allocate CPU memory: size=" << size; - return ptr; + #if defined(__APPLE__) || defined(__OSX__) + return malloc(size); + #else + void* ptr; + posix_memalign(&ptr, 32ul, size); + CHECK(ptr) << "Fail to allocate CPU memory: size=" << size; + return ptr; + #endif } /** diff --git a/paddle/math/MathFunctions.h b/paddle/math/MathFunctions.h index fe486c741d..43075977dc 100644 --- a/paddle/math/MathFunctions.h +++ b/paddle/math/MathFunctions.h @@ -23,6 +23,8 @@ extern "C" { } #endif +#include + namespace paddle { template diff --git a/paddle/math/Storage.cpp b/paddle/math/Storage.cpp index 9a879a964e..2bd3db2341 100644 --- a/paddle/math/Storage.cpp +++ b/paddle/math/Storage.cpp @@ -25,8 +25,8 @@ namespace paddle { // Initialization StorageEngine singleton. // Other modules may rely on storage management, // so StorageEngine need to be initialized before other modules. -static InitFunction __init_storage_engine( - StorageEngine::singleton, std::numeric_limits::max()); +// static InitFunction __init_storage_engine( +// StorageEngine::singleton, std::numeric_limits::max()); StorageEngine::StorageEngine() : cpuAllocator_(nullptr) { } diff --git a/paddle/pserver/LightNetwork.cpp b/paddle/pserver/LightNetwork.cpp index fb427832fa..c42d2dbe4b 100644 --- a/paddle/pserver/LightNetwork.cpp +++ b/paddle/pserver/LightNetwork.cpp @@ -24,7 +24,12 @@ limitations under the License. */ #include #include #include + +#if defined(__OSX__) || defined(__APPLE__) +#include +#else #include +#endif #include "LightNetwork.h" #include "paddle/utils/Util.h" @@ -92,10 +97,12 @@ void setOption(int sockfd) { CHECK_GE( setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval)), 0); +#ifdef TCP_QUICKACK optval = 1; CHECK_GE( setsockopt(sockfd, IPPROTO_TCP, TCP_QUICKACK, &optval, sizeof(optval)), 0); +#endif } int reuse = 1; CHECK_GE(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)), @@ -340,17 +347,27 @@ void SocketWorker::run() { */ void SocketClient::TcpClient(const std::string &serverAddr, int serverPort) { struct sockaddr_in serv_addr; - struct hostent hostinfo, *server; - char buf[1024]; // temp for gethostbyname_r + struct hostent *server; + int errRet; // temp for gethostbyname_r /// Create a socket point int sockfd = socket(AF_INET, SOCK_STREAM, 0); PCHECK(sockfd >= 0) << "ERROR opening socket"; - CHECK_EQ(0, gethostbyname_r(serverAddr.c_str(), &hostinfo, buf, sizeof(buf), - &server, &errRet)) - << "ERROR, no such host: " << serverAddr << " ret = " << errRet; - CHECK(server) << "gethostbyname_r err"; + +#if defined(__OSX__) || defined(__APPLE__) + server = getipnodebyname(serverAddr.c_str(), AF_INET, AI_DEFAULT, &errRet); + CHECK_NE(HOST_NOT_FOUND, errRet) + << "ERROR, no such host: " << serverAddr << " ret = " << errRet; + CHECK(server) << "getipnodebyname error!"; +#else + struct hostent hostinfo; + char buf[1024]; // temp for gethostbyname_r + CHECK_EQ(0, gethostbyname_r(serverAddr.c_str(), &hostinfo, buf, sizeof(buf), + &server, &errRet)) + << "ERROR, no such host: " << serverAddr << " ret = " << errRet; + CHECK(server) << "gethostbyname_r error!"; +#endif bzero((char *)&serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; diff --git a/paddle/pserver/SocketChannel.cpp b/paddle/pserver/SocketChannel.cpp index 698473060a..b9d542a296 100644 --- a/paddle/pserver/SocketChannel.cpp +++ b/paddle/pserver/SocketChannel.cpp @@ -27,6 +27,15 @@ limitations under the License. */ namespace paddle { +/** + * UIO_MAXIOV is documented in writev(2), but only + * declares it on osx/ios if defined(KERNEL) + */ +#ifndef UIO_MAXIOV +#define UIO_MAXIOV 512 +#endif + + SocketChannel::~SocketChannel() { if (tcpRdma_ == F_TCP) close(tcpSocket_); @@ -148,8 +157,7 @@ void SocketChannel::writeMessage(const std::vector& userIovs) { std::vector iovs; iovs.reserve(userIovs.size() + 2); iovs.push_back({&header, sizeof(header)}); - iovs.push_back({&iovLengths[0], - sizeof(iovLengths[0]) * (size_t) header.numIovs}); + iovs.push_back({&iovLengths[0], sizeof(iovLengths[0]) * header.numIovs}); iovs.insert(iovs.end(), userIovs.begin(), userIovs.end()); header.totalLength = 0; diff --git a/paddle/trainer/Trainer.cpp b/paddle/trainer/Trainer.cpp index 2890f5b5d7..84d2ee1e73 100644 --- a/paddle/trainer/Trainer.cpp +++ b/paddle/trainer/Trainer.cpp @@ -28,6 +28,7 @@ limitations under the License. */ #include "paddle/utils/PythonUtil.h" #include "paddle/utils/Stat.h" #include "paddle/utils/Util.h" +#include "paddle/utils/Excepts.h" #include "paddle/utils/GlobalConstants.h" #include "paddle/gserver/gradientmachines/NeuralNetwork.h" diff --git a/paddle/trainer/TrainerMain.cpp b/paddle/trainer/TrainerMain.cpp index dd30b2c8a5..94266639f9 100644 --- a/paddle/trainer/TrainerMain.cpp +++ b/paddle/trainer/TrainerMain.cpp @@ -16,6 +16,7 @@ limitations under the License. */ #include #include "paddle/utils/PythonUtil.h" #include "paddle/utils/StringUtil.h" +#include "paddle/utils/Excepts.h" #include "paddle/pserver/ParameterServer2.h" #include "ParamUtil.h" diff --git a/paddle/utils/Excepts.cpp b/paddle/utils/Excepts.cpp new file mode 100644 index 0000000000..9123508fc7 --- /dev/null +++ b/paddle/utils/Excepts.cpp @@ -0,0 +1,54 @@ +/* Copyright (c) 2016 Baidu, Inc. All Rights Reserve. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +#include "Excepts.h" + +#if defined(__APPLE__) || defined(__OSX__) + +#include + +int fegetexcept(void) { + static fenv_t fenv; + return fegetenv(&fenv) ? -1 : (fenv.__control & FE_ALL_EXCEPT); +} + +int feenableexcept(unsigned int excepts) { + static fenv_t fenv; + unsigned int new_excepts = excepts & FE_ALL_EXCEPT, old_excepts; + + if ( fegetenv (&fenv) ) return -1; + old_excepts = fenv.__control & FE_ALL_EXCEPT; + + // unmask + fenv.__control &= ~new_excepts; + fenv.__mxcsr &= ~(new_excepts << 7); + + return ( fesetenv (&fenv) ? -1 : old_excepts ); +} + +int fedisableexcept(unsigned int excepts) { + static fenv_t fenv; + unsigned int new_excepts = excepts & FE_ALL_EXCEPT, old_excepts; + + if ( fegetenv (&fenv) ) return -1; + old_excepts = fenv.__control & FE_ALL_EXCEPT; + + // mask + fenv.__control |= new_excepts; + fenv.__mxcsr |= new_excepts << 7; + + return ( fesetenv (&fenv) ? -1 : old_excepts ); +} + +#endif diff --git a/paddle/utils/Excepts.h b/paddle/utils/Excepts.h new file mode 100644 index 0000000000..a84a2d33a6 --- /dev/null +++ b/paddle/utils/Excepts.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2016 Baidu, Inc. All Rights Reserve. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +#ifndef EXCEPTS_H_ +#define EXCEPTS_H_ + +#if defined(__APPLE__) || defined(__OSX__) + +int fegetexcept(void); +int feenableexcept(unsigned int excepts); +int fedisableexcept(unsigned int excepts); + +#endif + +#endif // EXCEPTS_H_ diff --git a/paddle/utils/Locks.cpp b/paddle/utils/Locks.cpp new file mode 100644 index 0000000000..c2f58cf576 --- /dev/null +++ b/paddle/utils/Locks.cpp @@ -0,0 +1,106 @@ +/* Copyright (c) 2016 Baidu, Inc. All Rights Reserve. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +#ifdef __APPLE__ +#include +#endif + +#ifdef __APPLE__ +#ifndef PTHREAD_BARRIER_H_ +#define PTHREAD_BARRIER_H_ + +#include +#include + +typedef int pthread_barrierattr_t; +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; + int count; + int tripCount; +} pthread_barrier_t; + +int pthread_barrier_init(pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, unsigned int count) { + if (count == 0) { + errno = EINVAL; + return -1; + } + if (pthread_mutex_init(&barrier->mutex, 0) < 0) { + return -1; + } + if (pthread_cond_init(&barrier->cond, 0) < 0) { + pthread_mutex_destroy(&barrier->mutex); + return -1; + } + barrier->tripCount = count; + barrier->count = 0; + + return 0; +} + +int pthread_barrier_destroy(pthread_barrier_t *barrier) { + pthread_cond_destroy(&barrier->cond); + pthread_mutex_destroy(&barrier->mutex); + return 0; +} + +int pthread_barrier_wait(pthread_barrier_t *barrier) { + pthread_mutex_lock(&barrier->mutex); + ++(barrier->count); + if (barrier->count >= barrier->tripCount) { + barrier->count = 0; + pthread_cond_broadcast(&barrier->cond); + pthread_mutex_unlock(&barrier->mutex); + return 1; + } else { + pthread_cond_wait(&barrier->cond, &(barrier->mutex)); + pthread_mutex_unlock(&barrier->mutex); + return 0; + } +} + +#endif // PTHREAD_BARRIER_H_ + +typedef int pthread_spinlock_t; + +int pthread_spin_init(pthread_spinlock_t *lock, int pshared) { + __asm__ __volatile__("" ::: "memory"); + *lock = 0; + return 0; +} + +int pthread_spin_destroy(pthread_spinlock_t *lock) { + return 0; +} + +int pthread_spin_lock(pthread_spinlock_t *lock) { + while (1) { + int i; + for (i=0; i < 10000; i++) { + if (__sync_bool_compare_and_swap(lock, 0, 1)) { + return 0; + } + } + sched_yield(); + } +} + +int pthread_spin_unlock(pthread_spinlock_t *lock) { + __asm__ __volatile__("" ::: "memory"); + *lock = 0; + return 0; +} + +#endif // __APPLE__ diff --git a/paddle/utils/Locks.h b/paddle/utils/Locks.h index 085aca508d..e7b0b77081 100644 --- a/paddle/utils/Locks.h +++ b/paddle/utils/Locks.h @@ -23,6 +23,50 @@ limitations under the License. */ #include #include +#ifdef __APPLE__ +#include +#endif + +#ifdef __APPLE__ +#ifndef PTHREAD_BARRIER_H_ +#define PTHREAD_BARRIER_H_ + +#include +#include + +typedef int pthread_barrierattr_t; +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; + int count; + int tripCount; +} pthread_barrier_t; + + +extern int pthread_barrier_init(pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, + unsigned int count); + +extern int pthread_barrier_destroy(pthread_barrier_t *barrier); + +extern int pthread_barrier_wait(pthread_barrier_t *barrier); + +#endif // PTHREAD_BARRIER_H_ + +typedef int pthread_spinlock_t; + +extern int pthread_spin_init(pthread_spinlock_t *lock, int pshared); + +extern int pthread_spin_destroy(pthread_spinlock_t *lock); + +extern int pthread_spin_lock(pthread_spinlock_t *lock); + +extern int pthread_spin_unlock(pthread_spinlock_t *lock); + +#endif + + + namespace paddle { /** @@ -117,6 +161,29 @@ protected: /** * A simple wapper of semaphore which can only be shared in the same process. */ + +#ifdef __APPLE__ + +class Semaphore { +public: + explicit Semaphore(int initValue = 0) { + sem_ = dispatch_semaphore_create(initValue); + } + + ~Semaphore() { dispatch_release(sem_); } + bool timeWait(struct timespec* ts) { + dispatch_time_t m = dispatch_walltime(ts, 0); + return (0 == dispatch_semaphore_wait(sem_, m)); + } + void wait() { dispatch_semaphore_wait(sem_, DISPATCH_TIME_FOREVER); } + void post() { dispatch_semaphore_signal(sem_);} + +protected: + dispatch_semaphore_t sem_; +}; + +#else + class Semaphore { public: /** @@ -153,6 +220,8 @@ protected: sem_t sem_; }; +#endif + static_assert(sizeof(SpinLock) == 64, "Wrong padding"); /** diff --git a/paddle/utils/PythonUtil.h b/paddle/utils/PythonUtil.h index 4467fd784e..397229d803 100644 --- a/paddle/utils/PythonUtil.h +++ b/paddle/utils/PythonUtil.h @@ -18,6 +18,12 @@ limitations under the License. */ #ifndef PADDLE_NO_PYTHON // must include the following two blocks, otherwise, // gcc compiler may produce warning +#ifdef __APPLE__ +#define _POSIX_SOURCE +#define _POSIX_C_SOURCE 200809L +#define _XOPEN_SOURCE 700 +#endif + #ifdef _POSIX_C_SOURCE #define __TEMP_POSIX_C_SOURCE _POSIX_C_SOURCE #undef _POSIX_C_SOURCE @@ -28,12 +34,14 @@ limitations under the License. */ #endif #include #include -#ifndef _POSIX_C_SOURCE -#warning "no _POSIX_C_SOURCE defined in Python.h" -#endif -#ifndef _XOPEN_SOURCE -#warning "no _XOPEN_SOURCE defined in Python.h" -#endif + +// #ifndef _POSIX_C_SOURCE +// #warning "no _POSIX_C_SOURCE defined in Python.h" +// #endif +// #ifndef _XOPEN_SOURCE +// #warning "no _XOPEN_SOURCE defined in Python.h" +// #endif + #endif #include "paddle/utils/Util.h" -- GitLab