1 /**************************************************************************
2 ** Greg Koenig (koenig@uiuc.edu)
5 ** This is GridHybridSeedLB.C
9 #include "GridHybridSeedLB.decl.h"
11 #include "GridHybridSeedLB.h"
14 CreateLBFunc_Def (GridHybridSeedLB, "Grid load balancer that uses hybrid seed technique to optimize communication graph")
18 /**************************************************************************
21 GridHybridSeedLB::GridHybridSeedLB (const CkLBOptions &opt) : CentralLB (opt)
26 lbname = (char *) "GridHybridSeedLB";
29 CkPrintf ("[%d] GridHybridSeedLB created.\n", CkMyPe());
32 if (value = getenv ("CK_LDB_GRIDHYBRIDSEEDLB_MODE")) {
33 CK_LDB_GridHybridSeedLB_Mode = atoi (value);
35 CK_LDB_GridHybridSeedLB_Mode = CK_LDB_GRIDHYBRIDSEEDLB_MODE;
38 if (value = getenv ("CK_LDB_GRIDHYBRIDSEEDLB_BACKGROUND_LOAD")) {
39 CK_LDB_GridHybridSeedLB_Background_Load = atoi (value);
41 CK_LDB_GridHybridSeedLB_Background_Load = CK_LDB_GRIDHYBRIDSEEDLB_BACKGROUND_LOAD;
44 if (value = getenv ("CK_LDB_GRIDHYBRIDSEEDLB_LOAD_TOLERANCE")) {
45 CK_LDB_GridHybridSeedLB_Load_Tolerance = atof (value);
47 CK_LDB_GridHybridSeedLB_Load_Tolerance = CK_LDB_GRIDHYBRIDSEEDLB_LOAD_TOLERANCE;
55 /**************************************************************************
58 GridHybridSeedLB::GridHybridSeedLB (CkMigrateMessage *msg) : CentralLB (msg)
63 lbname = (char *) "GridHybridSeedLB";
65 if (value = getenv ("CK_LDB_GRIDHYBRIDSEEDLB_MODE")) {
66 CK_LDB_GridHybridSeedLB_Mode = atoi (value);
68 CK_LDB_GridHybridSeedLB_Mode = CK_LDB_GRIDHYBRIDSEEDLB_MODE;
71 if (value = getenv ("CK_LDB_GRIDHYBRIDSEEDLB_BACKGROUND_LOAD")) {
72 CK_LDB_GridHybridSeedLB_Background_Load = atoi (value);
74 CK_LDB_GridHybridSeedLB_Background_Load = CK_LDB_GRIDHYBRIDSEEDLB_BACKGROUND_LOAD;
77 if (value = getenv ("CK_LDB_GRIDHYBRIDSEEDLB_LOAD_TOLERANCE")) {
78 CK_LDB_GridHybridSeedLB_Load_Tolerance = atof (value);
80 CK_LDB_GridHybridSeedLB_Load_Tolerance = CK_LDB_GRIDHYBRIDSEEDLB_LOAD_TOLERANCE;
88 /**************************************************************************
89 ** The Charm++ load balancing framework invokes this method to determine
90 ** whether load balancing can be performed at a specified time.
92 bool GridHybridSeedLB::QueryBalanceNow (int step)
94 if (_lb_args.debug() > 2) {
95 CkPrintf ("[%d] GridHybridSeedLB is balancing on step %d.\n", CkMyPe(), step);
103 /**************************************************************************
104 ** The vmi-linux machine layer incorporates the idea that PEs are located
105 ** within identifiable clusters. This information can be supplied by the
106 ** user or can be probed automatically by the machine layer. The exposed
107 ** API call CmiGetCluster() returns the integer cluster number for a
108 ** specified PE or -1 if the information is unknown.
110 ** For machine layers other than vmi-linux, simply return the constant 0.
111 ** GridHybridSeedLB will assume a single-cluster computation and will
112 ** balance on the scaled processor load and number of LAN messages.
114 int GridHybridSeedLB::Get_Cluster (int pe)
121 /**************************************************************************
124 void GridHybridSeedLB::Initialize_PE_Data (CentralLB::LDStats *stats)
129 PE_Data = new PE_Data_T[Num_PEs];
132 for (int i = 0; i < Num_PEs; i++) {
133 (&PE_Data[i])->available = stats->procs[i].available;
134 (&PE_Data[i])->cluster = Get_Cluster (i);
135 (&PE_Data[i])->num_objs = 0;
136 (&PE_Data[i])->num_lan_objs = 0;
137 (&PE_Data[i])->num_lan_msgs = 0;
138 (&PE_Data[i])->num_wan_objs = 0;
139 (&PE_Data[i])->num_wan_msgs = 0;
140 (&PE_Data[i])->relative_speed = 0.0;
141 (&PE_Data[i])->scaled_load = 0.0;
143 if (stats->procs[i].pe_speed < min_speed) {
144 min_speed = stats->procs[i].pe_speed;
148 // Compute the relative PE speeds.
149 // Also add background CPU time to each PE's scaled load.
150 for (int i = 0; i < Num_PEs; i++) {
151 (&PE_Data[i])->relative_speed = (double) (stats->procs[i].pe_speed / min_speed);
152 if (CK_LDB_GridHybridSeedLB_Background_Load) {
153 (&PE_Data[i])->scaled_load += stats->procs[i].bg_walltime;
160 /**************************************************************************
163 int GridHybridSeedLB::Available_PE_Count ()
165 int available_pe_count;
168 available_pe_count = 0;
169 for (int i = 0; i < Num_PEs; i++) {
170 if ((&PE_Data[i])->available) {
171 available_pe_count += 1;
175 return (available_pe_count);
180 /**************************************************************************
183 int GridHybridSeedLB::Compute_Number_Of_Clusters ()
189 for (int i = 0; i < Num_PEs; i++) {
190 if ((&PE_Data[i])->cluster < 0) {
194 if ((&PE_Data[i])->cluster > max_cluster) {
195 max_cluster = (&PE_Data[i])->cluster;
199 return (max_cluster + 1);
204 /**************************************************************************
207 void GridHybridSeedLB::Initialize_Object_Data (CentralLB::LDStats *stats)
209 Object_Data = new Object_Data_T[Num_Objects];
211 for (int i = 0; i < Num_Objects; i++) {
212 (&Object_Data[i])->migratable = (&stats->objData[i])->migratable;
213 (&Object_Data[i])->from_pe = stats->from_proc[i];
214 (&Object_Data[i])->num_lan_msgs = 0;
215 (&Object_Data[i])->num_wan_msgs = 0;
216 (&Object_Data[i])->load = (&stats->objData[i])->wallTime;
217 (&Object_Data[i])->secondary_index = -1;
219 if ((&Object_Data[i])->migratable) {
220 (&Object_Data[i])->to_pe = -1;
221 (&Object_Data[i])->cluster = -1;
223 (&Object_Data[i])->to_pe = (&Object_Data[i])->from_pe;
224 (&Object_Data[i])->cluster = Get_Cluster ((&Object_Data[i])->from_pe);
225 if (_lb_args.debug() > 1) {
226 CkPrintf ("[%d] GridHybridSeedLB identifies object %d as non-migratable.\n", CkMyPe(), i);
234 /**************************************************************************
237 int GridHybridSeedLB::Compute_Migratable_Object_Count ()
244 for (int i = 0; i < Num_Objects; i++) {
245 if ((&Object_Data[i])->migratable) {
255 /**************************************************************************
258 void GridHybridSeedLB::Initialize_Cluster_Data ()
261 double min_total_cpu_power;
264 Cluster_Data = new Cluster_Data_T[Num_Clusters];
266 for (int i = 0; i < Num_Clusters; i++) {
267 (&Cluster_Data[i])->num_pes = 0;
268 (&Cluster_Data[i])->total_cpu_power = 0.0;
269 (&Cluster_Data[i])->scaled_cpu_power = 0.0;
272 // Compute the relative speed of each cluster.
273 for (int i = 0; i < Num_PEs; i++) {
274 cluster = (&PE_Data[i])->cluster;
276 (&Cluster_Data[cluster])->num_pes += 1;
277 (&Cluster_Data[cluster])->total_cpu_power += (&PE_Data[i])->relative_speed;
280 min_total_cpu_power = MAXDOUBLE;
281 for (int i = 0; i < Num_Clusters; i++) {
282 if ((&Cluster_Data[i])->total_cpu_power < min_total_cpu_power) {
283 min_total_cpu_power = (&Cluster_Data[i])->total_cpu_power;
287 for (int i = 0; i < Num_Clusters; i++) {
288 (&Cluster_Data[i])->scaled_cpu_power = (double) ((&Cluster_Data[i])->total_cpu_power / min_total_cpu_power);
294 /**************************************************************************
297 void GridHybridSeedLB::Initialize_Communication_Matrix (CentralLB::LDStats *stats)
299 LDCommData *com_data;
305 LDObjKey *recv_objects;
309 Migratable_Objects = new int[Num_Migratable_Objects];
312 for (int i = 0; i < Num_Objects; i++) {
313 if ((&Object_Data[i])->migratable) {
314 (&Object_Data[i])->secondary_index = index;
315 Migratable_Objects[index] = i;
320 // Create Communication_Matrix[] to hold all object-to-object message counts.
321 Communication_Matrix = new int *[Num_Migratable_Objects];
322 for (int i = 0; i < Num_Migratable_Objects; i++) {
323 Communication_Matrix[i] = new int[Num_Migratable_Objects];
324 for (int j = 0; j < Num_Migratable_Objects; j++) {
325 Communication_Matrix[i][j] = 0;
329 for (int i = 0; i < stats->n_comm; i++) {
330 com_data = &(stats->commData[i]);
331 if ((!com_data->from_proc()) && (com_data->recv_type() == LD_OBJ_MSG)) {
332 send_object = stats->getHash (com_data->sender);
333 recv_object = stats->getHash (com_data->receiver.get_destObj());
335 if ((send_object < 0) || (send_object > Num_Objects) || (recv_object < 0) || (recv_object > Num_Objects)) {
339 if ((!(&Object_Data[send_object])->migratable) || (!(&Object_Data[recv_object])->migratable)) {
343 send_index = (&Object_Data[send_object])->secondary_index;
344 recv_index = (&Object_Data[recv_object])->secondary_index;
346 Communication_Matrix[send_index][recv_index] += com_data->messages;
347 Communication_Matrix[recv_index][send_index] += com_data->messages;
348 } else if (com_data->receiver.get_type() == LD_OBJLIST_MSG) {
349 send_object = stats->getHash (com_data->sender);
351 if ((send_object < 0) || (send_object > Num_Objects)) {
355 if (!(&Object_Data[send_object])->migratable) {
359 recv_objects = com_data->receiver.get_destObjs (num_objects); // (num_objects is passed by reference)
361 for (int j = 0; j < num_objects; j++) {
362 recv_object = stats->getHash (recv_objects[j]);
364 if ((recv_object < 0) || (recv_object > Num_Objects)) {
368 if (!(&Object_Data[recv_object])->migratable) {
372 send_index = (&Object_Data[send_object])->secondary_index;
373 recv_index = (&Object_Data[recv_object])->secondary_index;
375 Communication_Matrix[send_index][recv_index] += com_data->messages;
376 Communication_Matrix[recv_index][send_index] += com_data->messages;
381 for (int i = 0; i < Num_Migratable_Objects; i++) {
382 Communication_Matrix[i][i] = 0;
388 /**************************************************************************
389 ** This takes objects and partitions them into clusters.
391 void GridHybridSeedLB::Partition_Objects_Into_Clusters (CentralLB::LDStats *stats)
395 int *partition_to_cluster_map;
413 if (Num_Clusters == 1) {
414 for (int i = 0; i < Num_Objects; i++) {
415 (&Object_Data[i])->cluster = 0;
421 // Compute the number of partitions for Metis, based on the scaled CPU power for each cluster.
422 // Also create a partition-to-cluster mapping so the output of Metis can be mapped back to clusters.
424 for (int i = 0; i < Num_Clusters; i++) {
425 num_partitions += (int) ceil ((&Cluster_Data[i])->scaled_cpu_power);
428 partition_to_cluster_map = new int[num_partitions];
432 while (partition < num_partitions) {
433 partition_count = (int) ceil ((&Cluster_Data[cluster])->scaled_cpu_power);
435 for (int i = partition; i < (partition + partition_count); i++) {
436 partition_to_cluster_map[i] = cluster;
439 partition += partition_count;
443 if ((CK_LDB_GridHybridSeedLB_Mode == 1) || (CK_LDB_GridHybridSeedLB_Mode == 3)) {
444 vertex_weights = new int[Num_Migratable_Objects];
446 for (int i = 0; i < Num_Objects; i++) {
447 if ((&Object_Data[i])->migratable) {
448 vertex_weights[vertex] = (int) ceil ((&Object_Data[i])->load * 10000);
454 // Construct a graph in CSR format for input to Metis.
455 xadj = new int[Num_Migratable_Objects + 1];
457 for (int i = 0; i < Num_Migratable_Objects; i++) {
458 for (int j = 0; j < Num_Migratable_Objects; j++) {
459 if (Communication_Matrix[i][j] > 0) {
464 adjncy = new int[num_edges];
465 edge_weights = new int[num_edges];
468 for (int i = 0; i < Num_Migratable_Objects; i++) {
469 for (int j = 0; j < Num_Migratable_Objects; j++) {
470 if (Communication_Matrix[i][j] > 0) {
472 edge_weights[count] = Communication_Matrix[i][j];
479 if ((CK_LDB_GridHybridSeedLB_Mode == 0) || (CK_LDB_GridHybridSeedLB_Mode == 2)) {
480 // Call Metis to partition the communication graph.
481 weight_flag = 1; // weights on edges only
482 numbering_flag = 0; // C style numbering (base 0)
484 newmap = new int[Num_Migratable_Objects];
486 METIS_PartGraphRecursive (&Num_Migratable_Objects, xadj, adjncy, NULL, edge_weights, &weight_flag, &numbering_flag, &num_partitions, options, &edgecut, newmap);
487 } else if ((CK_LDB_GridHybridSeedLB_Mode == 1) || (CK_LDB_GridHybridSeedLB_Mode == 3)) {
488 // Call Metis to partition the communication graph.
489 weight_flag = 3; // weights on both vertices and edges
490 numbering_flag = 0; // C style numbering (base 0)
492 newmap = new int[Num_Migratable_Objects];
494 METIS_PartGraphRecursive (&Num_Migratable_Objects, xadj, adjncy, vertex_weights, edge_weights, &weight_flag, &numbering_flag, &num_partitions, options, &edgecut, newmap);
496 if (_lb_args.debug() > 0) {
497 CkPrintf ("[%d] GridHybridSeedLB was told to use bad mode (%d).\n", CkMyPe(), CK_LDB_GridHybridSeedLB_Mode);
501 // Place the partitioned objects into their correct clusters.
502 for (int i = 0; i < Num_Migratable_Objects; i++) {
503 partition = newmap[i];
504 cluster = partition_to_cluster_map[partition];
506 index = Migratable_Objects[i];
508 (&Object_Data[index])->cluster = cluster;
513 delete [] edge_weights;
516 if ((CK_LDB_GridHybridSeedLB_Mode == 1) || (CK_LDB_GridHybridSeedLB_Mode == 3)) {
517 delete [] vertex_weights;
519 delete [] partition_to_cluster_map;
524 /**************************************************************************
527 void GridHybridSeedLB::Examine_InterObject_Messages (CentralLB::LDStats *stats)
529 LDCommData *com_data;
534 LDObjKey *recv_objects;
538 for (int i = 0; i < stats->n_comm; i++) {
539 com_data = &(stats->commData[i]);
540 if ((!com_data->from_proc()) && (com_data->recv_type() == LD_OBJ_MSG)) {
541 send_object = stats->getHash (com_data->sender);
542 recv_object = stats->getHash (com_data->receiver.get_destObj());
544 if ((send_object < 0) || (send_object > Num_Objects) || (recv_object < 0) || (recv_object > Num_Objects)) {
548 send_cluster = (&Object_Data[send_object])->cluster;
549 recv_cluster = (&Object_Data[recv_object])->cluster;
551 if (send_cluster == recv_cluster) {
552 (&Object_Data[send_object])->num_lan_msgs += com_data->messages;
554 (&Object_Data[send_object])->num_wan_msgs += com_data->messages;
556 } else if (com_data->receiver.get_type() == LD_OBJLIST_MSG) {
557 send_object = stats->getHash (com_data->sender);
559 if ((send_object < 0) || (send_object > Num_Objects)) {
563 send_cluster = (&Object_Data[send_object])->cluster;
565 recv_objects = com_data->receiver.get_destObjs (num_objects); // (num_objects is passed by reference)
567 for (int j = 0; j < num_objects; j++) {
568 recv_object = stats->getHash (recv_objects[j]);
570 if ((recv_object < 0) || (recv_object > Num_Objects)) {
574 recv_cluster = (&Object_Data[recv_object])->cluster;
576 if (send_cluster == recv_cluster) {
577 (&Object_Data[send_object])->num_lan_msgs += com_data->messages;
579 (&Object_Data[send_object])->num_wan_msgs += com_data->messages;
588 /**************************************************************************
591 void GridHybridSeedLB::Map_NonMigratable_Objects_To_PEs ()
593 for (int i = 0; i < Num_Objects; i++) {
594 if (!((&Object_Data[i])->migratable)) {
595 if (_lb_args.debug() > 1) {
596 CkPrintf ("[%d] GridHybridSeedLB identifies object %d as non-migratable.\n", CkMyPe(), i);
599 Assign_Object_To_PE (i, (&Object_Data[i])->from_pe);
606 /**************************************************************************
607 ** This method locates the maximum WAN object in terms of number of
608 ** messages that traverse a wide-area connection. The search is
609 ** constrained to objects within the specified cluster that have not yet
610 ** been mapped (balanced) to a PE.
612 ** The method returns -1 if no matching object is found.
614 int GridHybridSeedLB::Find_Maximum_Object (int cluster)
623 for (int i = 0; i < Num_Objects; i++) {
624 if ((((&Object_Data[i])->cluster == cluster) && ((&Object_Data[i])->to_pe == -1)) && ((&Object_Data[i])->load > max_load)) {
626 max_load = (&Object_Data[i])->load;
635 /**************************************************************************
636 ** This method locates the maximum WAN object in terms of number of
637 ** messages that traverse a wide-area connection. The search is
638 ** constrained to objects within the specified cluster that have not yet
639 ** been mapped (balanced) to a PE.
641 ** The method returns -1 if no matching object is found.
643 int GridHybridSeedLB::Find_Maximum_Border_Object (int cluster)
648 int max_wan_msgs_index;
650 double load_tolerance;
658 max_wan_msgs_index = -1;
661 for (int i = 0; i < Num_Objects; i++) {
662 if (((&Object_Data[i])->cluster == cluster) && ((&Object_Data[i])->to_pe == -1) && ((&Object_Data[i])->num_wan_msgs > 0)) {
663 if ((&Object_Data[i])->load > max_load) {
665 max_load = (&Object_Data[i])->load;
667 if ((&Object_Data[i])->num_wan_msgs > max_wan_msgs) {
668 max_wan_msgs_index = i;
669 max_wan_msgs = (&Object_Data[i])->num_wan_msgs;
674 if (max_load_index < 0) {
675 return (max_load_index);
678 if ((&Object_Data[max_load_index])->num_wan_msgs >= (&Object_Data[max_wan_msgs_index])->num_wan_msgs) {
679 return (max_load_index);
682 if (CK_LDB_GridHybridSeedLB_Load_Tolerance <= 0.0) {
683 return (max_load_index);
686 load_tolerance = (&Object_Data[max_load_index])->load * CK_LDB_GridHybridSeedLB_Load_Tolerance;
688 max_index = max_load_index;
690 for (int i = 0; i < Num_Objects; i++) {
691 if (((&Object_Data[i])->cluster == cluster) && ((&Object_Data[i])->to_pe == -1) && ((&Object_Data[i])->num_wan_msgs > 0) && ((&Object_Data[i])->num_wan_msgs > (&Object_Data[max_index])->num_wan_msgs) && (fabs ((&Object_Data[max_load_index])->load - (&Object_Data[i])->load) <= load_tolerance)) {
701 /**************************************************************************
702 ** The method returns -1 if no matching object is found.
704 int GridHybridSeedLB::Find_Maximum_Object_From_Seeds (int pe)
711 double load_tolerance;
722 cluster = (&PE_Data[pe])->cluster;
724 for (int i = 0; i < Num_Objects; i++) {
725 if (((&Object_Data[i])->cluster == cluster) && ((&Object_Data[i])->to_pe == -1) && ((&Object_Data[i])->load > max_load)) {
727 max_load = (&Object_Data[i])->load;
731 if (max_load_index < 0) {
732 return (max_load_index);
735 if (CK_LDB_GridHybridSeedLB_Load_Tolerance <= 0.0) {
736 return (max_load_index);
739 load_tolerance = (&Object_Data[max_load_index])->load * CK_LDB_GridHybridSeedLB_Load_Tolerance;
741 max_index = max_load_index;
743 for (int i = 0; i < Num_Objects; i++) {
744 if ((&Object_Data[i])->to_pe == pe) {
745 for (int j = 0; j < Num_Objects; j++) {
746 if (((&Object_Data[j])->cluster == cluster) && ((&Object_Data[j])->to_pe == -1) && (fabs ((&Object_Data[max_load_index])->load - (&Object_Data[j])->load) <= load_tolerance)) {
747 comm_events = Compute_Communication_Events (i, j);
748 if (comm_events > max_comm_events) {
750 max_comm_events = comm_events;
762 /**************************************************************************
763 ** The method returns -1 if no matching object is found.
765 int GridHybridSeedLB::Find_Maximum_Border_Object_From_Seeds (int pe)
772 double load_tolerance;
783 cluster = (&PE_Data[pe])->cluster;
785 for (int i = 0; i < Num_Objects; i++) {
786 if (((&Object_Data[i])->cluster == cluster) && ((&Object_Data[i])->to_pe == -1) && ((&Object_Data[i])->num_wan_msgs > 0) && ((&Object_Data[i])->load > max_load)) {
788 max_load = (&Object_Data[i])->load;
792 if (max_load_index < 0) {
793 return (max_load_index);
796 if (CK_LDB_GridHybridSeedLB_Load_Tolerance <= 0.0) {
797 return (max_load_index);
800 load_tolerance = (&Object_Data[max_load_index])->load * CK_LDB_GridHybridSeedLB_Load_Tolerance;
802 max_index = max_load_index;
804 for (int i = 0; i < Num_Objects; i++) {
805 if ((&Object_Data[i])->to_pe == pe) {
806 for (int j = 0; j < Num_Objects; j++) {
807 if (((&Object_Data[j])->cluster == cluster) && ((&Object_Data[j])->to_pe == -1) && ((&Object_Data[j])->num_wan_msgs > 0) && (fabs ((&Object_Data[max_load_index])->load - (&Object_Data[j])->load) <= load_tolerance)) {
808 comm_events = Compute_Communication_Events (i, j);
809 if (comm_events > max_comm_events) {
811 max_comm_events = comm_events;
823 /**************************************************************************
826 int GridHybridSeedLB::Compute_Communication_Events (int obj1, int obj2)
832 send_index = (&Object_Data[obj1])->secondary_index;
833 recv_index = (&Object_Data[obj2])->secondary_index;
835 return (Communication_Matrix[send_index][recv_index]);
840 /**************************************************************************
841 ** This method locates the minimum WAN PE in terms of number of objects
842 ** that communicate with objects across a wide-area connection. The search
843 ** is constrained to PEs within the specified cluster.
845 ** In the event of a "tie" (i.e., the number of WAN objects on a candidate
846 ** PE is equal to the minimum number of WAN objects discovered so far) the
847 ** tie is broken by considering the scaled CPU loads on the PEs. The PE
848 ** with the smaller scaled load is the better candidate. In the event of
849 ** a secondary tie, the secondary tie is broken by considering the number
850 ** of LAN objects on the two PEs.
852 ** The method returns -1 if no matching PE is found.
854 int GridHybridSeedLB::Find_Minimum_PE (int cluster)
856 if ((CK_LDB_GridHybridSeedLB_Mode == 0) || (CK_LDB_GridHybridSeedLB_Mode == 1)) {
864 for (int i = 0; i < Num_PEs; i++) {
865 if (((&PE_Data[i])->available) && ((&PE_Data[i])->cluster == cluster)) {
866 if ((&PE_Data[i])->num_objs < min_objs) {
868 min_objs = (&PE_Data[i])->num_objs;
869 } else if (((&PE_Data[i])->num_objs == min_objs) &&
870 ((&PE_Data[i])->num_wan_objs < (&PE_Data[min_index])->num_wan_objs)) {
872 } else if (((&PE_Data[i])->num_objs == min_objs) &&
873 ((&PE_Data[i])->num_wan_objs == (&PE_Data[min_index])->num_wan_objs) &&
874 ((&PE_Data[i])->num_wan_msgs < (&PE_Data[min_index])->num_wan_msgs)) {
876 } else if (((&PE_Data[i])->num_objs == min_objs) &&
877 ((&PE_Data[i])->num_wan_objs == (&PE_Data[min_index])->num_wan_objs) &&
878 ((&PE_Data[i])->num_wan_msgs == (&PE_Data[min_index])->num_wan_msgs) &&
879 ((&PE_Data[i])->scaled_load < (&PE_Data[min_index])->scaled_load)) {
886 } else if ((CK_LDB_GridHybridSeedLB_Mode == 2) || (CK_LDB_GridHybridSeedLB_Mode == 3)) {
889 double min_scaled_load;
890 int min_wan_msgs_index;
892 double load_tolerance;
898 min_scaled_load = MAXDOUBLE;
900 min_wan_msgs_index = -1;
901 min_wan_msgs = MAXINT;
903 for (int i = 0; i < Num_PEs; i++) {
904 if (((&PE_Data[i])->available) && ((&PE_Data[i])->cluster == cluster)) {
905 if ((&PE_Data[i])->scaled_load < min_scaled_load) {
907 min_scaled_load = (&PE_Data[i])->scaled_load;
909 if ((&PE_Data[i])->num_wan_msgs < min_wan_msgs) {
910 min_wan_msgs_index = i;
911 min_wan_msgs = (&PE_Data[i])->num_wan_msgs;
916 // If no PE at all was found, return a -1.
917 if (min_load_index < 0) {
918 return (min_load_index);
921 // If the number of WAN messages on the lightest loaded PE happens to match the minimum number
922 // of WAN messages overall, we win because this target PE is overall the minimum PE in terms
923 // of both load *and* WAN messages.
924 if ((&PE_Data[min_load_index])->num_wan_msgs <= (&PE_Data[min_wan_msgs_index])->num_wan_msgs) {
925 return (min_load_index);
928 // Otherwise, we now search for PEs that have loads +/- our tolerance. If any PE has a load
929 // within our tolerance, check its number of WAN messages. The one of these that has the
930 // fewest WAN messages is probably the best candidate for placing the next object onto.
932 load_tolerance = (&PE_Data[min_load_index])->scaled_load * CK_LDB_GridHybridSeedLB_Load_Tolerance;
934 min_index = min_load_index;
936 for (int i = 0; i < Num_PEs; i++) {
937 if (((&PE_Data[i])->available) && ((&PE_Data[i])->cluster == cluster)) {
938 if (i != min_load_index) {
939 if (fabs ((&PE_Data[i])->scaled_load - (&PE_Data[min_load_index])->scaled_load) <= load_tolerance) {
940 if ((&PE_Data[i])->num_wan_msgs < (&PE_Data[min_index])->num_wan_msgs) {
950 if (_lb_args.debug() > 0) {
951 CkPrintf ("[%d] GridHybridSeedLB was told to use bad mode (%d).\n", CkMyPe(), CK_LDB_GridHybridSeedLB_Mode);
959 /**************************************************************************
960 ** This method assigns target_object to target_pe. The data structure
961 ** entry for target_pe is updated appropriately with measurements from
962 ** target_object. This updated information is considered when placing
963 ** successive objects onto PEs.
965 void GridHybridSeedLB::Assign_Object_To_PE (int target_object, int target_pe)
967 (&Object_Data[target_object])->to_pe = target_pe;
969 (&PE_Data[target_pe])->num_objs += 1;
971 if ((&Object_Data[target_object])->num_lan_msgs > 0) {
972 (&PE_Data[target_pe])->num_lan_objs += 1;
973 (&PE_Data[target_pe])->num_lan_msgs += (&Object_Data[target_object])->num_lan_msgs;
976 if ((&Object_Data[target_object])->num_wan_msgs > 0) {
977 (&PE_Data[target_pe])->num_wan_objs += 1;
978 (&PE_Data[target_pe])->num_wan_msgs += (&Object_Data[target_object])->num_wan_msgs;
981 (&PE_Data[target_pe])->scaled_load += (&Object_Data[target_object])->load / (&PE_Data[target_pe])->relative_speed;
986 /**************************************************************************
987 ** The Charm++ load balancing framework invokes this method to cause the
988 ** load balancer to migrate objects to "better" PEs.
990 void GridHybridSeedLB::work (LDStats *stats)
996 if (_lb_args.debug() > 0) {
997 CkPrintf ("[%d] GridHybridSeedLB is working (mode=%d, background load=%d, load tolerance=%f).\n", CkMyPe(), CK_LDB_GridHybridSeedLB_Mode, CK_LDB_GridHybridSeedLB_Background_Load, CK_LDB_GridHybridSeedLB_Load_Tolerance);
1000 // Since this load balancer looks at communications data, it must call stats->makeCommHash().
1001 stats->makeCommHash ();
1003 // Initialize object variables for the number of PEs and number of objects.
1004 Num_PEs = stats->nprocs();
1005 Num_Objects = stats->n_objs;
1007 if (_lb_args.debug() > 0) {
1008 CkPrintf ("[%d] GridHybridSeedLB is examining %d PEs and %d objects.\n", CkMyPe(), Num_PEs, Num_Objects);
1011 // Initialize the PE_Data[] data structure.
1012 Initialize_PE_Data (stats);
1014 // If at least one available PE does not exist, return from load balancing.
1015 if (Available_PE_Count() < 1) {
1016 if (_lb_args.debug() > 0) {
1017 CkPrintf ("[%d] GridHybridSeedLB finds no available PEs -- no balancing done.\n", CkMyPe());
1025 // Determine the number of clusters.
1026 // If any PE is not mapped to a cluster, return from load balancing.
1027 Num_Clusters = Compute_Number_Of_Clusters ();
1028 if (Num_Clusters < 1) {
1029 if (_lb_args.debug() > 0) {
1030 CkPrintf ("[%d] GridHybridSeedLB finds incomplete PE cluster map -- no balancing done.\n", CkMyPe());
1038 if (_lb_args.debug() > 0) {
1039 CkPrintf ("[%d] GridHybridSeedLB finds %d clusters.\n", CkMyPe(), Num_Clusters);
1042 // Initialize the Object_Data[] data structure.
1043 Initialize_Object_Data (stats);
1045 // Compute number of migratable objects.
1046 Num_Migratable_Objects = Compute_Migratable_Object_Count ();
1048 // Initialize the Cluster_Data[] data structure.
1049 Initialize_Cluster_Data ();
1051 // Initialize the Communication_Matrix[] data structure.
1052 Initialize_Communication_Matrix (stats);
1054 // Partition objects into clusters.
1055 Partition_Objects_Into_Clusters (stats);
1057 // Examine all object-to-object messages for intra-cluster and inter-cluster communications.
1058 Examine_InterObject_Messages (stats);
1060 // Map non-migratable objects to PEs.
1061 Map_NonMigratable_Objects_To_PEs ();
1063 // Map migratable objects to PEs in each cluster.
1064 for (int i = 0; i < Num_Clusters; i++) {
1067 target_pe = Find_Minimum_PE (i);
1069 if ((&PE_Data[target_pe])->num_objs == 0) {
1070 target_object = Find_Maximum_Border_Object (i);
1072 target_object = Find_Maximum_Border_Object_From_Seeds (target_pe);
1073 if (target_object == -1) {
1074 target_object = Find_Maximum_Border_Object (i);
1078 if ((target_object == -1) || (target_pe == -1)) {
1082 Assign_Object_To_PE (target_object, target_pe);
1086 target_pe = Find_Minimum_PE (i);
1088 target_object = Find_Maximum_Object_From_Seeds (target_pe);
1089 if (target_object == -1) {
1090 target_object = Find_Maximum_Object (i);
1093 if ((target_object == -1) || (target_pe == -1)) {
1097 Assign_Object_To_PE (target_object, target_pe);
1101 // Make the assignment of objects to PEs in the load balancer framework.
1102 for (int i = 0; i < Num_Objects; i++) {
1103 stats->to_proc[i] = (&Object_Data[i])->to_pe;
1105 if (_lb_args.debug() > 2) {
1106 CkPrintf ("[%d] GridHybridSeedLB migrates object %d from PE %d to PE %d.\n", CkMyPe(), i, stats->from_proc[i], stats->to_proc[i]);
1107 } else if (_lb_args.debug() > 1) {
1108 if (stats->to_proc[i] != stats->from_proc[i]) {
1109 CkPrintf ("[%d] GridHybridSeedLB migrates object %d from PE %d to PE %d.\n", CkMyPe(), i, stats->from_proc[i], stats->to_proc[i]);
1115 delete [] Migratable_Objects;
1116 for (int i = 0; i < Num_Migratable_Objects; i++) {
1117 delete [] Communication_Matrix[i];
1119 delete [] Communication_Matrix;
1120 delete [] Cluster_Data;
1121 delete [] Object_Data;
1125 #include "GridHybridSeedLB.def.h"