QDP++
qdp_parscalar_specific.cc
Go to the documentation of this file.
1
6
7
8#include "qdp.h"
9#include "qdp_util.h"
10#include "qmp.h"
11
12
13namespace QDP {
14
15//-----------------------------------------------------------------------------
16// IO routine solely for debugging. Only defined here
17 template<class T>
18 std::ostream& operator<<(std::ostream& s, const multi1d<T>& s1)
19 {
20 for(int i=0; i < s1.size(); ++i)
21 s << " " << s1[i];
22
23 return s;
24 }
25
26
27//-----------------------------------------------------------------------------
29 void Map::make(const MapFunc& func)
30 {
31#if QDP_DEBUG >= 3
32 QDP_info("Map::make");
33#endif
34 const int nodeSites = Layout::sitesOnNode();
35
36 //--------------------------------------
37 // Setup the communication index arrays
38 goffsets.resize(nodeSites);
39 srcnode.resize(nodeSites);
40 dstnode.resize(nodeSites);
41
42 const int my_node = Layout::nodeNumber();
43
44 // Loop over the sites on this node
45 /* This for loop added by Jacques. Should be OK.
46 Loop works out forward and backward neighbours and writes
47 one value per value of linear. So no write conflicts */
48
49#pragma omp parallel for
50 for(int linear=0; linear < nodeSites; ++linear)
51 {
52 // Get the true lattice coord of this linear site index
53 multi1d<int> coord = Layout::siteCoords(my_node, linear);
54
55 // Source neighbor for this destination site
56 multi1d<int> fcoord = func(coord,+1);
57
58 // Destination neighbor receiving data from this site
59 // This functions as the inverse map
60 multi1d<int> bcoord = func(coord,-1);
61
62 int fnode = Layout::nodeNumber(fcoord);
63 int bnode = Layout::nodeNumber(bcoord);
64
65 // Source linear site and node
66 goffsets[linear] = Layout::linearSiteIndex(fcoord);
67 srcnode[linear] = fnode;
68
69 // Destination node
70 dstnode[linear] = bnode;
71
72#if QDP_DEBUG >= 3
73 QDP_info("linear=%d coord=%d %d %d %d fcoord=%d %d %d %d bcoord=%d %d %d %d goffsets=%d",
74 linear,
75 coord[0], coord[1], coord[2], coord[3],
76 fcoord[0], fcoord[1], fcoord[2], fcoord[3],
77 bcoord[0], bcoord[1], bcoord[2], bcoord[3],
78 goffsets[linear]);
79#endif
80 } // end for-loop
81
82 // Return a list of the unique nodes in the list
83 // NOTE: my_node may be included as a unique node, so one extra
84 multi1d<int> srcenodes_tmp = uniquify_list(srcnode);
85 multi1d<int> destnodes_tmp = uniquify_list(dstnode);
86
87 // To simplify life, remove a possible occurance of my_node
88 // This may mean that the list could be empty afterwards, so that
89 // means mark offnodeP as false
90 int cnt_srcenodes = 0;
91 for(int i=0; i < srcenodes_tmp.size(); ++i)
92 if (srcenodes_tmp[i] != my_node)
93 ++cnt_srcenodes;
94
95 int cnt_destnodes = 0;
96 for(int i=0; i < destnodes_tmp.size(); ++i)
97 if (destnodes_tmp[i] != my_node)
98 ++cnt_destnodes;
99
100#if QDP_DEBUG >= 3
101 // Debugging
102 for(int i=0; i < srcenodes_tmp.size(); ++i)
103 QDP_info("srcenodes_tmp(%d) = %d",i,srcenodes_tmp[i]);
104
105 for(int i=0; i < destnodes_tmp.size(); ++i)
106 QDP_info("destnodes_tmp(%d) = %d",i,destnodes_tmp[i]);
107
108 QDP_info("cnt_srcenodes = %d", cnt_srcenodes);
109 QDP_info("cnt_destnodes = %d", cnt_destnodes);
110#endif
111
112 // A sanity check - both counts must be either 0 or non-zero
113 if (cnt_srcenodes > 0 && cnt_destnodes == 0)
114 QDP_error_exit("Map: some bizarre error - no dest nodes but have srce nodes");
115
116 if (cnt_srcenodes == 0 && cnt_destnodes > 0)
117 QDP_error_exit("Map: some bizarre error - no srce nodes but have dest nodes");
118
119 // If no srce/dest nodes, then we know no off-node communications
120 offnodeP = (cnt_srcenodes > 0) ? true : false;
121
122 //
123 // The rest of the routine is devoted to supporting off-node communications
124 // If there is not any communications, then return
125 //
126 if (! offnodeP)
127 {
128#if QDP_DEBUG >= 3
129 QDP_info("no off-node communications: exiting Map::make");
130#endif
131 return;
132 }
133
134 // Finally setup the srce and dest nodes now without my_node
135 srcenodes.resize(cnt_srcenodes);
136 destnodes.resize(cnt_destnodes);
137
138 for(int i=0, j=0; i < srcenodes_tmp.size(); ++i)
139 if (srcenodes_tmp[i] != my_node)
140 srcenodes[j++] = srcenodes_tmp[i];
141
142 for(int i=0, j=0; i < destnodes_tmp.size(); ++i)
143 if (destnodes_tmp[i] != my_node)
144 destnodes[j++] = destnodes_tmp[i];
145
146#if QDP_DEBUG >= 3
147 // Debugging
148 for(int i=0; i < srcenodes.size(); ++i)
149 QDP_info("srcenodes(%d) = %d",i,srcenodes(i));
150
151 for(int i=0; i < destnodes.size(); ++i)
152 QDP_info("destnodes(%d) = %d",i,destnodes(i));
153#endif
154
155 // Run through the lists and find the number of each unique node
156 srcenodes_num.resize(srcenodes.size());
157 destnodes_num.resize(destnodes.size());
158
159 srcenodes_num = 0;
160 destnodes_num = 0;
161
162 // fast so no threading necessary
163 for(int linear=0; linear < nodeSites; ++linear)
164 {
165 int this_node = srcnode[linear];
166 if (this_node != my_node)
167 for(int i=0; i < srcenodes_num.size(); ++i)
168 {
169 if (srcenodes[i] == this_node)
170 {
171 srcenodes_num[i]++;
172 break;
173 }
174 }
175
176 int that_node = dstnode[linear];
177 if (that_node != my_node)
178 for(int i=0; i < destnodes_num.size(); ++i)
179 {
180 if (destnodes[i] == that_node)
181 {
182 destnodes_num[i]++;
183 break;
184 }
185 }
186 } // end for linear
187
188
189#if QDP_DEBUG >= 3
190 for(int i=0; i < destnodes.size(); ++i)
191 {
192 QDP_info("srcenodes(%d) = %d",i,srcenodes(i));
193 QDP_info("destnodes(%d) = %d",i,destnodes(i));
194 }
195
196 for(int i=0; i < destnodes_num.size(); ++i)
197 {
198 QDP_info("srcenodes_num(%d) = %d",i,srcenodes_num(i));
199 QDP_info("destnodes_num(%d) = %d",i,destnodes_num(i));
200 }
201#endif
202
203 // Implementation limitation in the Map::operator(). Only support
204 // a node sending data all to one node or no sending at all (offNodeP == false).
205 if (srcenodes.size() != 1)
206 QDP_error_exit("Map: for now only allow 1 destination node");
207
208 if (destnodes.size() != 1)
209 QDP_error_exit("Map: for now only allow receives from 1 node");
210
211
212 // Now make a small scatter array for the dest_buf so that when data
213 // is sent, it is put in an order the gather can pick it up
214 // If we allow multiple dest nodes, then soffsets here needs to be
215 // an array of arrays
216 soffsets.resize(destnodes_num[0]);
217
218 // Loop through sites on my *destination* node - here I assume all nodes have
219 // the same number of sites. Mimic the gather pattern needed on that node and
220 // set my scatter array to scatter into the correct site order
221 for(int i=0, si=0; i < nodeSites; ++i)
222 {
223 // Get the true lattice coord of this linear site index
224 multi1d<int> coord = Layout::siteCoords(destnodes[0], i);
225 multi1d<int> fcoord = func(coord,+1);
226 int fnode = Layout::nodeNumber(fcoord);
227 int fline = Layout::linearSiteIndex(fcoord);
228
229 if (fnode == my_node)
230 soffsets[si++] = fline;
231 }
232
233#if QDP_DEBUG >= 3
234 // Debugging
235 for(int i=0; i < soffsets.size(); ++i)
236 QDP_info("soffsets(%d) = %d",i,soffsets(i));
237#endif
238
239
240#if QDP_DEBUG >= 3
241 QDP_info("exiting Map::make");
242#endif
243 }
244
245
246//------------------------------------------------------------------------
247// Message passing convenience routines
248//------------------------------------------------------------------------
249
250 namespace QDPInternal
251 {
253 void broadcast_str(std::string& result)
254 {
255 char *dd_tmp;
256 int lleng;
257
258 // Only primary node can grab string
259 if (Layout::primaryNode())
260 {
261 lleng = result.length();
262 }
263
264 // First must broadcast size of string
266
267 // Now every node can alloc space for string
268 dd_tmp = new(std::nothrow) char[lleng];
269 if( dd_tmp == 0x0 ) {
270 QDP_error_exit("Unable to allocate dd_tmp\n");
271 }
272
274 memcpy(dd_tmp, result.c_str(), lleng);
275
276 // Now broadcast char array out to all nodes
277 QDPInternal::broadcast((void *)dd_tmp, lleng);
278
279 // All nodes can now grab char array and make a string, but only
280 // need this on non-primary nodes
281 if (! Layout::primaryNode())
282 {
283 result.assign(dd_tmp, lleng);
284 }
285
286 // Clean-up and boogie
287 delete[] dd_tmp;
288 }
289
291 bool gridArch()
292 {
293 return (QMP_get_msg_passing_type() == QMP_GRID) ? true : false;
294 }
295
297 void clearToSend(void *buffer, int count, int node)
298 {
299 // On non-grid machines, use a clear-to-send like protocol
300 if (! QDPInternal::gridArch())
301 {
302 if(Layout::nodeNumber() == 0 && node != 0)
303 QDPInternal::sendToWait(buffer, node, count);
304 if(Layout::nodeNumber() == node && node != 0)
305 QDPInternal::recvFromWait(buffer, 0, count);
306 }
307 }
308
310 void route(void *buffer, int srce_node, int dest_node, int count)
311 {
312#if QDP_DEBUG >= 2
313 QDP_info("starting a route, count=%d, srcenode=%d destnode=%d",
314 count,srce_node,dest_node);
315#endif
316
317// QMP_route(buffer, count, srce_node, dest_node);
318 DML_route_bytes((char*)buffer, count, srce_node, dest_node);
319
320#if QDP_DEBUG >= 2
321 QDP_info("finished a route");
322#endif
323 }
324
326 void
327 sendToWait(void *send_buf, int dest_node, int count)
328 {
329#if QDP_DEBUG >= 2
330 QDP_info("starting a sendToWait, count=%d, destnode=%d", count,dest_node);
331#endif
332
333 QMP_msgmem_t request_msg = QMP_declare_msgmem(send_buf, count);
334 QMP_msghandle_t request_mh = QMP_declare_send_to(request_msg, dest_node, 0);
335
336 if (QMP_start(request_mh) != QMP_SUCCESS)
337 QDP_error_exit("sendToWait failed\n");
338
339 QMP_wait(request_mh);
340
341 QMP_free_msghandle(request_mh);
342 QMP_free_msgmem(request_msg);
343
344#if QDP_DEBUG >= 2
345 QDP_info("finished a sendToWait");
346#endif
347 }
348
350 void
351 recvFromWait(void *recv_buf, int srce_node, int count)
352 {
353#if QDP_DEBUG >= 2
354 QDP_info("starting a recvFromWait, count=%d, srcenode=%d", count, srce_node);
355#endif
356
357 QMP_msgmem_t request_msg = QMP_declare_msgmem(recv_buf, count);
358 QMP_msghandle_t request_mh = QMP_declare_receive_from(request_msg, srce_node, 0);
359
360 if (QMP_start(request_mh) != QMP_SUCCESS)
361 QDP_error_exit("recvFromWait failed\n");
362
363 QMP_wait(request_mh);
364
365 QMP_free_msghandle(request_mh);
366 QMP_free_msgmem(request_msg);
367
368#if QDP_DEBUG >= 2
369 QDP_info("finished a recvFromWait");
370#endif
371 }
372
373 };
374
375
376//-----------------------------------------------------------------------------
377// Write a lattice quantity
379 const char* output, size_t size, size_t nmemb)
380 {
381 const int xinc = Layout::subgridLattSize()[0];
382
383 size_t sizemem = size*nmemb;
384 size_t tot_size = sizemem*xinc;
385 char *recv_buf = new(std::nothrow) char[tot_size];
386 if( recv_buf == 0x0 ) {
387 QDP_error_exit("Unable to allocate recv_buf\n");
388 }
389
390 // Find the location of each site and send to primary node
391 int old_node = 0;
392
393 for(int site=0; site < Layout::vol(); site += xinc)
394 {
395 // first site in each segment uniquely identifies the node
396 int node = Layout::nodeNumber(crtesn(site, Layout::lattSize()));
397
398 // Send nodes must wait for a ready signal from the master node
399 // to prevent message pileups on the master node
400 if (node != old_node)
401 {
402 // On non-grid machines, use a clear-to-send like protocol
403 QDPInternal::clearToSend(recv_buf,sizeof(int),node);
404 old_node = node;
405 }
406
407 // Copy to buffer: be really careful since max(linear) could vary among nodes
408 if (Layout::nodeNumber() == node)
409 {
410 for(int i=0; i < xinc; ++i)
411 {
412 int linear = Layout::linearSiteIndex(crtesn(site+i, Layout::lattSize()));
413 memcpy(recv_buf+i*sizemem, output+linear*sizemem, sizemem);
414 }
415 }
416
417 // Send result to primary node. Avoid sending prim-node sending to itself
418 if (node != 0)
419 {
420#if 1
421 // All nodes participate
422 QDPInternal::route((void *)recv_buf, node, 0, tot_size);
423#else
425 QDPInternal::recvFromWait((void *)recv_buf, node, tot_size);
426
427 if (Layout::nodeNumber() == node)
428 QDPInternal::sendToWait((void *)recv_buf, 0, tot_size);
429#endif
430 }
431
432 bin.writeArrayPrimaryNode(recv_buf, size, nmemb*xinc);
433 }
434
435 delete[] recv_buf;
436 }
437
438
439// Write a single site of a lattice quantity
441 const char* output, size_t size, size_t nmemb,
442 const multi1d<int>& coord)
443 {
444 size_t tot_size = size*nmemb;
445 char *recv_buf = new(std::nothrow) char[tot_size];
446 if( recv_buf == 0x0 ) {
447 QDP_error_exit("Unable to allocate recvbuf\n");
448 }
449
450
451 // Send site to primary node
452 int node = Layout::nodeNumber(coord);
453 int linear = Layout::linearSiteIndex(coord);
454
455 // Send nodes must wait for a ready signal from the master node
456 // to prevent message pileups on the master node
457 QDPInternal::clearToSend(recv_buf,sizeof(int),node);
458
459 // Copy to buffer: be really careful since max(linear) could vary among nodes
460 if (Layout::nodeNumber() == node)
461 memcpy(recv_buf, output+linear*tot_size, tot_size);
462
463 // Send result to primary node. Avoid sending prim-node sending to itself
464 if (node != 0)
465 {
466#if 1
467 // All nodes participate
468 QDPInternal::route((void *)recv_buf, node, 0, tot_size);
469#else
471 QDPInternal::recvFromWait((void *)recv_buf, node, tot_size);
472
473 if (Layout::nodeNumber() == node)
474 QDPInternal::sendToWait((void *)recv_buf, 0, tot_size);
475#endif
476 }
477
478 bin.writeArray(recv_buf, size, nmemb);
479
480 delete[] recv_buf;
481 }
482
483
484//-----------------------------------------------------------------------------
485// Write a lattice quantity
487 const char* output, size_t size, size_t nmemb,
488 const Subset& sub)
489 {
490 // Single node code
491 const Set& set = sub.getSet();
492 const multi1d<int>& lat_color = set.latticeColoring();
493 const int color = sub.color();
494
495 const int xinc = Layout::subgridLattSize()[0];
496
497 size_t sizemem = size*nmemb;
498 size_t max_tot_size = sizemem*xinc;
499 char *recv_buf = new(std::nothrow) char[max_tot_size];
500 if( recv_buf == 0x0 ) {
501 QDP_error_exit("Unable to allocate recv_buf\n");
502 }
503
504 char *recv_buf_size = new(std::nothrow) char[sizeof(int)];
505 if( recv_buf_size == 0x0 ) {
506 QDP_error_exit("Unable to allocate recv_buf_size\n");
507 }
508
509 // Find the location of each site and send to primary node
510 int old_node = 0;
511
512 for(int site=0; site < Layout::vol(); site += xinc)
513 {
514 // This algorithm is cumbersome. We do not keep the coordinate function for the subset.
515 // So, we have to ask the sending node how many sites are to be transferred,
516 // and rely on each node to send whatever number of sites live in the desired
517 // subgridLattSize strip.
518
519 // first site in each segment uniquely identifies the node
520 int node = Layout::nodeNumber(crtesn(site, Layout::lattSize()));
521
522 // Send nodes must wait for a ready signal from the master node
523 // to prevent message pileups on the master node
524 if (node != old_node)
525 {
526 // On non-grid machines, use a clear-to-send like protocol
527 QDPInternal::clearToSend(recv_buf,sizeof(int),node);
528 old_node = node;
529 }
530
531 // Copy to buffer: be really careful since max(linear) could vary among nodes
532 int site_cnt = 0;
533 if (Layout::nodeNumber() == node)
534 {
535 for(int i=0; i < xinc; ++i)
536 {
537 int linear = Layout::linearSiteIndex(crtesn(site+i, Layout::lattSize()));
538 if (lat_color[linear] == color)
539 {
540 memcpy(recv_buf+site_cnt*sizemem, output+linear*sizemem, sizemem);
541 site_cnt++;
542 }
543 }
544 memcpy(recv_buf_size, (void *)&site_cnt, sizeof(int));
545 }
546
547 // Send result to primary node. Avoid sending prim-node sending to itself
548 if (node != 0)
549 {
550#if 0
551 // All nodes participate
552 // First send the byte size for this
553 QDP_error_exit("Do not support route in writeOLattice(sub)");
554
555#else
556 // We are using the point-to-point version
558 {
559 QDPInternal::recvFromWait((void *)recv_buf_size, node, sizeof(int));
560 memcpy((void *)&site_cnt, recv_buf_size, sizeof(int));
561 QDPInternal::recvFromWait((void *)recv_buf, node, site_cnt*sizemem);
562 }
563
564 if (Layout::nodeNumber() == node)
565 {
566 QDPInternal::sendToWait((void *)recv_buf_size, 0, sizeof(int));
567 QDPInternal::sendToWait((void *)recv_buf, 0, site_cnt*sizemem);
568 }
569#endif
570 }
571
572 bin.writeArrayPrimaryNode(recv_buf, size, nmemb*site_cnt);
573 }
574
575 delete[] recv_buf_size;
576 delete[] recv_buf;
577 }
578
579
580
582
584 char* input, size_t size, size_t nmemb)
585 {
586 const int xinc = Layout::subgridLattSize()[0];
587
588 size_t sizemem = size*nmemb;
589 size_t tot_size = sizemem*xinc;
590 char *recv_buf = new(std::nothrow) char[tot_size];
591 if( recv_buf == 0x0 ) {
592 QDP_error_exit("Unable to allocate recvbuf\n");
593 }
594
595 // Find the location of each site and send to primary node
596 for(int site=0; site < Layout::vol(); site += xinc)
597 {
598 // first site in each segment uniquely identifies the node
599 int node = Layout::nodeNumber(crtesn(site, Layout::lattSize()));
600
601 // Only on primary node read the data
602 bin.readArrayPrimaryNode(recv_buf, size, nmemb*xinc);
603
604 // Send result to destination node. Avoid sending prim-node sending to itself
605 if (node != 0)
606 {
607#if 1
608 // All nodes participate
609 QDPInternal::route((void *)recv_buf, 0, node, tot_size);
610#else
612 QDPInternal::sendToWait((void *)recv_buf, node, tot_size);
613
614 if (Layout::nodeNumber() == node)
615 QDPInternal::recvFromWait((void *)recv_buf, 0, tot_size);
616#endif
617 }
618
619 if (Layout::nodeNumber() == node)
620 {
621 for(int i=0; i < xinc; ++i)
622 {
623 int linear = Layout::linearSiteIndex(crtesn(site+i, Layout::lattSize()));
624
625 memcpy(input+linear*sizemem, recv_buf+i*sizemem, sizemem);
626 }
627 }
628 }
629
630 delete[] recv_buf;
631 }
632
634
636 char* input, size_t size, size_t nmemb,
637 const multi1d<int>& coord)
638 {
639 size_t tot_size = size*nmemb;
640 char *recv_buf = new(std::nothrow) char[tot_size];
641 if( recv_buf == 0x0 ) {
642 QDP_error_exit("Unable to allocate recv_buf\n");
643 }
644
645
646 // Find the location of each site and send to primary node
647 int node = Layout::nodeNumber(coord);
648 int linear = Layout::linearSiteIndex(coord);
649
650 // Only on primary node read the data
651 bin.readArrayPrimaryNode(recv_buf, size, nmemb);
652
653 // Send result to destination node. Avoid sending prim-node sending to itself
654 if (node != 0)
655 {
656#if 1
657 // All nodes participate
658 QDPInternal::route((void *)recv_buf, 0, node, tot_size);
659#else
661 QDPInternal::sendToWait((void *)recv_buf, node, tot_size);
662
663 if (Layout::nodeNumber() == node)
664 QDPInternal::recvFromWait((void *)recv_buf, 0, tot_size);
665#endif
666 }
667
668 if (Layout::nodeNumber() == node)
669 memcpy(input+linear*tot_size, recv_buf, tot_size);
670
671 delete[] recv_buf;
672 }
673
675
677 char* input, size_t size, size_t nmemb,
678 const Subset& sub)
679 {
680 // Single node code
681 const Set& set = sub.getSet();
682 const multi1d<int>& lat_color = set.latticeColoring();
683 const int color = sub.color();
684
685 const int xinc = Layout::subgridLattSize()[0];
686
687 size_t sizemem = size*nmemb;
688 size_t max_tot_size = sizemem*xinc;
689 char *recv_buf = new(std::nothrow) char[max_tot_size];
690 if( recv_buf == 0x0 ) {
691 QDP_error_exit("Unable to allocate recv_buf\n");
692 }
693
694 char *recv_buf_size = new(std::nothrow) char[sizeof(int)];
695 if( recv_buf_size == 0x0 ) {
696 QDP_error_exit("Unable to allocate recv_buf_size\n");
697 }
698
699 // Find the location of each site and send to primary node
700 for(int site=0; site < Layout::vol(); site += xinc)
701 {
702 // This algorithm is cumbersome. We do not keep the coordinate function for the subset.
703 // So, we have to ask the sending node how many sites are to be transferred,
704 // and rely on each node to send whatever number of sites live in the desired
705 // subgridLattSize strip.
706
707 // first site in each segment uniquely identifies the node
708 int node = Layout::nodeNumber(crtesn(site, Layout::lattSize()));
709
710 // Find the amount of data to read. Unfortunately, have to ask the remote node
711 // Place the result in a send buffer
712 int site_cnt = 0;
713 if (Layout::nodeNumber() == node)
714 {
715 for(int i=0; i < xinc; ++i)
716 {
717 int linear = Layout::linearSiteIndex(crtesn(site+i, Layout::lattSize()));
718 if (lat_color[linear] == color)
719 {
720 site_cnt++;
721 }
722 }
723 memcpy(recv_buf_size, (void *)&site_cnt, sizeof(int));
724 }
725
726 if (node != 0)
727 {
728 // Send the data size to the primary node.
729 // We are using the point-to-point version
731 {
732 QDPInternal::recvFromWait((void *)recv_buf_size, node, sizeof(int));
733 memcpy((void *)&site_cnt, recv_buf_size, sizeof(int));
734 }
735
736 if (Layout::nodeNumber() == node)
737 {
738 QDPInternal::sendToWait((void *)recv_buf_size, 0, sizeof(int));
739 }
740 }
741
742 // Only on primary node read the data
743 bin.readArrayPrimaryNode(recv_buf, size, nmemb*site_cnt);
744
745 // Send result to destination node. Avoid sending prim-node sending to itself
746 if (node != 0)
747 {
748#if 0
749 // All nodes participate
750 // First send the byte size for this
751 QDP_error_exit("Do not support route in readOLattice(sub)");
752
753#else
754 // We are using the point-to-point version
756 QDPInternal::sendToWait((void *)recv_buf, node, site_cnt*sizemem);
757
758 if (Layout::nodeNumber() == node)
759 QDPInternal::recvFromWait((void *)recv_buf, 0, site_cnt*sizemem);
760#endif
761 }
762
763 if (Layout::nodeNumber() == node)
764 {
765 for(int i=0,j=0; i < xinc; ++i)
766 {
767 int linear = Layout::linearSiteIndex(crtesn(site+i, Layout::lattSize()));
768 if (lat_color[linear] == color)
769 {
770 memcpy(input+linear*sizemem, recv_buf+j*sizemem, sizemem);
771 j++;
772 }
773 }
774 }
775 }
776
777 delete[] recv_buf_size;
778 delete[] recv_buf;
779 }
780
781
782 // **************************************************************
784 {
785 void readOLatticeSlice(BinaryReader& bin, char* input,
786 size_t size, size_t nmemb,
787 int start_lexico, int stop_lexico)
788 {
789 const int xinc = Layout::subgridLattSize()[0];
790
791 if ((stop_lexico % xinc) != 0)
792 {
793 QDPIO::cerr << __func__ << ": erorr: stop_lexico= " << stop_lexico << " xinc= " << xinc << std::endl;
794 QDP_abort(1);
795 }
796
797 size_t sizemem = size*nmemb;
798 size_t tot_size = sizemem*xinc;
799 char *recv_buf = new(std::nothrow) char[tot_size];
800 if( recv_buf == 0x0 ) {
801 QDP_error_exit("Unable to allocate recvbuf\n");}
802
803 // Find the location of each site and send to primary node
804 for (int site=start_lexico; site < stop_lexico; site += xinc)
805 {
806 // first site in each segment uniquely identifies the node
807 int node = Layout::nodeNumber(crtesn(site, Layout::lattSize()));
808
809 // Only on primary node read the data
810 bin.readArrayPrimaryNode(recv_buf, size, nmemb*xinc);
811
812 // Send result to destination node. Avoid sending prim-node sending to itself
813 if (node != 0)
814 {
815#if 1
816 // All nodes participate
817 QDPInternal::route((void *)recv_buf, 0, node, tot_size);
818#else
820 QDPInternal::sendToWait((void *)recv_buf, node, tot_size);
821 if (Layout::nodeNumber() == node)
822 QDPInternal::recvFromWait((void *)recv_buf, 0, tot_size);
823#endif
824 }
825
826 if (Layout::nodeNumber() == node)
827 {
828 for(int i=0; i < xinc; ++i)
829 {
830 int linear = Layout::linearSiteIndex(crtesn(site+i, Layout::lattSize()));
831 memcpy(input+linear*sizemem, recv_buf+i*sizemem, sizemem);
832 }
833 }
834 }
835
836 delete[] recv_buf;
837 }
838
839
840 // Write a time slice of a lattice quantity (time must be most slowly varying)
841 void writeOLatticeSlice(BinaryWriter& bin, const char* output,
842 size_t size, size_t nmemb,
843 int start_lexico, int stop_lexico)
844 {
845 const int xinc = Layout::subgridLattSize()[0];
846
847 if ((stop_lexico % xinc) != 0)
848 {
849 QDPIO::cerr << __func__ << ": erorr: stop_lexico= " << stop_lexico << " xinc= " << xinc << std::endl;
850 QDP_abort(1);
851 }
852
853 size_t sizemem = size*nmemb;
854 size_t tot_size = sizemem*xinc;
855 char *recv_buf = new(std::nothrow) char[tot_size];
856 if( recv_buf == 0x0 ) {
857 QDP_error_exit("Unable to allocate recv_buf\n");}
858
859 // Find the location of each site and send to primary node
860 int old_node = 0;
861
862 for (int site=start_lexico; site < stop_lexico; site += xinc)
863 {
864 // first site in each segment uniquely identifies the node
865 int node = Layout::nodeNumber(crtesn(site, Layout::lattSize()));
866
867 // Send nodes must wait for a ready signal from the master node
868 // to prevent message pileups on the master node
869 if (node != old_node){
870 // On non-grid machines, use a clear-to-send like protocol
871 QDPInternal::clearToSend(recv_buf,sizeof(int),node);
872 old_node = node;}
873
874 // Copy to buffer: be really careful since max(linear) could vary among nodes
875 if (Layout::nodeNumber() == node){
876 for(int i=0; i < xinc; ++i){
877 int linear = Layout::linearSiteIndex(crtesn(site+i, Layout::lattSize()));
878 memcpy(recv_buf+i*sizemem, output+linear*sizemem, sizemem);
879 }
880 }
881
882 // Send result to primary node. Avoid sending prim-node sending to itself
883 if (node != 0)
884 {
885#if 1
886 // All nodes participate
887 QDPInternal::route((void *)recv_buf, node, 0, tot_size);
888#else
890 QDPInternal::recvFromWait((void *)recv_buf, node, tot_size);
891 if (Layout::nodeNumber() == node)
892 QDPInternal::sendToWait((void *)recv_buf, 0, tot_size);
893#endif
894 }
895
896 bin.writeArrayPrimaryNode(recv_buf, size, nmemb*xinc);
897 }
898 delete[] recv_buf;
899 }
900 }
901
902
903//-----------------------------------------------------------------------
904// Compute simple NERSC-like checksum of a gauge field
905/*
906 * \ingroup io
907 *
908 * \param u gauge configuration ( Read )
909 *
910 * \return checksum
911 */
912
914 int mat_size)
915 {
916 size_t size = sizeof(REAL32);
917 size_t su3_size = size*mat_size;
918 n_uint32_t checksum = 0; // checksum
919
920 multi1d<multi1d<ColorMatrix> > sa(Nd); // extract gauge fields
921 const int nodeSites = Layout::sitesOnNode();
922
923 for(int dd=0; dd<Nd; dd++) /* dir */
924 {
925 sa[dd].resize(nodeSites);
926 QDP_extract(sa[dd], u[dd], all);
927 }
928
929 char *chk_buf = new(std::nothrow) char[su3_size];
930 if( chk_buf == 0x0 ) {
931 QDP_error_exit("Unable to allocate chk_buf\n");
932 }
933
934 for(int linear=0; linear < nodeSites; ++linear)
935 {
936 for(int dd=0; dd<Nd; dd++) /* dir */
937 {
938 switch (mat_size)
939 {
940 case 12:
941 {
942 REAL32 su3[2][3][2];
943
944 for(int kk=0; kk<Nc; kk++) /* color */
945 for(int ii=0; ii<2; ii++) /* color */
946 {
947 Complex sitecomp = peekColor(sa[dd][linear],ii,kk);
948 su3[ii][kk][0] = toFloat(Real(real(sitecomp)));
949 su3[ii][kk][1] = toFloat(Real(imag(sitecomp)));
950 }
951
952 memcpy(chk_buf, &(su3[0][0][0]), su3_size);
953 }
954 break;
955
956 case 18:
957 {
958 REAL32 su3[3][3][2];
959
960 for(int kk=0; kk<Nc; kk++) /* color */
961 for(int ii=0; ii<Nc; ii++) /* color */
962 {
963 Complex sitecomp = peekColor(sa[dd][linear],ii,kk);
964 su3[ii][kk][0] = toFloat(Real(real(sitecomp)));
965 su3[ii][kk][1] = toFloat(Real(imag(sitecomp)));
966 }
967
968 memcpy(chk_buf, &(su3[0][0][0]), su3_size);
969 }
970 break;
971
972 default:
973 QDPIO::cerr << __func__ << ": unexpected size" << std::endl;
974 QDP_abort(1);
975 }
976
977 // Compute checksum
978 n_uint32_t* chk_ptr = (n_uint32_t*)chk_buf;
979 for(unsigned int i=0; i < mat_size*size/sizeof(n_uint32_t); ++i)
980 checksum += chk_ptr[i];
981 }
982 }
983
984 delete[] chk_buf;
985
986 // Get all nodes to contribute
987 QDPInternal::globalSumArray((unsigned int*)&checksum, 1); // g++ requires me to narrow the type to unsigned int
988
989 return checksum;
990 }
991
992
993//-----------------------------------------------------------------------
994// Read a QCD archive file
995// Read a QCD (NERSC) Archive format gauge field
996/*
997 * \ingroup io
998 *
999 * \param cfg_in binary writer object ( Modify )
1000 * \param u gauge configuration ( Modify )
1001 */
1002
1004 n_uint32_t& checksum, int mat_size, int float_size)
1005 {
1006 size_t size = float_size;
1007 size_t su3_size = size*mat_size;
1008 size_t tot_size = su3_size*Nd;
1009 const int nodeSites = Layout::sitesOnNode();
1010
1011 char *input = new(std::nothrow) char[tot_size*nodeSites]; // keep another copy in input buffers
1012 if( input == 0x0 ) {
1013 QDP_error_exit("Unable to allocate input\n");
1014 }
1015
1016 char *recv_buf = new(std::nothrow) char[tot_size];
1017 if( recv_buf == 0x0 ) {
1018 QDP_error_exit("Unable to allocate recv_buf\n");
1019 }
1020
1021 checksum = 0;
1022
1023 // Find the location of each site and send to primary node
1024 for(int site=0; site < Layout::vol(); ++site)
1025 {
1026 multi1d<int> coord = crtesn(site, Layout::lattSize());
1027
1028 int node = Layout::nodeNumber(coord);
1029 int linear = Layout::linearSiteIndex(coord);
1030
1031 // Only on primary node read the data
1032 cfg_in.readArrayPrimaryNode(recv_buf, size, mat_size*Nd);
1033
1034 if (Layout::primaryNode())
1035 {
1036 // Compute checksum
1037 n_uint32_t* chk_ptr = (n_uint32_t*)recv_buf;
1038 for(unsigned int i=0; i < mat_size*Nd*size/sizeof(n_uint32_t); ++i)
1039 checksum += chk_ptr[i];
1040 }
1041
1042 // Send result to destination node. Avoid sending prim-node sending to itself
1043 if (node != 0)
1044 {
1045#if 1
1046 // All nodes participate
1047 QDPInternal::route((void *)recv_buf, 0, node, tot_size);
1048#else
1049 if (Layout::primaryNode())
1050 QDPInternal::sendToWait((void *)recv_buf, node, tot_size);
1051
1052 if (Layout::nodeNumber() == node)
1053 QDPInternal::recvFromWait((void *)recv_buf, 0, tot_size);
1054#endif
1055 }
1056
1057 if (Layout::nodeNumber() == node)
1058 memcpy(input+linear*tot_size, recv_buf, tot_size);
1059 }
1060
1061 delete[] recv_buf;
1062
1063 QDPInternal::broadcast(checksum);
1064
1065 // Reconstruct the gauge field
1066 ColorMatrix sitefield;
1067 REAL su3[3][3][2];
1068
1069 for(int linear=0; linear < nodeSites; ++linear)
1070 {
1071 for(int dd=0; dd<Nd; dd++) /* dir */
1072 {
1073 // Transfer the data from input into SU3
1074 if (float_size == 4)
1075 {
1076 REAL* su3_p = (REAL *)su3;
1077 REAL32* input_p = (REAL32 *)( input+su3_size*(dd+Nd*linear) );
1078 for(int cp_index=0; cp_index < mat_size; cp_index++) {
1079 su3_p[cp_index] = (REAL)(input_p[cp_index]);
1080 }
1081 }
1082 else if (float_size == 8)
1083 {
1084 // IEEE64BIT case
1085 REAL *su3_p = (REAL *)su3;
1086 REAL64 *input_p = (REAL64 *)( input+su3_size*(dd+Nd*linear) );
1087 for(int cp_index=0; cp_index < mat_size; cp_index++) {
1088 su3_p[cp_index] = (REAL)input_p[cp_index];
1089 }
1090 }
1091 else {
1092 QDPIO::cerr << __func__ << ": Unknown mat size" << std::endl;
1093 QDP_abort(1);
1094 }
1095
1096 /* Reconstruct the third column if necessary */
1097 if (mat_size == 12)
1098 {
1099 su3[2][0][0] = su3[0][1][0]*su3[1][2][0] - su3[0][1][1]*su3[1][2][1]
1100 - su3[0][2][0]*su3[1][1][0] + su3[0][2][1]*su3[1][1][1];
1101 su3[2][0][1] = su3[0][2][0]*su3[1][1][1] + su3[0][2][1]*su3[1][1][0]
1102 - su3[0][1][0]*su3[1][2][1] - su3[0][1][1]*su3[1][2][0];
1103
1104 su3[2][1][0] = su3[0][2][0]*su3[1][0][0] - su3[0][2][1]*su3[1][0][1]
1105 - su3[0][0][0]*su3[1][2][0] + su3[0][0][1]*su3[1][2][1];
1106 su3[2][1][1] = su3[0][0][0]*su3[1][2][1] + su3[0][0][1]*su3[1][2][0]
1107 - su3[0][2][0]*su3[1][0][1] - su3[0][2][1]*su3[1][0][0];
1108
1109 su3[2][2][0] = su3[0][0][0]*su3[1][1][0] - su3[0][0][1]*su3[1][1][1]
1110 - su3[0][1][0]*su3[1][0][0] + su3[0][1][1]*su3[1][0][1];
1111 su3[2][2][1] = su3[0][1][0]*su3[1][0][1] + su3[0][1][1]*su3[1][0][0]
1112 - su3[0][0][0]*su3[1][1][1] - su3[0][0][1]*su3[1][1][0];
1113 }
1114
1115 /* Copy into the big array */
1116 for(int kk=0; kk<Nc; kk++) /* color */
1117 {
1118 for(int ii=0; ii<Nc; ii++) /* color */
1119 {
1120 Complex sitecomp = cmplx(Real(su3[ii][kk][0]), Real(su3[ii][kk][1]));
1121 pokeColor(sitefield,sitecomp,ii,kk);
1122 }
1123 }
1124
1125 u[dd].elem(linear) = sitefield.elem();
1126 }
1127 }
1128
1129 delete[] input;
1130 }
1131
1132
1133//-----------------------------------------------------------------------
1134// Write a QCD archive file
1135// Write a QCD (NERSC) Archive format gauge field
1136/*
1137 * \ingroup io
1138 *
1139 * \param cfg_out binary writer object ( Modify )
1140 * \param u gauge configuration ( Read )
1141 */
1143 int mat_size)
1144 {
1145 size_t size = sizeof(REAL32);
1146 size_t su3_size = size*mat_size;
1147 size_t tot_size = su3_size*Nd;
1148 char *recv_buf = new(std::nothrow) char[tot_size];
1149 if( recv_buf == 0x0 ) {
1150 QDP_error_exit("Unable to allocate recv_buf\n");
1151 }
1152
1153 const int nodeSites = Layout::sitesOnNode();
1154
1155 multi1d<multi1d<ColorMatrix> > sa(Nd); // extract gauge fields
1156
1157 for(int dd=0; dd<Nd; dd++) /* dir */
1158 {
1159 sa[dd].resize(nodeSites);
1160 QDP_extract(sa[dd], u[dd], all);
1161 }
1162
1163 // Find the location of each site and send to primary node
1164 for(int site=0; site < Layout::vol(); ++site)
1165 {
1166 multi1d<int> coord = crtesn(site, Layout::lattSize());
1167
1168 int node = Layout::nodeNumber(coord);
1169 int linear = Layout::linearSiteIndex(coord);
1170
1171 // Copy to buffer: be really careful since max(linear) could vary among nodes
1172 if (Layout::nodeNumber() == node)
1173 {
1174 char *recv_buf_tmp = recv_buf;
1175
1176 for(int dd=0; dd<Nd; dd++) /* dir */
1177 {
1178 if ( mat_size == 12 )
1179 {
1180 REAL32 su3[2][3][2];
1181
1182 for(int kk=0; kk<Nc; kk++) /* color */
1183 for(int ii=0; ii<2; ii++) /* color */
1184 {
1185 Complex sitecomp = peekColor(sa[dd][linear],ii,kk);
1186 su3[ii][kk][0] = toFloat(Real(real(sitecomp)));
1187 su3[ii][kk][1] = toFloat(Real(imag(sitecomp)));
1188 }
1189
1190 memcpy(recv_buf_tmp, &(su3[0][0][0]), su3_size);
1191 }
1192 else
1193 {
1194 REAL32 su3[3][3][2];
1195
1196 for(int kk=0; kk<Nc; kk++) /* color */
1197 for(int ii=0; ii<Nc; ii++) /* color */
1198 {
1199 Complex sitecomp = peekColor(sa[dd][linear],ii,kk);
1200 su3[ii][kk][0] = toFloat(Real(real(sitecomp)));
1201 su3[ii][kk][1] = toFloat(Real(imag(sitecomp)));
1202 }
1203
1204 memcpy(recv_buf_tmp, &(su3[0][0][0]), su3_size);
1205 }
1206
1207 recv_buf_tmp += su3_size;
1208 }
1209 }
1210
1211 // Send result to primary node. Avoid sending prim-node sending to itself
1212 if (node != 0)
1213 {
1214#if 1
1215 // All nodes participate
1216 QDPInternal::route((void *)recv_buf, node, 0, tot_size);
1217#else
1218 if (Layout::primaryNode())
1219 QDPInternal::recvFromWait((void *)recv_buf, node, tot_size);
1220
1221 if (Layout::nodeNumber() == node)
1222 QDPInternal::sendToWait((void *)recv_buf, 0, tot_size);
1223#endif
1224 }
1225
1226 cfg_out.writeArrayPrimaryNode(recv_buf, size, mat_size*Nd);
1227 }
1228
1229 delete[] recv_buf;
1230
1231 if (cfg_out.fail())
1232 {
1233 QDPIO::cerr << __func__ << ": error writing configuration" << std::endl;
1234 QDP_abort(1);
1235 }
1236 }
1237
1238} // namespace QDP;
Binary input base class.
Definition qdp_io.h:372
virtual void readArrayPrimaryNode(char *output, size_t nbytes, size_t nmemb)
Read data on the primary node only.
Definition qdp_io.cc:715
Binary writer base class.
Definition qdp_io.h:1010
virtual void writeArrayPrimaryNode(const char *output, size_t nbytes, size_t nmemb)
Write data on the primary node only.
Definition qdp_io.cc:1159
virtual void writeArray(const char *output, size_t nbytes, size_t nmemb)
Write data from the primary node.
Definition qdp_io.cc:1182
virtual bool fail()
Checks status of the previous IO operation.
Definition qdp_io.cc:1015
MapFunc.
Definition qdp_map.h:32
void make(const MapFunc &func)
Actual constructor from a function object.
Set - collection of subsets controlling which sites are involved in an operation.
Definition qdp_subset.h:96
const multi1d< int > & latticeColoring() const
The coloring of the lattice sites.
Definition qdp_subset.h:131
Subsets - controls how lattices are looped.
Definition qdp_subset.h:39
int color() const
Access the coloring for this subset.
Definition qdp_subset.h:60
const Set & getSet() const
The super-set of this subset.
Definition qdp_subset.h:87
Container for a multi-dimensional 1D array.
Definition qdp_multi.h:25
int size() const
Size of array.
Definition qdp_multi.h:60
void resize(int ns1)
Resize routine, call a templated resize, using *this to disambiguate.
Definition qdp_multi.h:56
int DML_route_bytes(char *buf, size_t size, int fromnode, int tonode)
OScalar< PScalar< PScalar< RComplex< REAL > > > > Complex
OScalar< PScalar< PColorMatrix< RComplex< REAL >, Nc > > > ColorMatrix
OScalar< PScalar< PScalar< RScalar< REAL > > > > Real
REAL32 REAL
double REAL64
void QDP_extract(multi1d< OScalar< T > > &dest, const OLattice< T > &src, const Subset &s)
Copy data values from field src to array dest.
void readArchiv(BinaryReader &cfg_in, multi1d< LatticeColorMatrix > &u, n_uint32_t &checksum, int mat_size, int float_size)
Read a NERSC Gauge Connection Archive file.
TextWriter & operator<<(TextWriter &txt, const std::string &output)
Definition qdp_io.cc:283
void writeArchiv(BinaryWriter &cfg_out, const multi1d< LatticeColorMatrix > &u, int mat_size)
Writes a NERSC Gauge Connection Archive gauge configuration file.
float toFloat(const IScalar< T > &s)
QDP Real to float primitive in conversion routine.
Definition qdp_inner.h:1623
const int Nc
Definition qdp_params.h:25
const int Nd
Definition qdp_params.h:24
Subset all
Default all subset.
Definition qdp_subset.cc:16
void writeOLatticeSlice(BinaryWriter &bin, const char *output, size_t size, size_t nmemb, int start_lexico, int stop_lexico)
void readOLatticeSlice(BinaryReader &bin, char *input, size_t size, size_t nmemb, int start_lexico, int stop_lexico)
Lattice time slice reader.
int nodeNumber()
Returns the node number of this node.
int linearSiteIndex(int site)
The linearized site index for the corresponding lexicographic site.
int sitesOnNode()
Subgrid lattice volume.
multi1d< int > siteCoords(int node, int index) QDP_CONST
Reconstruct the lattice coordinate from the node and site number.
const multi1d< int > & lattSize()
Virtual grid (problem grid) lattice size.
const multi1d< int > & subgridLattSize()
Subgrid (grid on each node) lattice size.
int vol()
Total lattice volume.
bool primaryNode()
Returns whether this is the primary node.
StandardOutputStream cerr
Definition qdp_stdio.cc:22
void broadcast(T &dest)
Broadcast from primary node to all other nodes.
void sendToWait(void *send_buf, int dest_node, int count)
Send to another node (wait).
void clearToSend(void *buffer, int count, int node)
Send a clear-to-send.
void route(void *buffer, int srce_node, int dest_node, int count)
Route to another node (blocking).
bool gridArch()
Is this a grid architecture.
void recvFromWait(void *recv_buf, int srce_node, int count)
Receive from another node (wait).
void broadcast_str(std::string &result)
Broadcast a string from primary node to all other nodes.
void globalSumArray(unsigned int *dest, int len)
Wrapper to get a functional unsigned global sum.
Yet another random number generator.
MakeReturn< UnaryNode< FnReal, typenameCreateLeaf< QDPExpr< T1, C1 > >::Leaf_t >, typenameUnaryReturn< C1, FnReal >::Type_t >::Expression_t real(const QDPExpr< T1, C1 > &l)
Definition qdp.h:4972
MakeReturn< UnaryNode< FnPeekColorMatrix, typenameCreateLeaf< QDPExpr< T1, C1 > >::Leaf_t >, C1 >::Expression_t peekColor(const QDPExpr< T1, C1 > &l, int row, int col)
Definition qdp_newops.h:161
void QDP_error_exit(const char *format,...)
Simple error display and abort routine.
Definition qdp_util.cc:93
void readOLattice(BinaryReader &bin, char *input, size_t size, size_t nmemb)
Read a lattice quantity.
multi1d< int > uniquify_list(const multi1d< int > &ll)
Unique-ify a list.
Definition qdp_util.cc:128
C1 & pokeColor(QDPType< T1, C1 > &l, const QDPExpr< T2, C2 > &r, int row, int col)
Definition qdp_newops.h:360
void writeOLattice(BinaryWriter &bin, const char *output, size_t size, size_t nmemb)
Write a lattice quantity.
void QDP_abort(int status)
Panic button.
MakeReturn< BinaryNode< FnCmplx, typenameCreateLeaf< QDPType< T1, C1 > >::Leaf_t, typenameCreateLeaf< QDPExpr< T2, C2 > >::Leaf_t >, typenameBinaryReturn< C1, C2, FnCmplx >::Type_t >::Expression_t cmplx(const QDPType< T1, C1 > &l, const QDPExpr< T2, C2 > &r)
Definition qdp.h:2348
n_uint32_t computeChecksum(const multi1d< LatticeColorMatrix > &u, int mat_size)
Compute simple NERSC-like checksum of a gauge field.
MakeReturn< UnaryNode< FnImag, typenameCreateLeaf< QDPExpr< T1, C1 > >::Leaf_t >, typenameUnaryReturn< C1, FnImag >::Type_t >::Expression_t imag(const QDPExpr< T1, C1 > &l)
Definition qdp.h:4985
multi1d< int > crtesn(int ipos, const multi1d< int > &latt_size)
Decompose a lexicographic site into coordinates.
int QDP_info(const char *format,...)
Simple information display routine.
Definition qdp_util.cc:43
Primary include file for QDP.