Bridge++  Ver. 1.2.x
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
fieldIO_LIME_MPIIO.cpp
Go to the documentation of this file.
1 
13 // static const char rcsid[] = "$Id: fieldIO_LIME_MPIIO.cpp 1147 2014-09-16 13:41:54Z matufuru $";
14 
15 // this code only makes sense in MPI environment.
16 #ifdef USE_MPI
17 
18 #include "fieldIO_LIME_MPIIO.h"
19 #include <list>
20 
21 using Bridge::vout;
22 
23 const std::string FieldIO_LIME_MPIIO::class_name = "FieldIO_LIME_MPIIO";
24 
25 //====================================================================
26 // private definitions
27 
28 namespace {
29 // ILDG metadata
30  const char ildg_metadata_template[] =
31  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
32  "<ildgFormat xmlns=\"http://www.lqcd.org/ildg\"\n"
33  " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
34  " xsi:schemaLocation=\"http://www.lqcd.org/ildg http://www.lqcd.org/ildg/filefmt.xsd\">\n"
35  " <version> 1.0 </version>\n"
36  " <field> su3gauge </field>\n"
37  " <precision> %zu </precision>\n"
38  " <lx> %d </lx> <ly> %d </ly> <lz> %d </lz> <lt> %d </lt>\n"
39  "</ildgFormat>";
40 
41 // LIME header format
42 
43 #define LIME_MAGIC ((uint32_t)0x456789ab)
44 #define MB_MASK ((uint16_t)0x8000)
45 #define ME_MASK ((uint16_t)0x4000)
46 
47  struct LIME_header
48  {
49  uint32_t magic;
50  uint16_t version;
51  uint16_t bitfield;
52  uint64_t length;
53  char type[128];
54  };
55 
56 // local header info
57  struct LIME_record_info
58  {
59  uint64_t offset;
60  uint64_t length;
61  char type[128];
62  };
63 
64  typedef std::list<LIME_record_info> LIME_message_info;
65  typedef std::list<LIME_message_info> LIME_file_info;
66 
67  int traverse(MPI_File& fh, LIME_file_info& file_info);
68  int read_lime_header(MPI_File& fh, LIME_header& header);
69  int read_lime_content(MPI_File& fh, const MPI_Offset offset, char *buf, const size_t length);
70  int find_record_offset(const LIME_file_info& file_info, const char *type, MPI_Offset& pos);
71 
72  int report_file_info(const LIME_file_info& file_info);
73 
74  size_t write_lime_header(MPI_File& fh, const char *type, const size_t length, const uint16_t flag);
75  size_t write_lime_record(MPI_File& fh, const char *type, const char *content, const size_t length, const uint16_t flag);
76 
78 }
79 
80 //====================================================================
81 void FieldIO_LIME_MPIIO::read_file(Field *u, string filename)
82 {
83  static const char _function_name[] = "FieldIO_LIME_MPIIO::read_file";
84 
85  initialize();
86 
87  MPI_File fh;
88  int ret;
89 
90  int nin_file = m_format->nin();
91  int nex_file = m_format->nex();
92 
93 // Field::element_type *buf = new Field::element_type [m_nvol*m_nvector];
94  double *buf = new double [nin_file * nex_file * m_nvol];
95  if (!buf) {
96  vout.crucial(m_vl, "%s: allocate buffer failed.\n", _function_name);
97  abort();
98  }
99 
100 #ifdef USE_BGNET
101  ret = MPI_File_open(MPI_COMM_WORLD, const_cast<char *>(filename.c_str()), MPI_MODE_RDONLY, MPI_INFO_NULL, &fh);
102 #else
103  ret = MPI_File_open(Communicator_impl::world(), const_cast<char *>(filename.c_str()), MPI_MODE_RDONLY, MPI_INFO_NULL, &fh);
104 #endif
105  if (ret) {
106  vout.crucial(m_vl, "%s: MPI_File_open failed.\n", _function_name);
107  abort();
108  }
109 
110  MPI_Offset pos = 0;
111 
112  // process records
113  if (Communicator::is_primary()) {
114  LIME_file_info file_info;
115 
116  traverse(fh, file_info);
117 
118  report_file_info(file_info);
119 
120  if (!find_record_offset(file_info, "ildg-binary-data", pos)) {
121  vout.crucial(m_vl, "binary data record not found.\n");
122  abort();
123  }
124  }
125 
126  // It would be better to use MPI communicator here (even when BGNET is available),
127  // since the mixture of MPI/BGNET is buggy in BG/Q
128 #ifdef USE_BGNET
129  MPI_Bcast(&pos, sizeof(off_t), MPI_BYTE, 0, MPI_COMM_WORLD);
130 #else
131  Communicator::Base::broadcast(sizeof(off_t), &pos, 0);
132 #endif
133 
134  ret = MPI_File_set_view(fh, pos, m_type_vector, m_type_tiled, const_cast<char *>("native"), MPI_INFO_NULL);
135  if (ret) {
136  vout.crucial(m_vl, "%s: MPI_File_set_view failed.\n", _function_name);
137  abort();
138  }
139 
140  ret = MPI_File_read_all(fh, (void *)buf, m_nvol * nex_file, m_type_vector, MPI_STATUS_IGNORE);
141  if (ret) {
142  vout.crucial(m_vl, "%s: MPI_File_read_all failed.\n", _function_name);
143  abort();
144  }
145 
146  ret = MPI_File_close(&fh);
147  if (ret) {
148  vout.crucial(m_vl, "%s: MPI_File_close failed.\n", _function_name);
149  abort();
150  }
151 
152  if (!is_bigendian()) {
153 // convert_endian(buf, sizeof(Field::element_type), m_nvol*m_nvector);
154  convert_endian(buf, sizeof(double), m_nvol * nin_file * nex_file);
155  }
156 
157  // unpack buffer
158  double *p = buf;
159 
160  for (int j = 0; j < nex_file; ++j) {
161  for (int isite = 0; isite < m_nvol; ++isite) {
162  for (int i = 0; i < nin_file; ++i) {
163  int s, t;
164  m_format->file_to_field(s, t, i, j);
165 
166  u->set(s, isite, t, *p++);
167  }
168  }
169  }
170 
171  delete [] buf;
172 
173  finalize();
174 }
175 
176 
177 //====================================================================
178 void FieldIO_LIME_MPIIO::write_file(Field *u, string filename)
179 {
180  static const char _function_name[] = "FieldIO_LIME_MPIIO::write_file";
181 
182  initialize();
183 
184  int nin_file = m_format->nin();
185  int nex_file = m_format->nex();
186 
187  // Field::element_type *buf = new Field::element_type [m_nvol*m_nvector];
188  double *buf = new double [nin_file * nex_file * m_nvol];
189  if (!buf) {
190  vout.crucial(m_vl, "%s: allocate buffer failed.\n", _function_name);
191  abort();
192  }
193 
194  size_t data_length = sizeof(double) * nin_file * nex_file * CommonParameters::Lvol();
195 
196  // pack buffer
197  double *p = buf;
198 
199  for (int j = 0; j < nex_file; ++j) {
200  for (int isite = 0; isite < m_nvol; ++isite) {
201  for (int i = 0; i < nin_file; ++i) {
202  int s, t;
203  m_format->file_to_field(s, t, i, j);
204 
205  *p++ = u->cmp(s, isite, t);
206  }
207  }
208  }
209 
210  if (!is_bigendian()) {
211  // convert_endian(buf, sizeof(Field::element_type), m_nvol*m_nvector);
212  convert_endian(buf, sizeof(double), nin_file * nex_file * m_nvol);
213  }
214 
215  MPI_File fh;
216  int ret;
217 
218 #ifdef USE_BGNET
219  ret = MPI_File_open(MPI_COMM_WORLD, const_cast<char *>(filename.c_str()), MPI_MODE_CREATE | MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);
220 #else
221  ret = MPI_File_open(Communicator_impl::world(), const_cast<char *>(filename.c_str()), MPI_MODE_CREATE | MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);
222 #endif
223  if (ret) {
224  vout.crucial(m_vl, "%s: MPI_File_open failed.\n", _function_name);
225  abort();
226  }
227 
228  MPI_Offset pos = 0;
229 
230  if (Communicator::is_primary()) {
231  // metadata
232  char metadata[2048];
233  sprintf(metadata, ildg_metadata_template,
234  sizeof(double) * 8, /* bit width */
239 
240  pos += write_lime_record(fh, "ildg-format", metadata, strlen(metadata), MB_MASK);
241 
242  // content: write header
243  pos += write_lime_header(fh, "ildg-binary-data", data_length, ME_MASK);
244  }
245 
246  // It would be better to use MPI communicator here (even when BGNET is available),
247  // since the mixture of MPI/BGNET is buggy in BG/Q
248 #ifdef USE_BGNET
249  MPI_Bcast(&pos, sizeof(off_t), MPI_BYTE, 0, MPI_COMM_WORLD);
250 #else
251  Communicator::Base::broadcast(sizeof(off_t), &pos, 0);
252 #endif
253 
254  // content: write data
255 
256  ret = MPI_File_set_view(fh, pos, m_type_vector, m_type_tiled, const_cast<char *>("native"), MPI_INFO_NULL);
257  if (ret) {
258  vout.crucial(m_vl, "%s: MPI_File_set_view failed.\n", _function_name);
259  abort();
260  }
261 
262  ret = MPI_File_write_all(fh, (void *)buf, m_nvol * nex_file, m_type_vector, MPI_STATUS_IGNORE);
263  if (ret) {
264  vout.crucial(m_vl, "%s: MPI_File_write_all failed.\n", _function_name);
265  abort();
266  }
267 
268  // content: padding if needed
269  if (data_length % 8 > 0) {
270  size_t padding_size = (8 - data_length % 8) % 8;
271 
272  const char blank[8] = "";
273  ret = MPI_File_write_at(fh, pos + data_length, const_cast<char *>(blank), padding_size, MPI_BYTE, MPI_STATUS_IGNORE);
274  if (ret) {
275  vout.crucial(vl, "%s: write padding failed.\n", _function_name);
276  abort();
277  }
278 
279  vout.general(m_vl, "%s: padding %lu bytes added.\n", _function_name, padding_size);
280  }
281 
282  ret = MPI_File_close(&fh);
283  if (ret) {
284  vout.crucial(m_vl, "%s: MPI_File_close failed.\n", _function_name);
285  abort();
286  }
287 
288  delete [] buf;
289 
290  finalize();
291 }
292 
293 
294 //====================================================================
295 int FieldIO_LIME_MPIIO::initialize()
296 {
297  static const char _function_name[] = "FieldIO_LIME_MPIIO::initialize";
298 
299  // store verbose level to private parameter.
300  vl = m_vl;
301 
302  if (m_is_initialized) return EXIT_SUCCESS;
303 
304  int nin_file = m_format->nin();
305  int nex_file = m_format->nex();
306 
307  const int ndim = CommonParameters::Ndim();
308 
309  int *global_dims = new int[ndim];
310  global_dims[0] = CommonParameters::Lx();
311  global_dims[1] = CommonParameters::Ly();
312  global_dims[2] = CommonParameters::Lz();
313  global_dims[3] = CommonParameters::Lt();
314 
315  int *local_dims = new int[ndim];
316  local_dims[0] = CommonParameters::Nx();
317  local_dims[1] = CommonParameters::Ny();
318  local_dims[2] = CommonParameters::Nz();
319  local_dims[3] = CommonParameters::Nt();
320 
321  m_nvol = 1;
322  for (int i = 0; i < ndim; ++i) {
323  m_nvol *= local_dims[i];
324  }
325 
326  int *grid_pos = new int[ndim];
327  for (int i = 0; i < ndim; ++i) {
328  grid_pos[i] = Communicator::ipe(i);
329  }
330 
331  int *starts = new int[ndim];
332  for (int i = 0; i < ndim; ++i) {
333  starts[i] = local_dims[i] * grid_pos[i];
334  }
335 
336  int ret = 0;
337 
338 // MPI_Datatype m_type_vector;
339 // ret = MPI_Type_contiguous(sizeof(Field::element_type)*nin_file, MPI_BYTE, &m_type_vector);
340  ret = MPI_Type_contiguous(sizeof(double) * nin_file, MPI_BYTE, &m_type_vector);
341  if (ret) {
342  vout.general(m_vl, "%s: MPI_Type_Contiguous failed.\n", _function_name);
343  return EXIT_FAILURE;
344  }
345 
346  ret = MPI_Type_commit(&m_type_vector);
347  if (ret) {
348  vout.general(m_vl, "%s: MPI_Type_commit failed.\n", _function_name);
349  return EXIT_FAILURE;
350  }
351 
352 // MPI_Datatype m_type_tiled;
353  ret = MPI_Type_create_subarray(ndim, global_dims, local_dims, starts, MPI_ORDER_FORTRAN, m_type_vector, &m_type_tiled);
354  if (ret) {
355  vout.general(m_vl, "%s: MPI_Type_create_subarray failed.\n", _function_name);
356  return EXIT_FAILURE;
357  }
358 
359  ret = MPI_Type_commit(&m_type_tiled);
360  if (ret) {
361  vout.general(m_vl, "%s: MPI_Type_commit failed.\n", _function_name);
362  return EXIT_FAILURE;
363  }
364 
365  m_is_initialized = true;
366 
367  delete [] starts;
368  delete [] grid_pos;
369  delete [] local_dims;
370  delete [] global_dims;
371 
372  vout.detailed(m_vl, "FieldIO_LIME_MPIIO via MPI I/O initialize done.\n");
373 
374  return EXIT_SUCCESS;
375 }
376 
377 
378 //====================================================================
379 int FieldIO_LIME_MPIIO::finalize()
380 {
381  static const char _function_name[] = "FieldIO_LIME_MPIIO::finalize";
382 
383  if (!m_is_initialized) return EXIT_SUCCESS;
384 
385  int ret;
386 
387  ret = MPI_Type_free(&m_type_tiled);
388  if (ret) {
389  vout.general(m_vl, "%s: MPI_Type_free failed.\n", _function_name);
390  return EXIT_FAILURE;
391  }
392 
393  ret = MPI_Type_free(&m_type_vector);
394  if (ret) {
395  vout.general(m_vl, "%s: MPI_Type_free failed.\n", _function_name);
396  return EXIT_FAILURE;
397  }
398 
399  m_is_initialized = false;
400 
401  vout.detailed(m_vl, "%s via MPI I/O finalize done.\n", class_name.c_str());
402 
403  return EXIT_SUCCESS;
404 }
405 
406 
407 //====================================================================
408 namespace {
409 //--------------------------------------------------------------------
410  int read_lime_header(MPI_File& fh, LIME_header& header)
411  {
412  MPI_Status status;
413 
414  int ret = MPI_File_read(fh, (void *)&header, sizeof(LIME_header), MPI_BYTE, &status);
415 
416  int count;
417 
418  MPI_Get_count(&status, MPI_BYTE, &count);
419  if (count != sizeof(LIME_header)) { // data length short. end of file.
420  return 1;
421  }
422 
423  if (ret) {
424  vout.crucial(vl, "%s: io error.\n", __func__);
425  return -1;
426  }
427 
428  if (FieldIO::is_bigendian() == false) {
429  FieldIO::convert_endian(&header.magic, 4, 1);
430  FieldIO::convert_endian(&header.version, 2, 1);
431  FieldIO::convert_endian(&header.bitfield, 2, 1);
432  FieldIO::convert_endian(&header.length, 8, 1);
433  }
434 
435  if (header.magic != LIME_MAGIC) {
436  vout.crucial(vl, "not lime header.\n");
437  return -1;
438  }
439 
440  return 0;
441  }
442 
443 
444 //====================================================================
445  int traverse(MPI_File& fh, LIME_file_info& file_info)
446  {
447  // go to the beginning of the file
448  MPI_File_seek(fh, 0, MPI_SEEK_SET);
449 
450  MPI_Offset pos = 0;
451 
452  LIME_message_info message_info;
453 
454  while (true)
455  {
456  LIME_header header;
457  int stat = read_lime_header(fh, header);
458 
459 // if (stat == -1) { // bad input
460 // return -1;
461 // } else if (stat == 1) { // end of file
462 // break;
463 // } else if (stat != 0) {
464 // // unknown status.
465 // return -1;
466 // }
467 
468 // vout.detailed(vl, "read_lime_header: stat = %d, pos = %lu\n", stat, pos);
469 
470  if (stat != 0) {
471  break;
472  }
473 
474  // read ok
475  pos += sizeof(LIME_header);
476 
477  LIME_record_info record_info;
478 
479  memcpy((void *)&record_info, (void *)&header, sizeof(LIME_record_info));
480  record_info.offset = pos;
481 
482  // padding (0-7)
483  size_t padding_size = (8 - header.length % 8) % 8;
484 
485  // seek to next record
486  MPI_File_seek(fh, header.length + padding_size, MPI_SEEK_CUR);
487  pos += header.length + padding_size;
488 
489 
490  // store record info
491  if ((header.bitfield & MB_MASK) == MB_MASK) {
492  message_info.clear();
493  }
494 
495  message_info.push_back(record_info);
496 
497  if ((header.bitfield & ME_MASK) == ME_MASK) {
498  file_info.push_back(message_info);
499 // message_info.clear();
500  }
501  }
502 
503  return 0;
504  }
505 
506 
507 //====================================================================
508  int find_record_offset(const LIME_file_info& file_info, const char *type, MPI_Offset& pos)
509  {
510  bool is_found = false;
511 
512  for (LIME_file_info::const_iterator p = file_info.begin(); p != file_info.end(); ++p) {
513  for (LIME_message_info::const_iterator q = p->begin(); q != p->end(); ++q) {
514  if (strncmp(q->type, type, strlen(type)) == 0) {
515  is_found = true;
516  pos = q->offset;
517  break;
518  }
519  }
520  }
521 
522  return is_found ? 1 : 0;
523  }
524 
525 
526 //====================================================================
527  int read_record_content(MPI_File& fh, const LIME_file_info& file_info, const char *type, std::string& content)
528  {
529  bool is_found = false;
530  LIME_record_info info;
531 
532  for (LIME_file_info::const_iterator p = file_info.begin(); p != file_info.end(); ++p) {
533  for (LIME_message_info::const_iterator q = p->begin(); q != p->end(); ++q) {
534  if (strncmp(q->type, type, strlen(type)) == 0) {
535  is_found = true;
536  info = *q;
537  break;
538  }
539  }
540  }
541 
542  if (!is_found) {
543  return 0;
544  }
545 
546  MPI_Status status;
547  char *buf = new char [info.length + 1];
548  MPI_File_read_at(fh, info.offset, buf, info.length, MPI_BYTE, &status);
549 
550  int count;
551  MPI_Get_count(&status, MPI_BYTE, &count);
552 
553  if (count != info.length) {
554  vout.crucial(vl, "%s: read error. content length mismatch.\n", __func__);
555  abort();
556  }
557 
558  content = std::string(buf);
559 
560  return 1;
561  }
562 
563 
564 //====================================================================
565  int report_file_info(const LIME_file_info& file_info)
566  {
567  Bridge::VerboseLevel vlo = vl;
568 
570 
571  for (LIME_file_info::const_iterator p = file_info.begin(); p != file_info.end(); ++p) {
572  vout.detailed(vl, "Message:\n");
573 
574  for (LIME_message_info::const_iterator q = p->begin(); q != p->end(); ++q) {
575  vout.detailed(vl, "\tRecord:\n");
576  vout.detailed(vl, "\t\toffset = %lu\n", q->offset);
577  vout.detailed(vl, "\t\tsize = %lu\n", q->length);
578  vout.detailed(vl, "\t\ttype = %s\n", q->type);
579  }
580  }
581 
582  vl = vlo;
583 
584  return 0;
585  }
586 
587 
588 //====================================================================
589  size_t write_lime_header(MPI_File& fh, const char *type, const size_t length, const uint16_t flag)
590  {
591  LIME_header header;
592 
593  memset(&header, 0, sizeof(LIME_header));
594 
595  header.magic = LIME_MAGIC;
596  header.version = (uint16_t)1;
597  header.bitfield = flag;
598  strncpy(header.type, type, 128);
599  header.length = length;
600 
601  if (FieldIO::is_bigendian() == false) {
602  FieldIO::convert_endian(&header.magic, 4, 1);
603  FieldIO::convert_endian(&header.version, 2, 1);
604  FieldIO::convert_endian(&header.bitfield, 2, 1);
605  FieldIO::convert_endian(&header.length, 8, 1);
606  }
607 
608  MPI_Status status;
609  int ret = MPI_File_write(fh, (void *)&header, sizeof(LIME_header), MPI_BYTE, &status);
610 
611  if (ret) {
612  vout.crucial(vl, "%s: write header failed.\n", __func__);
613  return 0;
614  }
615 
616  return sizeof(LIME_header); // length written.
617  }
618 
619 
620 //====================================================================
621  size_t write_lime_record(MPI_File& fh, const char *type, const char *content, const size_t length, const uint16_t flag)
622  {
623  const char blank[8] = "";
624 
625  if (write_lime_header(fh, type, length, flag) == 0) {
626  return 0;
627  }
628 
629  size_t padding_size = (8 - length % 8) % 8;
630 
631  MPI_Status status;
632  int ret = MPI_File_write(fh, const_cast<char *>(content), length, MPI_BYTE, &status);
633  if (ret) {
634  vout.crucial(vl, "%s: write content failed.\n", __func__);
635  return 0;
636  }
637 
638  if (padding_size > 0) {
639  ret = MPI_File_write(fh, const_cast<char *>(blank), padding_size, MPI_BYTE, &status);
640  if (ret) {
641  vout.crucial(vl, "%s: write padding failed.\n", __func__);
642  return 0;
643  }
644  }
645 
646  return sizeof(LIME_header) + length + padding_size;
647  }
648 
649 
650 //--------------------------------------------------------------------
651 } // unnamed namespace
652 //====================================================================
653 #endif /* USE_MPI */
BridgeIO vout
Definition: bridgeIO.cpp:207
static const std::string class_name
Definition: fieldIO.h:51
void detailed(const char *format,...)
Definition: bridgeIO.cpp:50
void set(const int jin, const int site, const int jex, double v)
Definition: field.h:128
void general(const char *format,...)
Definition: bridgeIO.cpp:38
virtual void file_to_field(int &s, int &t, const int i, const int j) const =0
virtual int nex() const =0
Container of Field-type object.
Definition: field.h:37
virtual int nin() const =0
double cmp(const int jin, const int site, const int jex) const
Definition: field.h:108
void read_file(Field *v, std::string filename)
read data from file.
static int broadcast(size_t size, void *data, int sender)
static int ipe(const int dir)
logical coordinate of current proc.
static int Lvol()
static bool is_bigendian()
Definition: fieldIO.cpp:202
void write_file(Field *v, std::string filename)
write data to file.
const IO_Format::Format * m_format
Definition: fieldIO.h:57
void crucial(const char *format,...)
Definition: bridgeIO.cpp:26
Bridge::VerboseLevel vl
Definition: checker.cpp:18
VerboseLevel
Definition: bridgeIO.h:25
static void convert_endian(void *buf, size_t size, size_t nmemb)
check if machine byte order is big-endian.
Definition: fieldIO.cpp:224
static bool is_primary()
check if the present node is primary in small communicator.
Bridge::VerboseLevel m_vl
Definition: fieldIO.h:59