//////////////////////////////////////////////////////////////////////////// // File: MultiThreadSIFT.cpp // Author: Changchang Wu // Description : An example to show how to use SiftGPU in multi-threading // with each thread using different GPU device. // The same idea also applies to SiftMatchGPU. // // // Copyright (c) 2007 University of North Carolina at Chapel Hill // All Rights Reserved // // Permission to use, copy, modify and distribute this software and its // documentation for educational, research and non-profit purposes, without // fee, and without a written agreement is hereby granted, provided that the // above copyright notice and the following paragraph appear in all copies. // // The University of North Carolina at Chapel Hill make no representations // about the suitability of this software for any purpose. It is provided // 'as is' without express or implied warranty. // // Please send BUG REPORTS to ccwu@cs.unc.edu // //////////////////////////////////////////////////////////////////////////// #include #include #include using std::vector; using std::iostream; #include #ifdef _WIN32 #include //define this to get dll import definition for win32 #define SIFTGPU_DLL #ifdef _DEBUG #pragma comment(lib, "../../lib/siftgpu_d.lib") #else #pragma comment(lib, "../../lib/siftgpu.lib") #endif #define thread_t HANDLE #else #include #include #define thread_t pthread_t pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER; #endif #include "../SiftGPU/SiftGPU.h" class ScopedMutex { #ifdef _WIN32 private: HANDLE hmutex; public: ScopedMutex(const char* name) { hmutex = CreateMutex(NULL, FALSE, name); WaitForSingleObject(hmutex, INFINITE); } ~ScopedMutex() { ReleaseMutex(hmutex); CloseHandle(hmutex); } #else public: ScopedMutex(const char* name) { pthread_mutex_lock(&global_mutex); } ~ScopedMutex() { pthread_mutex_unlock(&global_mutex); } #endif }; class MultiThreadSIFT { protected: SiftGPU* _sift; const void * _thread_param; int _device_id; private: void Initialize(int device_id) { ScopedMutex mutex("siftgpu_initialize"); printf("#%d: Initialize MultiThreadSIFT...", device_id); InitializeSIFT(); printf("done\n"); //The initialization part should be protected by a mutex in //single-process-multi-thread mode. For now many parameters //are still global static variables. } public: MultiThreadSIFT(int device_id = 0, const void* thread_param = NULL) { _thread_param = thread_param; _device_id = device_id; } virtual ~MultiThreadSIFT() { if(_sift) delete _sift; } thread_t RunThread() { #ifdef _WIN32 return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RunMultiThreadSIFT, this, 0, 0); #else thread_t threadid; pthread_create(&threadid, NULL, RunMultiThreadSIFT, this); return threadid; #endif } #ifdef _WIN32 static DWORD #else static void* #endif RunMultiThreadSIFT(void* mts) { MultiThreadSIFT* mtsift = (MultiThreadSIFT*) mts; mtsift->Initialize(mtsift->_device_id); mtsift->RunTask(); return 0; } public: //Two Functions to overload for specific task virtual void RunTask() { } //set parameters and initizlze SIFT virtual void InitializeSIFT() { //////////////////////////// char device[2] = {'0' + _device_id, '\0'}; //works for 0-9...use sprintf if you have more than 10 char * argv[] = {"-fo", "-1", "-v", "0", "-cuda", device}; //-nogl was previously required, but now default int argc = sizeof(argv)/sizeof(char*); ///////////////////////////////////// _sift = new SiftGPU; _sift->ParseParam(argc, argv); //create an OpenGL context for computation, and SiftGPU will be initialized automatically if(_sift->CreateContextGL() != SiftGPU::SIFTGPU_FULL_SUPPORTED) exit(0); } }; //Multi-threading demo. //Each thread will load a file, and repeat the processing 100 times. class MultiThreadDemo: public MultiThreadSIFT { public: MultiThreadDemo(int deviceid, const char* filename): MultiThreadSIFT(deviceid, filename) { } virtual void RunTask() { printf("#%d, running task\n", _device_id); time_t t1, t2; t1 = time(NULL); for(int i = 0; i < 100; ++i) _sift->RunSIFT(); t2 = time(NULL); printf("#%d: %dhz\n", _device_id, int(100/(t2-t1))); } virtual void InitializeSIFT() { MultiThreadSIFT::InitializeSIFT(); const char* filename = (const char*) _thread_param; _sift->RunSIFT(filename); ////////////////////////////////////////////////////////////////////// //WARNING: the image loader (DeviL) used by SiftGPU is not thread-safe. //This demo will put the file loading part in InitializeSIFT, which //is protected by a mutex. In your multi-thread application, you should //load the image data outside SiftGPU, and specify the memory data to //SiftGPU directly. ///////////////////////////////////////////////////////////////////// } }; //Multi-process demo //Each process will repeat the processing of a file for 100 times. class MultiProcessDemo: public MultiThreadSIFT { public: MultiProcessDemo(int deviceid, const char* filename): MultiThreadSIFT(deviceid, filename) { } virtual void RunTask() { char* filename = (char*) _thread_param; time_t t1, t2; t1 = time(NULL); for(int i = 0; i < 100; ++i) _sift->RunSIFT(filename); t2 = time(NULL); printf("Speed on device %d : %dhz\n", _device_id, int(100/(t2-t1))); } virtual void InitializeSIFT() { //Although the multi-process demo here uses CUDA, //if multiple GPUs are mapped to multiple monitors/displayes //it is possible to use OpenGL (not CUDA)for this. //Also, the mutex protection is not necessary char device[2] = {'0' + _device_id, '\0'}; //works for 0-9...use sprintf if you have more than 10 char * argv[] = {"-fo", "-1", "-v", "0", "-cuda", device}; int argc = sizeof(argv)/sizeof(char*); ///////////////////////////////////// //create two server with differ socket ports _sift = CreateRemoteSiftGPU(7777 + _device_id, NULL); _sift->ParseParam(argc, argv); //create an OpenGL context for computation, and SiftGPU will be initialized automatically if(_sift->CreateContextGL() != SiftGPU::SIFTGPU_FULL_SUPPORTED) exit(0); } }; int main() { //NOTE that SiftGPU must be compiled with CUDA for this demo MultiThreadDemo thread1(0, "../data/640-1.jpg"); MultiThreadDemo thread2(1, "../data/800-1.jpg"); //Use MultiProcessDemo for multi-process mode //MultiProcessDemo thread1(0, "../data/640-1.jpg"); //MultiProcessDemo thread2(1, "../data/800-1.jpg"); printf("Starting two threads...\n"); thread_t t1 = thread1.RunThread(); thread_t t2 = thread2.RunThread(); #ifdef _WIN32 HANDLE handles[2] = {t1, t2}; WaitForMultipleObjects(2, handles, TRUE, INFINITE); //////////////////////////////////////////////////////////////// CloseHandle(t1); CloseHandle(t2); #else pthread_join(t1, NULL); pthread_join(t2, NULL); #endif return 1; }