PageRenderTime 47ms CodeModel.GetById 9ms RepoModel.GetById 1ms app.codeStats 0ms

/src/shared/write_c_binary.c

https://gitlab.com/Aaeinstein54/specfem3d
C | 600 lines | 323 code | 118 blank | 159 comment | 54 complexity | 665f815837f46817729fa2756620f679 MD5 | raw file
  1. /*
  2. !=====================================================================
  3. !
  4. ! S p e c f e m 3 D V e r s i o n 3 . 0
  5. ! ---------------------------------------
  6. !
  7. ! Main historical authors: Dimitri Komatitsch and Jeroen Tromp
  8. ! Princeton University, USA
  9. ! and CNRS / University of Marseille, France
  10. ! (there are currently many more authors!)
  11. ! (c) Princeton University and CNRS / University of Marseille, July 2012
  12. !
  13. ! This program is free software; you can redistribute it and/or modify
  14. ! it under the terms of the GNU General Public License as published by
  15. ! the Free Software Foundation; either version 2 of the License, or
  16. ! (at your option) any later version.
  17. !
  18. ! This program is distributed in the hope that it will be useful,
  19. ! but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. ! GNU General Public License for more details.
  22. !
  23. ! You should have received a copy of the GNU General Public License along
  24. ! with this program; if not, write to the Free Software Foundation, Inc.,
  25. ! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  26. !
  27. !=====================================================================
  28. */
  29. // for large files
  30. #define _FILE_OFFSET_BITS 64
  31. #include "config.h"
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <unistd.h>
  35. #include <sys/types.h>
  36. #include <sys/stat.h>
  37. #include <fcntl.h>
  38. static int fd;
  39. void
  40. FC_FUNC_(open_file_create,OPEN_FILE)(char *file) {
  41. fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
  42. if (fd == -1) {
  43. fprintf(stderr, "Error opening file: %s exiting\n", file);
  44. exit(-1);
  45. }
  46. }
  47. void
  48. FC_FUNC_(open_file_append,OPEN_FILE)(char *file) {
  49. fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0644);
  50. if (fd == -1) {
  51. fprintf(stderr, "Error opening file: %s exiting\n", file);
  52. exit(-1);
  53. }
  54. }
  55. void
  56. FC_FUNC_(close_file,CLOSE_FILE)() {
  57. close(fd);
  58. }
  59. void
  60. FC_FUNC_(write_integer,WRITE_INTEGER)(int *z) {
  61. int dummy_unused_variable = write(fd, z, sizeof(int));
  62. }
  63. void
  64. FC_FUNC_(write_real,WRITE_REAL)(float *z) {
  65. int dummy_unused_variable = write(fd, z, sizeof(float));
  66. }
  67. void
  68. FC_FUNC_(write_n_real,WRITE_N_REAL)(float *z,int *n) {
  69. int dummy_unused_variable = write(fd, z, *n*sizeof(float));
  70. }
  71. void
  72. FC_FUNC_(write_character,WRITE_CHARACTER)(char *z, int *lchar) {
  73. int dummy_unused_variable = write(fd, z, *lchar*sizeof(char));
  74. }
  75. void
  76. FC_FUNC_(open_file_fd,OPEN_FILE_FD)(char *file, int *pfd) {
  77. *pfd = open(file, O_WRONLY | O_CREAT, 0644);
  78. if (*pfd == -1) {
  79. fprintf(stderr, "Error opening file: %s exiting\n", file);
  80. exit(-1);
  81. }
  82. }
  83. void
  84. FC_FUNC_(close_file_fd,CLOSE_FILE_FD)(int *pfd) {
  85. close(*pfd);
  86. }
  87. void
  88. FC_FUNC_(write_integer_fd,WRITE_INTEGER_FD)(int *pfd, int *z) {
  89. int dummy_unused_variable = write(*pfd, z, sizeof(int));
  90. }
  91. void
  92. FC_FUNC_(write_real_fd,WRITE_REAL_FD)(int *pfd, float *z) {
  93. int dummy_unused_variable = write(*pfd, z, sizeof(float));
  94. }
  95. void
  96. FC_FUNC_(write_n_real_fd,WRITE_N_REAL_FD)(int *pfd, float *z,int *n) {
  97. int dummy_unused_variable = write(*pfd, z, *n*sizeof(float));
  98. }
  99. void
  100. FC_FUNC_(write_character_fd,WRITE_CHARACTER_FD)(int *pfd, char *z, int *lchar) {
  101. int dummy_unused_variable = write(*pfd, z, *lchar*sizeof(char));
  102. }
  103. /* ---------------------------------------
  104. IO performance test
  105. Software Optimization for High Performance Computing: Creating Faster Applications
  106. By Isom L. Crawford and Kevin R. Wadleigh
  107. Jul 18, 2003
  108. - uses functions fopen/fread/fwrite for binary file I/O
  109. --------------------------------------- */
  110. #define __USE_GNU
  111. #include <string.h>
  112. #include <regex.h>
  113. #define MIN(x,y) ((x) < (y) ? (x) : (y))
  114. /* fastest performance on nehalem nodes:
  115. Linux 2.6.18-164.11.1.el5 #1 SMP Wed Jan 20 10:04:55 EST 2010 x86_64 x86_64 x86_64 GNU/Linux
  116. achieved with 16 KB buffers: */
  117. //#define MAX_B 65536 // 64 KB
  118. //#define MAX_B 32768 // 32 KB
  119. #define MAX_B 16384 // 16 KB
  120. //#define MAX_B 8192 // 8 KB
  121. // absorbing files: instead of passing file descriptor, we use the array index
  122. // first 0 - 3 indices for crust mantle files
  123. // last 4 - 8 indices for outer core files
  124. // index 9 - for NOISE_TOMOGRAPHY (SURFACE_MOVIE)
  125. #define ABS_FILEID 10
  126. // file points
  127. static FILE * fp_abs[ABS_FILEID];
  128. // file work buffers
  129. static char * work_buffer[ABS_FILEID];
  130. void open_file_abs_r_fbin(int *fid, char *filename,int *length, long long *filesize){
  131. // opens file for read access
  132. //This sequence assigns the MAX_B array work_buffer to the file pointer
  133. // to be used for its buffering. performance should benefit.
  134. char * fncopy;
  135. char * blank;
  136. FILE *ft;
  137. int ret;
  138. // checks filesize
  139. if (*filesize == 0){
  140. perror("Error file size for reading");
  141. exit(EXIT_FAILURE);
  142. }
  143. // Trim the file name.
  144. fncopy = strndup(filename, *length);
  145. blank = strchr(fncopy, ' ');
  146. if (blank != NULL) {
  147. fncopy[blank - fncopy] = '\0';
  148. }
  149. // opens file
  150. ft = fopen( fncopy, "rb+" );
  151. if (ft == NULL ) { perror("fopen"); exit(-1); }
  152. // sets mode for full buffering
  153. work_buffer[*fid] = (char *)malloc(MAX_B);
  154. ret = setvbuf( ft, work_buffer[*fid], _IOFBF, (size_t)MAX_B );
  155. if (ret != 0){
  156. perror("Error setting working buffer");
  157. exit(EXIT_FAILURE);
  158. }
  159. // stores file index id fid: from 0 to 8
  160. fp_abs[*fid] = ft;
  161. free(fncopy);
  162. }
  163. void open_file_abs_w_fbin(int *fid, char *filename, int *length, long long *filesize){
  164. // opens file for write access
  165. //This sequence assigns the MAX_B array work_buffer to the file pointer
  166. // to be used for its buffering. performance should benefit.
  167. char * fncopy;
  168. char * blank;
  169. FILE *ft;
  170. int ret;
  171. // checks filesize
  172. if (*filesize == 0){
  173. perror("Error file size for writing");
  174. exit(EXIT_FAILURE);
  175. }
  176. // Trim the file name.
  177. fncopy = strndup(filename, *length);
  178. blank = strchr(fncopy, ' ');
  179. if (blank != NULL) {
  180. fncopy[blank - fncopy] = '\0';
  181. }
  182. // opens file
  183. ft = fopen( fncopy, "wb+" );
  184. if (ft == NULL ) { perror("fopen"); exit(-1); }
  185. // sets mode for full buffering
  186. work_buffer[*fid] = (char *)malloc(MAX_B);
  187. ret = setvbuf( ft, work_buffer[*fid], _IOFBF, (size_t)MAX_B );
  188. if (ret != 0){
  189. perror("Error setting working buffer");
  190. exit(EXIT_FAILURE);
  191. }
  192. // stores file index id fid: from 0 to 8
  193. fp_abs[*fid] = ft;
  194. free(fncopy);
  195. }
  196. void close_file_abs_fbin(int * fid){
  197. // closes file
  198. fclose(fp_abs[*fid]);
  199. free(work_buffer[*fid]);
  200. }
  201. void write_abs_fbin(int *fid, char *buffer, int *length, int *index){
  202. // writes binary file data in chunks of MAX_B
  203. FILE *ft;
  204. int itemlen,remlen,donelen,ret;
  205. // file pointer
  206. ft = fp_abs[*fid];
  207. donelen = 0;
  208. remlen = *length;
  209. ret = 0;
  210. // writes items of maximum MAX_B to the file
  211. while (remlen > 0){
  212. itemlen = MIN(remlen,MAX_B);
  213. ret = fwrite(buffer,1,itemlen,ft);
  214. if (ret > 0){
  215. donelen = donelen + ret;
  216. remlen = remlen - MAX_B;
  217. buffer += MAX_B;
  218. }
  219. else{
  220. remlen = 0;
  221. }
  222. }
  223. }
  224. void read_abs_fbin(int *fid, char *buffer, int *length, int *index){
  225. // reads binary file data in chunks of MAX_B
  226. FILE *ft;
  227. int ret,itemlen,remlen,donelen;
  228. long long pos;
  229. // file pointer
  230. ft = fp_abs[*fid];
  231. // positions file pointer (for reverse time access)
  232. pos = ((long long)*length) * (*index -1);
  233. ret = fseek(ft, pos , SEEK_SET);
  234. if (ret != 0) {
  235. perror("Error fseek");
  236. exit(EXIT_FAILURE);
  237. }
  238. donelen = 0;
  239. remlen = *length;
  240. ret = 0;
  241. // reads items of maximum MAX_B to the file
  242. while (remlen > 0){
  243. // checks end of file
  244. if (ferror(ft) || feof(ft)) return;
  245. itemlen = MIN(remlen,MAX_B);
  246. ret = fread(buffer,1,itemlen,ft);
  247. if (ferror(ft) || feof(ft)) return;
  248. if (ret > 0){
  249. donelen = donelen + ret;
  250. remlen = remlen - MAX_B;
  251. buffer += MAX_B;
  252. }
  253. else{
  254. remlen = 0;
  255. }
  256. }
  257. }
  258. /* ---------------------------------------
  259. IO performance test
  260. A Performance Comparison of "read" and "mmap" in the Solaris 8 OS
  261. By Oyetunde Fadele, September 2002
  262. http://developers.sun.com/solaris/articles/read_mmap.html
  263. or
  264. High-performance network programming, Part 2: Speed up processing at both the client and server
  265. by Girish Venkatachalam
  266. http://www.ibm.com/developerworks/aix/library/au-highperform2/
  267. - uses functions mmap/memcpy for mapping file I/O
  268. ------------------------------------- */
  269. #include <errno.h>
  270. #include <limits.h>
  271. #include <sys/mman.h>
  272. // file maps
  273. static char * map_abs[ABS_FILEID];
  274. // file descriptors
  275. static int map_fd_abs[ABS_FILEID];
  276. // file sizes
  277. static long long filesize_abs[ABS_FILEID];
  278. void open_file_abs_w_map(int *fid, char *filename, int *length, long long *filesize){
  279. // opens file for write access
  280. int ft;
  281. int result;
  282. char *map;
  283. char *fncopy;
  284. char *blank;
  285. // checks filesize
  286. if (*filesize == 0){
  287. perror("Error file size for writing");
  288. exit(EXIT_FAILURE);
  289. }
  290. // Trim the file name.
  291. fncopy = strndup(filename, *length);
  292. blank = strchr(fncopy, ' ');
  293. if (blank != NULL) {
  294. fncopy[blank - fncopy] = '\0';
  295. }
  296. /* Open a file for writing.
  297. * - Creating the file if it doesn't exist.
  298. * - Truncating it to 0 size if it already exists. (not really needed)
  299. *
  300. * Note: "O_WRONLY" mode is not sufficient when mmaping.
  301. */
  302. ft = open(fncopy, O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600);
  303. if (ft == -1) {
  304. perror("Error opening file for writing");
  305. exit(EXIT_FAILURE);
  306. }
  307. // file index id fid: from 0 to 8
  308. map_fd_abs[*fid] = ft;
  309. free(fncopy);
  310. /* Stretch the file size to the size of the (mmapped) array of ints
  311. */
  312. filesize_abs[*fid] = *filesize;
  313. result = lseek(ft, filesize_abs[*fid] - 1, SEEK_SET);
  314. if (result == -1) {
  315. close(ft);
  316. perror("Error calling lseek() to 'stretch' the file");
  317. exit(EXIT_FAILURE);
  318. }
  319. /* Something needs to be written at the end of the file to
  320. * have the file actually have the new size.
  321. * Just writing an empty string at the current file position will do.
  322. *
  323. * Note:
  324. * - The current position in the file is at the end of the stretched
  325. * file due to the call to lseek().
  326. * - An empty string is actually a single '\0' character, so a zero-byte
  327. * will be written at the last byte of the file.
  328. */
  329. result = write(ft, "", 1);
  330. if (result != 1) {
  331. close(ft);
  332. perror("Error writing last byte of the file");
  333. exit(EXIT_FAILURE);
  334. }
  335. /* Now the file is ready to be mmapped.
  336. */
  337. map = mmap(0, filesize_abs[*fid], PROT_READ | PROT_WRITE, MAP_SHARED, ft, 0);
  338. if (map == MAP_FAILED) {
  339. close(ft);
  340. perror("Error mmapping the file");
  341. exit(EXIT_FAILURE);
  342. }
  343. map_abs[*fid] = map;
  344. }
  345. void open_file_abs_r_map(int *fid, char *filename,int *length, long long *filesize){
  346. // opens file for read access
  347. char * fncopy;
  348. char * blank;
  349. int ft;
  350. char *map;
  351. // checks filesize
  352. if (*filesize == 0){
  353. perror("Error file size for reading");
  354. exit(EXIT_FAILURE);
  355. }
  356. // Trim the file name.
  357. fncopy = strndup(filename, *length);
  358. blank = strchr(fncopy, ' ');
  359. if (blank != NULL) {
  360. fncopy[blank - fncopy] = '\0';
  361. }
  362. ft = open(fncopy, O_RDONLY);
  363. if (ft == -1) {
  364. perror("Error opening file for reading");
  365. exit(EXIT_FAILURE);
  366. }
  367. // file index id fid: from 0 to 8
  368. map_fd_abs[*fid] = ft;
  369. free(fncopy);
  370. filesize_abs[*fid] = *filesize;
  371. map = mmap(0, filesize_abs[*fid], PROT_READ, MAP_SHARED, ft, 0);
  372. if (map == MAP_FAILED) {
  373. close(ft);
  374. perror("Error mmapping the file");
  375. exit(EXIT_FAILURE);
  376. }
  377. map_abs[*fid] = map;
  378. }
  379. void close_file_abs_map(int * fid){
  380. /* Don't forget to free the mmapped memory
  381. */
  382. if (munmap(map_abs[*fid], filesize_abs[*fid]) == -1) {
  383. perror("Error un-mmapping the file");
  384. /* Decide here whether to close(fd) and exit() or not. Depends... */
  385. }
  386. /* Un-mmaping doesn't close the file, so we still need to do that.
  387. */
  388. close(map_fd_abs[*fid]);
  389. }
  390. void write_abs_map(int *fid, char *buffer, int *length , int *index){
  391. char *map;
  392. long long offset;
  393. map = map_abs[*fid];
  394. // offset in bytes
  395. offset = ((long long)*index -1) * (*length) ;
  396. // copies buffer to map
  397. memcpy( &map[offset], buffer, *length );
  398. }
  399. void read_abs_map(int *fid, char *buffer, int *length , int *index){
  400. char *map;
  401. long long offset;
  402. map = map_abs[*fid];
  403. // offset in bytes
  404. offset = ((long long)*index -1) * (*length) ;
  405. // copies map to buffer
  406. memcpy( buffer, &map[offset], *length );
  407. }
  408. /*
  409. wrapper functions
  410. - for your preferred, optimized file i/o ;
  411. e.g. uncomment // #define USE_MAP... in config.h to use mmap routines
  412. or comment out (default) to use fopen/fwrite/fread functions
  413. note: mmap functions should work fine for local harddisk directories, but can lead to
  414. problems with global (e.g. NFS) directories
  415. (on nehalem, Linux 2.6.18-164.11.1.el5 #1 SMP Wed Jan 20 10:04:55 EST 2010 x86_64 x86_64 x86_64 GNU/Linux
  416. - mmap functions are about 20 % faster than conventional fortran, unformatted file i/o
  417. - fwrite/fread function are about 12 % faster than conventional fortran, unformatted file i/o )
  418. */
  419. void
  420. FC_FUNC_(open_file_abs_w,OPEN_FILE_ABS_W)(int *fid, char *filename,int *length, long long *filesize) {
  421. #ifdef USE_MAP_FUNCTION
  422. open_file_abs_w_map(fid,filename,length,filesize);
  423. #else
  424. open_file_abs_w_fbin(fid,filename,length,filesize);
  425. #endif
  426. }
  427. void
  428. FC_FUNC_(open_file_abs_r,OPEN_FILE_ABS_R)(int *fid, char *filename,int *length, long long *filesize) {
  429. #ifdef USE_MAP_FUNCTION
  430. open_file_abs_r_map(fid,filename,length,filesize);
  431. #else
  432. open_file_abs_r_fbin(fid,filename,length,filesize);
  433. #endif
  434. }
  435. void
  436. FC_FUNC_(close_file_abs,CLOSE_FILES_ABS)(int *fid) {
  437. #ifdef USE_MAP_FUNCTION
  438. close_file_abs_map(fid);
  439. #else
  440. close_file_abs_fbin(fid);
  441. #endif
  442. }
  443. void
  444. FC_FUNC_(write_abs,WRITE_ABS)(int *fid, char *buffer, int *length , int *index) {
  445. #ifdef USE_MAP_FUNCTION
  446. write_abs_map(fid,buffer,length,index);
  447. #else
  448. write_abs_fbin(fid,buffer,length,index);
  449. #endif
  450. }
  451. void
  452. FC_FUNC_(read_abs,READ_ABS)(int *fid, char *buffer, int *length , int *index) {
  453. #ifdef USE_MAP_FUNCTION
  454. read_abs_map(fid,buffer,length,index);
  455. #else
  456. read_abs_fbin(fid,buffer,length,index);
  457. #endif
  458. }