2
0

benchmark.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. /*
  2. ** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
  3. **
  4. ** This program is free software; you can redistribute it and/or modify
  5. ** it under the terms of the GNU General Public License as published by
  6. ** the Free Software Foundation; either version 2 of the License, or
  7. ** (at your option) any later version.
  8. **
  9. ** This program is distributed in the hope that it will be useful,
  10. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ** GNU General Public License for more details.
  13. **
  14. ** You should have received a copy of the GNU General Public License
  15. ** along with this program; if not, write to the Free Software
  16. ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. #include "sfconfig.h"
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #if HAVE_UNISTD_H
  22. #include <unistd.h>
  23. #endif
  24. #if (HAVE_DECL_S_IRGRP == 0)
  25. #include <sf_unistd.h>
  26. #endif
  27. #include <string.h>
  28. #include <math.h>
  29. #include <time.h>
  30. #include <fcntl.h>
  31. #include <sys/stat.h>
  32. #include <sndfile.h>
  33. #ifndef M_PI
  34. #define M_PI 3.14159265358979323846264338
  35. #endif
  36. /*
  37. ** Neat solution to the Win32/OS2 binary file flage requirement.
  38. ** If O_BINARY isn't already defined by the inclusion of the system
  39. ** headers, set it to zero.
  40. */
  41. #ifndef O_BINARY
  42. #define O_BINARY 0
  43. #endif
  44. #define WRITE_FLAGS (O_WRONLY | O_CREAT | O_TRUNC | O_BINARY)
  45. #define READ_FLAGS (O_RDONLY | O_BINARY)
  46. #if (defined (WIN32) || defined (_WIN32) || defined (__OS2__))
  47. #define WRITE_PERMS 0777
  48. #else
  49. #define WRITE_PERMS (S_IRUSR | S_IWUSR | S_IRGRP)
  50. #endif
  51. #define BUFFER_SIZE (1<<18)
  52. #define BLOCK_COUNT (30)
  53. #define TEST_DURATION (5) /* 5 Seconds. */
  54. typedef struct
  55. { double write_rate ;
  56. double read_rate ;
  57. } PERF_STATS ;
  58. static void *data = NULL ;
  59. static void calc_raw_performance (PERF_STATS *stats) ;
  60. static void calc_short_performance (int format, double read_rate, double write_rate) ;
  61. static void calc_int_performance (int format, double read_rate, double write_rate) ;
  62. static void calc_float_performance (int format, double read_rate, double write_rate) ;
  63. static int cpu_is_big_endian (void) ;
  64. static const char* get_subtype_str (int subtype) ;
  65. int
  66. main (int argc, char *argv [])
  67. { PERF_STATS stats ;
  68. char buffer [256] = "Benchmarking " ;
  69. int format_major ;
  70. if (! (data = malloc (BUFFER_SIZE * sizeof (double))))
  71. { perror ("Error : malloc failed") ;
  72. exit (1) ;
  73. } ;
  74. sf_command (NULL, SFC_GET_LIB_VERSION, buffer + strlen (buffer), sizeof (buffer) - strlen (buffer)) ;
  75. puts (buffer) ;
  76. memset (buffer, '-', strlen (buffer)) ;
  77. puts (buffer) ;
  78. printf ("Each test takes a little over %d seconds.\n\n", TEST_DURATION) ;
  79. calc_raw_performance (&stats) ;
  80. if (argc < 2 || strcmp ("--native-only", argv [1]) == 0)
  81. { puts ("\nNative endian I/O :") ;
  82. format_major = cpu_is_big_endian () ? SF_FORMAT_AIFF : SF_FORMAT_WAV ;
  83. calc_short_performance (format_major | SF_FORMAT_PCM_16, stats.read_rate, stats.write_rate) ;
  84. calc_int_performance (format_major | SF_FORMAT_PCM_24, stats.read_rate, stats.write_rate) ;
  85. calc_int_performance (format_major | SF_FORMAT_PCM_32, stats.read_rate, stats.write_rate) ;
  86. calc_float_performance (format_major | SF_FORMAT_PCM_16, stats.read_rate, stats.write_rate) ;
  87. calc_float_performance (format_major | SF_FORMAT_PCM_24, stats.read_rate, stats.write_rate) ;
  88. calc_float_performance (format_major | SF_FORMAT_PCM_32, stats.read_rate, stats.write_rate) ;
  89. calc_float_performance (format_major | SF_FORMAT_FLOAT , stats.read_rate, stats.write_rate) ;
  90. } ;
  91. if (argc < 2 || strcmp ("--swap-only", argv [1]) == 0)
  92. { puts ("\nEndian swapped I/O :") ;
  93. format_major = cpu_is_big_endian () ? SF_FORMAT_WAV : SF_FORMAT_AIFF ;
  94. calc_short_performance (format_major | SF_FORMAT_PCM_16, stats.read_rate, stats.write_rate) ;
  95. calc_int_performance (format_major | SF_FORMAT_PCM_24, stats.read_rate, stats.write_rate) ;
  96. calc_int_performance (format_major | SF_FORMAT_PCM_32, stats.read_rate, stats.write_rate) ;
  97. calc_float_performance (format_major | SF_FORMAT_PCM_16, stats.read_rate, stats.write_rate) ;
  98. calc_float_performance (format_major | SF_FORMAT_PCM_24, stats.read_rate, stats.write_rate) ;
  99. calc_float_performance (format_major | SF_FORMAT_PCM_32, stats.read_rate, stats.write_rate) ;
  100. calc_float_performance (format_major | SF_FORMAT_FLOAT , stats.read_rate, stats.write_rate) ;
  101. } ;
  102. puts ("") ;
  103. free (data) ;
  104. return 0 ;
  105. } /* main */
  106. /*==============================================================================
  107. */
  108. static void
  109. calc_raw_performance (PERF_STATS *stats)
  110. { clock_t start_clock, clock_time ;
  111. int fd, k, byte_count, retval, op_count ;
  112. const char *filename ;
  113. filename = "benchmark.dat" ;
  114. byte_count = BUFFER_SIZE * sizeof (short) ;
  115. /* Collect write stats */
  116. printf (" Raw write PCM_16 : ") ;
  117. fflush (stdout) ;
  118. clock_time = 0 ;
  119. op_count = 0 ;
  120. start_clock = clock () ;
  121. while (clock_time < (CLOCKS_PER_SEC * TEST_DURATION))
  122. { if ((fd = open (filename, WRITE_FLAGS, WRITE_PERMS)) < 0)
  123. { printf ("Error : not able to open file : %s\n", filename) ;
  124. perror ("") ;
  125. exit (1) ;
  126. } ;
  127. for (k = 0 ; k < BLOCK_COUNT ; k++)
  128. { if ((retval = write (fd, data, byte_count)) != byte_count)
  129. { printf ("Error : write returned %d (should have been %d)\n", retval, byte_count) ;
  130. exit (1) ;
  131. } ;
  132. } ;
  133. close (fd) ;
  134. clock_time = clock () - start_clock ;
  135. op_count ++ ;
  136. } ;
  137. stats->write_rate = (1.0 * BUFFER_SIZE) * BLOCK_COUNT * op_count ;
  138. stats->write_rate *= (1.0 * CLOCKS_PER_SEC) / clock_time ;
  139. printf ("%10.0f samples per sec\n", stats->write_rate) ;
  140. /* Collect read stats */
  141. printf (" Raw read PCM_16 : ") ;
  142. fflush (stdout) ;
  143. clock_time = 0 ;
  144. op_count = 0 ;
  145. start_clock = clock () ;
  146. while (clock_time < (CLOCKS_PER_SEC * TEST_DURATION))
  147. { if ((fd = open (filename, READ_FLAGS)) < 0)
  148. { printf ("Error : not able to open file : %s\n", filename) ;
  149. perror ("") ;
  150. exit (1) ;
  151. } ;
  152. for (k = 0 ; k < BLOCK_COUNT ; k++)
  153. { if ((retval = read (fd, data, byte_count)) != byte_count)
  154. { printf ("Error : write returned %d (should have been %d)\n", retval, byte_count) ;
  155. exit (1) ;
  156. } ;
  157. } ;
  158. close (fd) ;
  159. clock_time = clock () - start_clock ;
  160. op_count ++ ;
  161. } ;
  162. stats->read_rate = (1.0 * BUFFER_SIZE) * BLOCK_COUNT * op_count ;
  163. stats->read_rate *= (1.0 * CLOCKS_PER_SEC) / clock_time ;
  164. printf ("%10.0f samples per sec\n", stats->read_rate) ;
  165. unlink (filename) ;
  166. } /* calc_raw_performance */
  167. /*------------------------------------------------------------------------------
  168. */
  169. static void
  170. calc_short_performance (int format, double read_rate, double write_rate)
  171. { SNDFILE *file ;
  172. SF_INFO sfinfo ;
  173. clock_t start_clock, clock_time ;
  174. double performance ;
  175. int k, item_count, retval, op_count ;
  176. const char* subtype ;
  177. short *short_data ;
  178. const char *filename ;
  179. filename = "benchmark.dat" ;
  180. subtype = get_subtype_str (format & SF_FORMAT_SUBMASK) ;
  181. short_data = data ;
  182. item_count = BUFFER_SIZE ;
  183. for (k = 0 ; k < item_count ; k++)
  184. short_data [k] = 32700.0 * sin (2 * M_PI * k / 32000.0) ;
  185. /* Collect write stats */
  186. printf (" Write %-5s to %s : ", "short", subtype) ;
  187. fflush (stdout) ;
  188. sfinfo.channels = 1 ;
  189. sfinfo.format = format ;
  190. sfinfo.frames = 1 ;
  191. sfinfo.samplerate = 32000 ;
  192. clock_time = 0 ;
  193. op_count = 0 ;
  194. start_clock = clock () ;
  195. while (clock_time < (CLOCKS_PER_SEC * TEST_DURATION))
  196. { if (! (file = sf_open (filename, SFM_WRITE, &sfinfo)))
  197. { printf ("Error : not able to open file : %s\n", filename) ;
  198. perror ("") ;
  199. exit (1) ;
  200. } ;
  201. /* Turn off the addition of a PEAK chunk. */
  202. sf_command (file, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_FALSE) ;
  203. for (k = 0 ; k < BLOCK_COUNT ; k++)
  204. { if ((retval = sf_write_short (file, short_data, item_count)) != item_count)
  205. { printf ("Error : sf_write_short returned %d (should have been %d)\n", retval, item_count) ;
  206. exit (1) ;
  207. } ;
  208. } ;
  209. sf_close (file) ;
  210. clock_time = clock () - start_clock ;
  211. op_count ++ ;
  212. } ;
  213. performance = (1.0 * BUFFER_SIZE) * BLOCK_COUNT * op_count ;
  214. performance *= (1.0 * CLOCKS_PER_SEC) / clock_time ;
  215. printf ("%6.2f%% of raw write\n", 100.0 * performance / write_rate) ;
  216. /* Collect read stats */
  217. printf (" Read %-5s from %s : ", "short", subtype) ;
  218. fflush (stdout) ;
  219. clock_time = 0 ;
  220. op_count = 0 ;
  221. start_clock = clock () ;
  222. while (clock_time < (CLOCKS_PER_SEC * TEST_DURATION))
  223. { if (! (file = sf_open (filename, SFM_READ, &sfinfo)))
  224. { printf ("Error : not able to open file : %s\n", filename) ;
  225. perror ("") ;
  226. exit (1) ;
  227. } ;
  228. for (k = 0 ; k < BLOCK_COUNT ; k++)
  229. { if ((retval = sf_read_short (file, short_data, item_count)) != item_count)
  230. { printf ("Error : write returned %d (should have been %d)\n", retval, item_count) ;
  231. exit (1) ;
  232. } ;
  233. } ;
  234. sf_close (file) ;
  235. clock_time = clock () - start_clock ;
  236. op_count ++ ;
  237. } ;
  238. performance = (1.0 * item_count) * BLOCK_COUNT * op_count ;
  239. performance *= (1.0 * CLOCKS_PER_SEC) / clock_time ;
  240. printf ("%6.2f%% of raw read\n", 100.0 * performance / read_rate) ;
  241. unlink (filename) ;
  242. } /* calc_short_performance */
  243. static void
  244. calc_int_performance (int format, double read_rate, double write_rate)
  245. { SNDFILE *file ;
  246. SF_INFO sfinfo ;
  247. clock_t start_clock, clock_time ;
  248. double performance ;
  249. int k, item_count, retval, op_count ;
  250. const char* subtype ;
  251. int *int_data ;
  252. const char *filename ;
  253. filename = "benchmark.dat" ;
  254. subtype = get_subtype_str (format & SF_FORMAT_SUBMASK) ;
  255. int_data = data ;
  256. item_count = BUFFER_SIZE ;
  257. for (k = 0 ; k < item_count ; k++)
  258. int_data [k] = 32700.0 * (1<<16) * sin (2 * M_PI * k / 32000.0) ;
  259. /* Collect write stats */
  260. printf (" Write %-5s to %s : ", "int", subtype) ;
  261. fflush (stdout) ;
  262. sfinfo.channels = 1 ;
  263. sfinfo.format = format ;
  264. sfinfo.frames = 1 ;
  265. sfinfo.samplerate = 32000 ;
  266. clock_time = 0 ;
  267. op_count = 0 ;
  268. start_clock = clock () ;
  269. while (clock_time < (CLOCKS_PER_SEC * TEST_DURATION))
  270. { if (! (file = sf_open (filename, SFM_WRITE, &sfinfo)))
  271. { printf ("Error : not able to open file : %s\n", filename) ;
  272. perror ("") ;
  273. exit (1) ;
  274. } ;
  275. /* Turn off the addition of a PEAK chunk. */
  276. sf_command (file, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_FALSE) ;
  277. for (k = 0 ; k < BLOCK_COUNT ; k++)
  278. { if ((retval = sf_write_int (file, int_data, item_count)) != item_count)
  279. { printf ("Error : sf_write_short returned %d (should have been %d)\n", retval, item_count) ;
  280. exit (1) ;
  281. } ;
  282. } ;
  283. sf_close (file) ;
  284. clock_time = clock () - start_clock ;
  285. op_count ++ ;
  286. } ;
  287. performance = (1.0 * BUFFER_SIZE) * BLOCK_COUNT * op_count ;
  288. performance *= (1.0 * CLOCKS_PER_SEC) / clock_time ;
  289. printf ("%6.2f%% of raw write\n", 100.0 * performance / write_rate) ;
  290. /* Collect read stats */
  291. printf (" Read %-5s from %s : ", "int", subtype) ;
  292. fflush (stdout) ;
  293. clock_time = 0 ;
  294. op_count = 0 ;
  295. start_clock = clock () ;
  296. while (clock_time < (CLOCKS_PER_SEC * TEST_DURATION))
  297. { if (! (file = sf_open (filename, SFM_READ, &sfinfo)))
  298. { printf ("Error : not able to open file : %s\n", filename) ;
  299. perror ("") ;
  300. exit (1) ;
  301. } ;
  302. for (k = 0 ; k < BLOCK_COUNT ; k++)
  303. { if ((retval = sf_read_int (file, int_data, item_count)) != item_count)
  304. { printf ("Error : write returned %d (should have been %d)\n", retval, item_count) ;
  305. exit (1) ;
  306. } ;
  307. } ;
  308. sf_close (file) ;
  309. clock_time = clock () - start_clock ;
  310. op_count ++ ;
  311. } ;
  312. performance = (1.0 * item_count) * BLOCK_COUNT * op_count ;
  313. performance *= (1.0 * CLOCKS_PER_SEC) / clock_time ;
  314. printf ("%6.2f%% of raw read\n", 100.0 * performance / read_rate) ;
  315. unlink (filename) ;
  316. } /* calc_int_performance */
  317. static void
  318. calc_float_performance (int format, double read_rate, double write_rate)
  319. { SNDFILE *file ;
  320. SF_INFO sfinfo ;
  321. clock_t start_clock, clock_time ;
  322. double performance ;
  323. int k, item_count, retval, op_count ;
  324. const char* subtype ;
  325. float *float_data ;
  326. const char *filename ;
  327. filename = "benchmark.dat" ;
  328. subtype = get_subtype_str (format & SF_FORMAT_SUBMASK) ;
  329. float_data = data ;
  330. item_count = BUFFER_SIZE ;
  331. for (k = 0 ; k < item_count ; k++)
  332. float_data [k] = 1.0 * sin (2 * M_PI * k / 32000.0) ;
  333. /* Collect write stats */
  334. printf (" Write %-5s to %s : ", "float", subtype) ;
  335. fflush (stdout) ;
  336. sfinfo.channels = 1 ;
  337. sfinfo.format = format ;
  338. sfinfo.frames = 1 ;
  339. sfinfo.samplerate = 32000 ;
  340. clock_time = 0 ;
  341. op_count = 0 ;
  342. start_clock = clock () ;
  343. while (clock_time < (CLOCKS_PER_SEC * TEST_DURATION))
  344. { if (! (file = sf_open (filename, SFM_WRITE, &sfinfo)))
  345. { printf ("Error : not able to open file : %s\n", filename) ;
  346. perror ("") ;
  347. exit (1) ;
  348. } ;
  349. /* Turn off the addition of a PEAK chunk. */
  350. sf_command (file, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_FALSE) ;
  351. for (k = 0 ; k < BLOCK_COUNT ; k++)
  352. { if ((retval = sf_write_float (file, float_data, item_count)) != item_count)
  353. { printf ("Error : sf_write_short returned %d (should have been %d)\n", retval, item_count) ;
  354. exit (1) ;
  355. } ;
  356. } ;
  357. sf_close (file) ;
  358. clock_time = clock () - start_clock ;
  359. op_count ++ ;
  360. } ;
  361. performance = (1.0 * BUFFER_SIZE) * BLOCK_COUNT * op_count ;
  362. performance *= (1.0 * CLOCKS_PER_SEC) / clock_time ;
  363. printf ("%6.2f%% of raw write\n", 100.0 * performance / write_rate) ;
  364. /* Collect read stats */
  365. printf (" Read %-5s from %s : ", "float", subtype) ;
  366. fflush (stdout) ;
  367. clock_time = 0 ;
  368. op_count = 0 ;
  369. start_clock = clock () ;
  370. while (clock_time < (CLOCKS_PER_SEC * TEST_DURATION))
  371. { if (! (file = sf_open (filename, SFM_READ, &sfinfo)))
  372. { printf ("Error : not able to open file : %s\n", filename) ;
  373. perror ("") ;
  374. exit (1) ;
  375. } ;
  376. for (k = 0 ; k < BLOCK_COUNT ; k++)
  377. { if ((retval = sf_read_float (file, float_data, item_count)) != item_count)
  378. { printf ("Error : write returned %d (should have been %d)\n", retval, item_count) ;
  379. exit (1) ;
  380. } ;
  381. } ;
  382. sf_close (file) ;
  383. clock_time = clock () - start_clock ;
  384. op_count ++ ;
  385. } ;
  386. performance = (1.0 * item_count) * BLOCK_COUNT * op_count ;
  387. performance *= (1.0 * CLOCKS_PER_SEC) / clock_time ;
  388. printf ("%6.2f%% of raw read\n", 100.0 * performance / read_rate) ;
  389. unlink (filename) ;
  390. } /* calc_float_performance */
  391. /*==============================================================================
  392. */
  393. static int
  394. cpu_is_big_endian (void)
  395. { unsigned char *cptr ;
  396. int endtest ;
  397. endtest = 0x12345678 ;
  398. cptr = (unsigned char*) (&endtest) ;
  399. if (cptr [0] == 0x12 && cptr [1] == 0x34 && cptr [3] == 0x78)
  400. return SF_TRUE ;
  401. return SF_FALSE ;
  402. } /* cpu_is_big_endian */
  403. static const char*
  404. get_subtype_str (int subtype)
  405. { switch (subtype)
  406. { case SF_FORMAT_PCM_16 :
  407. return "PCM_16" ;
  408. case SF_FORMAT_PCM_24 :
  409. return "PCM_24" ;
  410. case SF_FORMAT_PCM_32 :
  411. return "PCM_32" ;
  412. case SF_FORMAT_FLOAT :
  413. return "FLOAT " ;
  414. case SF_FORMAT_DOUBLE :
  415. return "DOUBLE" ;
  416. default : break ;
  417. } ;
  418. return "UNKNOWN" ;
  419. } /* get_subtype_str */