|
GPU-SD
1.0.0
|
00001 00002 /* Copyright (c) 2011, Stefan Eilemann <eile@eyescale.ch> 00003 * 00004 * This library is free software; you can redistribute it and/or modify it under 00005 * the terms of the GNU Lesser General Public License version 2.1 as published 00006 * by the Free Software Foundation. 00007 * 00008 * This library is distributed in the hope that it will be useful, but WITHOUT 00009 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00010 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 00011 * details. 00012 * 00013 * You should have received a copy of the GNU Lesser General Public License 00014 * along with this library; if not, write to the Free Software Foundation, Inc., 00015 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00016 */ 00017 00018 #include "module.h" 00019 00020 #include <gpusd/gpuInfo.h> 00021 #include <dns_sd.h> 00022 #include <algorithm> 00023 #include <cerrno> 00024 #include <cstring> 00025 #include <iostream> 00026 #include <sstream> 00027 #ifndef _WIN32 00028 # include <arpa/inet.h> 00029 # include <sys/time.h> 00030 #endif 00031 00032 #define WAIT_TIME 500 // ms 00033 00034 namespace gpusd 00035 { 00036 namespace dns_sd 00037 { 00038 namespace 00039 { 00040 00041 Module* instance = 0; 00042 00043 static bool handleEvent( DNSServiceRef service ) 00044 { 00045 const int fd = DNSServiceRefSockFD( service ); 00046 const int nfds = fd + 1; 00047 00048 fd_set fdSet; 00049 FD_ZERO( &fdSet ); 00050 FD_SET( fd, &fdSet ); 00051 00052 struct timeval tv; 00053 tv.tv_sec = 0; 00054 tv.tv_usec = WAIT_TIME * 1000; 00055 00056 const int result = select( nfds, &fdSet, 0, 0, &tv ); 00057 switch( result ) 00058 { 00059 case 0: // timeout 00060 return false; 00061 00062 default: 00063 DNSServiceProcessResult( service ); 00064 return true; 00065 00066 case -1: 00067 std::cerr << "Select error: " << strerror( errno ) << " (" 00068 << errno << ")" << std::endl; 00069 return false; 00070 } 00071 } 00072 00073 template< class T > 00074 bool getTXTRecordValue( const uint16_t txtLen, const unsigned char* txt, 00075 const std::string& name, T& result ) 00076 { 00077 uint8_t len = 0; 00078 const char* data = (const char*)TXTRecordGetValuePtr( txtLen, txt, 00079 name.c_str(), &len ); 00080 if( !data || len == 0 ) 00081 return false; 00082 00083 std::istringstream in( std::string( data, len )); 00084 in >> result; 00085 return true; 00086 } 00087 00088 00089 static void resolveCallback( DNSServiceRef service, DNSServiceFlags flags, 00090 uint32_t interfaceIdx, DNSServiceErrorType error, 00091 const char* name, const char* host, uint16_t port, 00092 uint16_t txtLen, const unsigned char* txt, 00093 void* context ) 00094 { 00095 if( error != kDNSServiceErr_NoError) 00096 { 00097 std::cerr << "Resolve callback error: " << error << std::endl; 00098 return; 00099 } 00100 00101 unsigned nGPUs = 0; 00102 getTXTRecordValue( txtLen, txt, "GPU Count", nGPUs ); 00103 if( !nGPUs ) 00104 return; 00105 00106 GPUInfos* result = reinterpret_cast< GPUInfos* >( context ); 00107 for( unsigned i = 0; i < nGPUs; ++i ) 00108 { 00109 std::ostringstream out; 00110 out << "GPU" << i << " "; 00111 const std::string& gpu = out.str(); 00112 00113 std::string type; 00114 if( !getTXTRecordValue( txtLen, txt, gpu + "Type", type )) 00115 continue; 00116 00117 GPUInfo info( type ); 00118 info.hostname = host; 00119 getTXTRecordValue( txtLen, txt, "Session", info.session ); 00120 getTXTRecordValue( txtLen, txt, gpu + "Port", info.port ); 00121 getTXTRecordValue( txtLen, txt, gpu + "Device", info.device ); 00122 getTXTRecordValue( txtLen, txt, gpu + "X", info.pvp[0] ); 00123 getTXTRecordValue( txtLen, txt, gpu + "Y", info.pvp[1] ); 00124 getTXTRecordValue( txtLen, txt, gpu + "Width", info.pvp[2] ); 00125 getTXTRecordValue( txtLen, txt, gpu + "Height", info.pvp[3] ); 00126 result->push_back( info ); 00127 } 00128 } 00129 00130 00131 static void browseCallback( DNSServiceRef service, DNSServiceFlags flags, 00132 uint32_t interfaceIdx, DNSServiceErrorType error, 00133 const char* name, const char* type, 00134 const char* domain, void* context ) 00135 { 00136 if( error != kDNSServiceErr_NoError) 00137 { 00138 std::cerr << "Browse callback error: " << error << std::endl; 00139 return; 00140 } 00141 00142 if( !( flags & kDNSServiceFlagsAdd )) 00143 return; 00144 00145 error = DNSServiceResolve( &service, 0, interfaceIdx, name, type, domain, 00146 (DNSServiceResolveReply)resolveCallback, 00147 context ); 00148 if( error != kDNSServiceErr_NoError) 00149 { 00150 std::cerr << "DNSServiceResolve error: " << error << std::endl; 00151 return; 00152 } 00153 00154 GPUInfos* result = reinterpret_cast< GPUInfos* >( context ); 00155 const size_t old = result->size(); 00156 00157 while( old == result->size() && handleEvent( service )) 00158 /* nop */; 00159 } 00160 00161 } 00162 00163 void Module::use() 00164 { 00165 if( !instance ) 00166 instance = new Module; 00167 } 00168 00169 GPUInfos Module::discoverGPUs_() const 00170 { 00171 DNSServiceRef service; 00172 00173 GPUInfos candidates[2]; 00174 uint32_t interfaces[2] = { 0, kDNSServiceInterfaceIndexLocalOnly }; 00175 for( unsigned i = 0; i < 2; ++i ) 00176 { 00177 const DNSServiceErrorType error = DNSServiceBrowse( &service, 0, 00178 interfaces[i], 00179 "_gpu-sd._tcp", "", 00180 (DNSServiceBrowseReply)browseCallback, 00181 &candidates[i] ); 00182 if( error == kDNSServiceErr_NoError ) 00183 { 00184 while( handleEvent( service )) 00185 /* nop */; 00186 DNSServiceRefDeallocate( service ); 00187 } 00188 else 00189 std::cerr << "DNSServiceDiscovery error: " << error << std::endl; 00190 } 00191 00192 // set localhost records to localhost 00193 for( GPUInfosIter i = candidates[0].begin(); i != candidates[0].end(); ++i ) 00194 { 00195 GPUInfo& info = *i; 00196 if( std::find( candidates[1].begin(), candidates[1].end(), info ) != 00197 candidates[1].end( )) 00198 { 00199 info.hostname.clear(); 00200 } 00201 } 00202 return candidates[0]; 00203 } 00204 00205 } 00206 }
1.0.0 by
1.7.5.1