main.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. /******************************************************************************
  2. * Copyright 2010 Duane Merrill
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may ob3ain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. *
  17. *
  18. *
  19. * AUTHORS' REQUEST:
  20. *
  21. * If you use|reference|benchmark this code, please cite our Technical
  22. * Report (http://www.cs.virginia.edu/~dgm4d/papers/RadixSortTR.pdf):
  23. *
  24. * @TechReport{ Merrill:Sorting:2010,
  25. * author = "Duane Merrill and Andrew Grimshaw",
  26. * title = "Revisiting Sorting for GPGPU Stream Architectures",
  27. * year = "2010",
  28. * institution = "University of Virginia, Department of Computer Science",
  29. * address = "Charlottesville, VA, USA",
  30. * number = "CS2010-03"
  31. * }
  32. *
  33. * For more information, see our Google Code project site:
  34. * http://code.google.com/p/back40computing/
  35. *
  36. * Thanks!
  37. ******************************************************************************/
  38. /******************************************************************************
  39. * Simple test driver program for *large-problem* radix sorting.
  40. *
  41. * Useful for demonstrating how to integrate radix sorting into
  42. * your application
  43. ******************************************************************************/
  44. /******************************************************************************
  45. * Converted from CUDA to OpenCL/DirectCompute by Erwin Coumans
  46. ******************************************************************************/
  47. #ifdef _WIN32
  48. #pragma warning (disable:4996)
  49. #endif
  50. #include <stdlib.h>
  51. #include <stdio.h>
  52. #include <string.h>
  53. #include <math.h>
  54. #include <float.h>
  55. #include <algorithm>
  56. #include <string>
  57. //#include <iostream>
  58. #include <sstream>
  59. /**********************
  60. *
  61. */
  62. #include "Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h"
  63. #include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h"
  64. #include "../btgui/Bullet3AppSupport/b3Clock.h"
  65. cl_context g_cxMainContext;
  66. cl_device_id g_device;
  67. cl_command_queue g_cqCommandQueue;
  68. /***********************
  69. *
  70. */
  71. bool g_verbose;
  72. ///Preferred OpenCL device/platform. When < 0 then no preference is used.
  73. ///Note that b3OpenCLUtils might still use the preference of using a platform vendor that matches the SDK vendor used to build the application.
  74. ///Preferred device/platform take priority over this platform-vendor match
  75. int gPreferredDeviceId = -1;
  76. int gPreferredPlatformId = -1;
  77. /******************************************************************************
  78. * Routines
  79. ******************************************************************************/
  80. /**
  81. * Keys-only sorting. Uses the GPU to sort the specified vector of elements for the given
  82. * number of iterations, displaying runtime information.
  83. *
  84. * @param[in] num_elements
  85. * Size in elements of the vector to sort
  86. * @param[in] h_keys
  87. * Vector of keys to sort
  88. * @param[in] iterations
  89. * Number of times to invoke the GPU sorting primitive
  90. * @param[in] cfg
  91. * Config
  92. */
  93. template <typename K>
  94. void TimedSort(
  95. unsigned int num_elements,
  96. K *h_keys,
  97. unsigned int iterations)
  98. {
  99. printf("Keys only, %d iterations, %d elements\n", iterations, num_elements);
  100. int max_elements = num_elements;
  101. b3AlignedObjectArray<unsigned int> hostData;
  102. hostData.resize(num_elements);
  103. for (int i=0;i<num_elements;i++)
  104. {
  105. hostData[i] = h_keys[i];
  106. }
  107. b3RadixSort32CL sorter(g_cxMainContext,g_device,g_cqCommandQueue);
  108. b3OpenCLArray<unsigned int> gpuData(g_cxMainContext,g_cqCommandQueue);
  109. gpuData.copyFromHost(hostData);
  110. //sorter.executeHost(gpuData);
  111. sorter.execute(gpuData);
  112. b3AlignedObjectArray<unsigned int> hostDataSorted;
  113. gpuData.copyToHost(hostDataSorted);
  114. clFinish(g_cqCommandQueue);
  115. {
  116. //printf("Key-values, %d iterations, %d elements", iterations, num_elements);
  117. // Create sorting enactor
  118. // Perform the timed number of sorting iterations
  119. double elapsed = 0;
  120. float duration = 0;
  121. b3Clock watch;
  122. //warm-start
  123. gpuData.copyFromHost(hostData);
  124. clFinish(g_cqCommandQueue);
  125. sorter.execute(gpuData);
  126. watch.reset();
  127. for (int i = 0; i < iterations; i++)
  128. {
  129. // Move a fresh copy of the problem into device storage
  130. gpuData.copyFromHost(hostData);
  131. clFinish(g_cqCommandQueue);
  132. // Start GPU timing record
  133. double startMs = watch.getTimeMicroseconds()/1e3;
  134. // Call the sorting API routine
  135. sorter.execute(gpuData);
  136. clFinish(g_cqCommandQueue);
  137. double stopMs = watch.getTimeMicroseconds()/1e3;
  138. duration = stopMs - startMs;
  139. // End GPU timing record
  140. elapsed += (double) duration;
  141. printf("duration = %f\n", duration);
  142. }
  143. // Display timing information
  144. double avg_runtime = elapsed / iterations;
  145. // double throughput = ((double) num_elements) / avg_runtime / 1000.0 / 1000.0;
  146. // printf(", %f GPU ms, %f x10^9 elts/sec\n", avg_runtime, throughput);
  147. double throughput = ((double) num_elements) / avg_runtime / 1000.0 ;
  148. printf(", %f GPU ms, %f x10^6 elts/sec\n", avg_runtime, throughput);
  149. gpuData.copyToHost(hostData);
  150. for (int i=0;i<num_elements;i++)
  151. {
  152. h_keys[i] = hostData[i];
  153. }
  154. }
  155. }
  156. /**
  157. * Key-value sorting. Uses the GPU to sort the specified vector of elements for the given
  158. * number of iterations, displaying runtime information.
  159. *
  160. * @param[in] num_elements
  161. * Size in elements of the vector to sort
  162. * @param[in] h_keys
  163. * Vector of keys to sort
  164. * @param[in,out] h_values
  165. * Vector of values to sort
  166. * @param[in] iterations
  167. * Number of times to invoke the GPU sorting primitive
  168. * @param[in] cfg
  169. * Config
  170. */
  171. template <typename K, typename V>
  172. void TimedSort(
  173. unsigned int num_elements,
  174. K *h_keys,
  175. V *h_values,
  176. unsigned int iterations)
  177. {
  178. printf("Key-values, %d iterations, %d elements\n", iterations, num_elements);
  179. int max_elements = num_elements;
  180. b3AlignedObjectArray<b3SortData> hostData;
  181. hostData.resize(num_elements);
  182. for (int i=0;i<num_elements;i++)
  183. {
  184. hostData[i].m_key = h_keys[i];
  185. hostData[i].m_value = h_values[i];
  186. }
  187. b3RadixSort32CL sorter(g_cxMainContext,g_device,g_cqCommandQueue);
  188. b3OpenCLArray<b3SortData> gpuData(g_cxMainContext,g_cqCommandQueue);
  189. gpuData.copyFromHost(hostData);
  190. //sorter.executeHost(gpuData);
  191. sorter.execute(gpuData);
  192. b3AlignedObjectArray<b3SortData> hostDataSorted;
  193. gpuData.copyToHost(hostDataSorted);
  194. #if 0
  195. for (int i=0;i<num_elements;i++)
  196. {
  197. printf("hostData[%d].m_key = %d\n",i, hostDataSorted[i].m_key);
  198. printf("hostData[%d].m_value = %d\n",i,hostDataSorted[i].m_value);
  199. }
  200. #endif
  201. clFinish(g_cqCommandQueue);
  202. {
  203. //printf("Key-values, %d iterations, %d elements", iterations, num_elements);
  204. // Create sorting enactor
  205. // Perform the timed number of sorting iterations
  206. double elapsed = 0;
  207. float duration = 0;
  208. b3Clock watch;
  209. //warm-start
  210. gpuData.copyFromHost(hostData);
  211. sorter.execute(gpuData);
  212. clFinish(g_cqCommandQueue);
  213. watch.reset();
  214. for (int i = 0; i < iterations; i++)
  215. {
  216. // Move a fresh copy of the problem into device storage
  217. gpuData.copyFromHost(hostData);
  218. clFinish(g_cqCommandQueue);
  219. // Start GPU timing record
  220. double startMs = watch.getTimeMicroseconds()/1e3;
  221. // Call the sorting API routine
  222. sorter.execute(gpuData);
  223. clFinish(g_cqCommandQueue);
  224. double stopMs = watch.getTimeMicroseconds()/1e3;
  225. duration = stopMs - startMs;
  226. // End GPU timing record
  227. elapsed += (double) duration;
  228. printf("duration = %f\n", duration);
  229. }
  230. // Display timing information
  231. double avg_runtime = elapsed / iterations;
  232. // double throughput = ((double) num_elements) / avg_runtime / 1000.0 / 1000.0;
  233. // printf(", %f GPU ms, %f x10^9 elts/sec\n", avg_runtime, throughput);
  234. double throughput = ((double) num_elements) / avg_runtime / 1000.0 ;
  235. printf(", %f GPU ms, %f x10^6 elts/sec\n", avg_runtime, throughput);
  236. gpuData.copyToHost(hostData);
  237. for (int i=0;i<num_elements;i++)
  238. {
  239. h_keys[i] = hostData[i].m_key;
  240. h_values[i] = hostData[i].m_value;
  241. }
  242. }
  243. }
  244. /**
  245. * Generates random 32-bit keys.
  246. *
  247. * We always take the second-order byte from rand() because the higher-order
  248. * bits returned by rand() are commonly considered more uniformly distributed
  249. * than the lower-order bits.
  250. *
  251. * We can decrease the entropy level of keys by adopting the technique
  252. * of Thearling and Smith in which keys are computed from the bitwise AND of
  253. * multiple random samples:
  254. *
  255. * entropy_reduction | Effectively-unique bits per key
  256. * -----------------------------------------------------
  257. * -1 | 0
  258. * 0 | 32
  259. * 1 | 25.95
  260. * 2 | 17.41
  261. * 3 | 10.78
  262. * 4 | 6.42
  263. * ... | ...
  264. *
  265. */
  266. template <typename K>
  267. void RandomBits(K &key, int entropy_reduction = 0, int lower_key_bits = sizeof(K) * 8)
  268. {
  269. const unsigned int NUM_UCHARS = (sizeof(K) + sizeof(unsigned char) - 1) / sizeof(unsigned char);
  270. unsigned char key_bits[NUM_UCHARS];
  271. do {
  272. for (int j = 0; j < NUM_UCHARS; j++) {
  273. unsigned char quarterword = 0xff;
  274. for (int i = 0; i <= entropy_reduction; i++) {
  275. quarterword &= (rand() >> 7);
  276. }
  277. key_bits[j] = quarterword;
  278. }
  279. if (lower_key_bits < sizeof(K) * 8) {
  280. unsigned long long base = 0;
  281. memcpy(&base, key_bits, sizeof(K));
  282. base &= (1 << lower_key_bits) - 1;
  283. memcpy(key_bits, &base, sizeof(K));
  284. }
  285. memcpy(&key, key_bits, sizeof(K));
  286. } while (key != key); // avoids NaNs when generating random floating point numbers
  287. }
  288. /******************************************************************************
  289. * Templated routines for printing keys/values to the console
  290. ******************************************************************************/
  291. template<typename T>
  292. void PrintValue(T val) {
  293. printf("%d", val);
  294. }
  295. template<>
  296. void PrintValue<float>(float val) {
  297. printf("%f", val);
  298. }
  299. template<>
  300. void PrintValue<double>(double val) {
  301. printf("%f", val);
  302. }
  303. template<>
  304. void PrintValue<unsigned char>(unsigned char val) {
  305. printf("%u", val);
  306. }
  307. template<>
  308. void PrintValue<unsigned short>(unsigned short val) {
  309. printf("%u", val);
  310. }
  311. template<>
  312. void PrintValue<unsigned int>(unsigned int val) {
  313. printf("%u", val);
  314. }
  315. template<>
  316. void PrintValue<long>(long val) {
  317. printf("%ld", val);
  318. }
  319. template<>
  320. void PrintValue<unsigned long>(unsigned long val) {
  321. printf("%lu", val);
  322. }
  323. template<>
  324. void PrintValue<long long>(long long val) {
  325. printf("%lld", val);
  326. }
  327. template<>
  328. void PrintValue<unsigned long long>(unsigned long long val) {
  329. printf("%llu", val);
  330. }
  331. /**
  332. * Compares the equivalence of two arrays
  333. */
  334. template <typename T, typename SizeT>
  335. int CompareResults(T* computed, T* reference, SizeT len, bool verbose = true)
  336. {
  337. printf("\n");
  338. for (SizeT i = 0; i < len; i++) {
  339. if (computed[i] != reference[i]) {
  340. printf("INCORRECT: [%lu]: ", (unsigned long) i);
  341. PrintValue<T>(computed[i]);
  342. printf(" != ");
  343. PrintValue<T>(reference[i]);
  344. if (verbose) {
  345. printf("\nresult[...");
  346. for (size_t j = (i >= 5) ? i - 5 : 0; (j < i + 5) && (j < len); j++) {
  347. PrintValue<T>(computed[j]);
  348. printf(", ");
  349. }
  350. printf("...]");
  351. printf("\nreference[...");
  352. for (size_t j = (i >= 5) ? i - 5 : 0; (j < i + 5) && (j < len); j++) {
  353. PrintValue<T>(reference[j]);
  354. printf(", ");
  355. }
  356. printf("...]");
  357. }
  358. return 1;
  359. }
  360. }
  361. printf("CORRECT\n");
  362. return 0;
  363. }
  364. /**
  365. * Creates an example sorting problem whose keys is a vector of the specified
  366. * number of K elements, values of V elements, and then dispatches the problem
  367. * to the GPU for the given number of iterations, displaying runtime information.
  368. *
  369. * @param[in] iterations
  370. * Number of times to invoke the GPU sorting primitive
  371. * @param[in] num_elements
  372. * Size in elements of the vector to sort
  373. * @param[in] cfg
  374. * Config
  375. */
  376. template<typename K, typename V>
  377. void TestSort(
  378. unsigned int iterations,
  379. int num_elements,
  380. bool keys_only)
  381. {
  382. // Allocate the sorting problem on the host and fill the keys with random bytes
  383. K *h_keys = NULL;
  384. K *h_reference_keys = NULL;
  385. V *h_values = NULL;
  386. h_keys = (K*) malloc(num_elements * sizeof(K));
  387. h_reference_keys = (K*) malloc(num_elements * sizeof(K));
  388. if (!keys_only) h_values = (V*) malloc(num_elements * sizeof(V));
  389. // Use random bits
  390. for (unsigned int i = 0; i < num_elements; ++i) {
  391. RandomBits<K>(h_keys[i], 0);
  392. //h_keys[i] = num_elements-i;
  393. //h_keys[i] = 0xffffffffu-i;
  394. if (!keys_only)
  395. h_values[i] = h_keys[i];//0xffffffffu-i;
  396. h_reference_keys[i] = h_keys[i];
  397. }
  398. // Run the timing test
  399. if (keys_only) {
  400. TimedSort<K>(num_elements, h_keys, iterations);
  401. } else {
  402. TimedSort<K, V>(num_elements, h_keys, h_values, iterations);
  403. }
  404. // cudaThreadSynchronize();
  405. // Display sorted key data
  406. if (g_verbose) {
  407. printf("\n\nKeys:\n");
  408. for (int i = 0; i < num_elements; i++) {
  409. PrintValue<K>(h_keys[i]);
  410. printf(", ");
  411. }
  412. printf("\n\n");
  413. }
  414. // Verify solution
  415. std::sort(h_reference_keys, h_reference_keys + num_elements);
  416. CompareResults<K>(h_keys, h_reference_keys, num_elements, true);
  417. printf("\n");
  418. fflush(stdout);
  419. // Free our allocated host memory
  420. if (h_keys != NULL) free(h_keys);
  421. if (h_values != NULL) free(h_values);
  422. }
  423. /**
  424. * Displays the commandline usage for this tool
  425. */
  426. void Usage()
  427. {
  428. printf("\ntest_large_problem_sorting [--device=<device index>] [--v] [--i=<num-iterations>] [--n=<num-elements>] [--key-values] [--deviceId=<int>] [--platformId=<int>]\n");
  429. printf("\n");
  430. printf("\t--v\tDisplays sorted results to the console.\n");
  431. printf("\n");
  432. printf("\t--i\tPerforms the sorting operation <num-iterations> times\n");
  433. printf("\t\t\ton the device. Re-copies original input each time. Default = 1\n");
  434. printf("\n");
  435. printf("\t--n\tThe number of elements to comprise the sample problem\n");
  436. printf("\t\t\tDefault = 512\n");
  437. printf("\n");
  438. printf("\t--key-values\tSpecifies that keys are accommodated by value pairings\n");
  439. printf("\n");
  440. }
  441. /******************************************************************************
  442. * Command-line parsing
  443. ******************************************************************************/
  444. #include <map>
  445. #include <algorithm>
  446. #include <string>
  447. class b3CommandLineArgs
  448. {
  449. protected:
  450. std::map<std::string, std::string> pairs;
  451. public:
  452. // Constructor
  453. b3CommandLineArgs(int argc, char **argv)
  454. {
  455. using namespace std;
  456. for (int i = 1; i < argc; i++)
  457. {
  458. string arg = argv[i];
  459. if ((arg[0] != '-') || (arg[1] != '-')) {
  460. continue;
  461. }
  462. string::size_type pos;
  463. string key, val;
  464. if ((pos = arg.find( '=')) == string::npos) {
  465. key = string(arg, 2, arg.length() - 2);
  466. val = "";
  467. } else {
  468. key = string(arg, 2, pos - 2);
  469. val = string(arg, pos + 1, arg.length() - 1);
  470. }
  471. pairs[key] = val;
  472. }
  473. }
  474. bool CheckCmdLineFlag(const char* arg_name)
  475. {
  476. using namespace std;
  477. map<string, string>::iterator itr;
  478. if ((itr = pairs.find(arg_name)) != pairs.end()) {
  479. return true;
  480. }
  481. return false;
  482. }
  483. template <typename T>
  484. void GetCmdLineArgument(const char *arg_name, T &val);
  485. int ParsedArgc()
  486. {
  487. return pairs.size();
  488. }
  489. };
  490. template <typename T>
  491. void b3CommandLineArgs::GetCmdLineArgument(const char *arg_name, T &val)
  492. {
  493. using namespace std;
  494. map<string, string>::iterator itr;
  495. if ((itr = pairs.find(arg_name)) != pairs.end()) {
  496. istringstream strstream(itr->second);
  497. strstream >> val;
  498. }
  499. }
  500. template <>
  501. void b3CommandLineArgs::GetCmdLineArgument<char*>(const char* arg_name, char* &val)
  502. {
  503. using namespace std;
  504. map<string, string>::iterator itr;
  505. if ((itr = pairs.find(arg_name)) != pairs.end()) {
  506. string s = itr->second;
  507. val = (char*) malloc(sizeof(char) * (s.length() + 1));
  508. strcpy(val, s.c_str());
  509. } else {
  510. val = NULL;
  511. }
  512. }
  513. /******************************************************************************
  514. * Main
  515. ******************************************************************************/
  516. extern bool gDebugSkipLoadingBinary;
  517. void myprintf(const char* msg)
  518. {
  519. (void*) msg;
  520. }
  521. int main( int argc, char** argv)
  522. {
  523. //gDebugSkipLoadingBinary = true;
  524. // b3SetCustomPrintfFunc(myprintf);
  525. cl_int ciErrNum;
  526. b3CommandLineArgs args(argc,argv);
  527. args.GetCmdLineArgument("deviceId", gPreferredDeviceId);
  528. args.GetCmdLineArgument("platformId", gPreferredPlatformId);
  529. b3Printf("Initialize OpenCL using b3OpenCLUtils_createContextFromType\n");
  530. cl_platform_id platformId;
  531. // g_cxMainContext = b3OpenCLUtils_createContextFromType(CL_DEVICE_TYPE_ALL, &ciErrNum, 0, 0,gPreferredDeviceId,gPreferredPlatformId,&platformId);
  532. g_cxMainContext = b3OpenCLUtils_createContextFromType(CL_DEVICE_TYPE_GPU, &ciErrNum, 0, 0,gPreferredDeviceId,gPreferredPlatformId,&platformId);
  533. //g_cxMainContext = b3OpenCLUtils_createContextFromType(CL_DEVICE_TYPE_CPU, &ciErrNum, 0, 0,gPreferredDeviceId,gPreferredPlatformId,&platformId);
  534. oclCHECKERROR(ciErrNum, CL_SUCCESS);
  535. int numDev = b3OpenCLUtils_getNumDevices(g_cxMainContext);
  536. if (!numDev)
  537. {
  538. b3Error("error: no OpenCL devices\n");
  539. exit(0);
  540. }
  541. int devId = 0;
  542. g_device = b3OpenCLUtils_getDevice(g_cxMainContext,devId);
  543. b3OpenCLUtils_printDeviceInfo(g_device);
  544. // create a command-queue
  545. g_cqCommandQueue = clCreateCommandQueue(g_cxMainContext, g_device, 0, &ciErrNum);
  546. oclCHECKERROR(ciErrNum, CL_SUCCESS);
  547. //srand(time(NULL));
  548. srand(0); // presently deterministic
  549. unsigned int num_elements = 8*1024*1024;//4*1024*1024;//4*1024*1024;//257;//8*524288;//2048;//512;//524288;
  550. unsigned int iterations = 10;
  551. bool keys_only = true;
  552. //
  553. // Check command line arguments
  554. //
  555. if (args.CheckCmdLineFlag("help"))
  556. {
  557. Usage();
  558. return 0;
  559. }
  560. args.GetCmdLineArgument("i", iterations);
  561. args.GetCmdLineArgument("n", num_elements);
  562. keys_only = !args.CheckCmdLineFlag("key-values");
  563. g_verbose = args.CheckCmdLineFlag("v");
  564. TestSort<unsigned int, unsigned int>(
  565. iterations,
  566. num_elements,
  567. keys_only);
  568. }