/* * ************************************************* * Version 2 (Pset Operations in resource request) * * ************************************************* * * Remark: * - Here we combine several API calls from version 1 * - ADVANTAGES/DISADVANTAGES: * - opposite of version 1 * --> we might need to find a compromise of both versions * * * Assumptions: * - PSets: * - Psets can cache arbitrary attributes DURING THEIR CREATION ONLY * - All PSets are created by the RTE * - Psets can be created by the RTE on behalf of the application via Resource Change Requests * - Resource Changes: * - Each Set operation is a resource change request * - A single Resource Change requests can involve several set operations * - Each resource change is associated with an existing Pset * - Resource Changes can be queried for a specified PSet * - No communicator required for resource change mechanism * * REQUIRED NEW API: * - Request Resource changes: * - MPI_Session_Dyn_create_pset_op_handle --> creates a representation (op_handle) of the specified set operation which can be used in resource change request * - MPI_Session_Dyn_request_res_change --> sends a res change request (conisting of op_handles and attributes for the new sets) * * - Query Resource Changes: * - MPI_Session_Dyn_Recv_res_change --> receives number and names of PSets created by the resource change associated with a specified set. Can be made collective/consistent across processes in a specified PSet. * * - Info related to PSets: * - MPI_Session_Pset_IsProcessIncluded OR mandatory PSet attribute to be looked up with MPI_Sessin_get_pset_info function (as assumed in code example) * - MPI_Session_get_primary_process OR mandatory PSet attribute to be looked up with MPI_Sessin_get_pset_info function (as assumed in code example) * * - Info related to Session: * MPI_Session_get_default_pset OR mandatory Session attribute to be looked up with MPI_Session_get_info function (as assumed in code example) * * - Test if processes have finished their MPI initialization process: * - MPI_Session_Test_Exist OR An adjsuted version of MPI_Session_comm_from_group function which can handle the case where not all involved processes are initialized yet (as assumed in code example) * ------------------------------------------------------------------------------------------------------------------------------- * * ************* * CODE EXAMPLE: * ************* */ int main(){ MPI_Session_init(MPI_INFO_NULL, MPI_ERROR_RETURNS, &session); // get the session info MPI_Session_get_info(session, &info); // get the default pset, i.e. the PSet containing the processes "created by same command / set operation" MPI_Info_get(info, MPI_SESSION_PSET_DEFAULT, MPI_PSET_MAX_NAME_LEN, default_pset, &flag); // Get the "MAIN_PSET" Attribute cached on the default PSet (by application in resource change request) MPI_Session_Get_Pset_info(session, default_pset, &default_pset_info); MPI_Info_get(default_pset_info, "MAIN_PSET", MPI_PSET_MAX_NAME_LEN, main_pset, &flag); // If this is not a dynamic process there is no "MAIN_PSET" attribute on default Pset (mpi://world), so the default PSet is the main PSet if (!flag){ strcpy(main_pset, default_pset); } /* Check if this is the primary process of PSet. In this example, the 'primary process' of the main_pset requests resource changes*/ MPI_Session_Get_Pset_info(session, main_pset, &main_pset_info); MPI_Info_get(main_pset_info, MPI_PSET_IS_PRIMARY_PROC, &primary_proc_flag, &flag); // Pset --> communicator MPI_Session_group_from_pset(main_pset, &group); MPI_Comm_create_from_group(group, &comm); /* MAIN LOOP */ while(1 /* work */){ /* * Application dependent load: * Possible a balancing and work step */ rebalance_step(/* */); /*...;*/ work_step(); /* REQUEST RESOURCE CHANGE */ if (primary_process_flag && /* need to request a resource change */){ MPI_rc_op_handle op_handles[2]; // NEW TYPE MPI_Info add_info, union_info; // info objects for specifying details of set operations (MPI_Info_create omitted for the sake of brevity) MPI_Info new_pset_attributes[2]; // info objects for specifying attributes to be cached on new PSets (MPI_Info_create omitted for the sake of brevity) /*********************************** * create the ADD operation handle * ***********************************/ MPI_Info_set(add_info, MPI_NUM_PROCS, "8"); // Set info for 'ADD' (In this example we request 8 new procs) MPI_Info_set(add_info, MPI_PSET_LABEL, "label://add_pset"); // Label for the 'ADD-PSet' (we need this to reference the new set in the union operation) // NEW API: Create a resource change operation handle MPI_Session_create_rc_op_handle( MPI_RC_ADD, // IN: The operation to create (would be MPI_RC_SUB when we remove processes) add_info, // IN: Info object containing parameters of the operation &op_handles[0] // OUT: A MPI_rc_op_handle (Used in MPI_Session_request_res_change) ); /************************************* * create the UNION operation handle * *************************************/ MPI_Info_set(union_info, MPI_UNION_PSET1, main_pset); MPI_Info_set(union_info, MPI_UNION_PSET2, "label://add_pset"); MPI_Info_set(union_info, MPI_PSET_LABEL, "label://union_pset"); // Label for 'UNION-PSet' MPI_Session_create_rc_op_handle(MPI_RC_UNION, union_info, &op_handles[1]); // (would be MPI_RC_DIFFERENCE when we remove processes) /*********************************** * Send the REQUEST to the RTE * ***********************************/ // Set Attributes for Resource Change PSets MPI_Info_set(new_pset_attributes[0], "MAIN_PSET", "label://union_pset"); // 'MAIN_PSET' attribute to be cached on 'ADD-PSet' (which is the default PSet of dynamic processes) new_pset_attributes[1] = MPI_INFO_NULL; // No Attributes cached on 'UNION-PSet' // NEW API: Send a resource change request to the RTE MPI_Session_request_res_change( 2, // IN: Number of operations to be performed by this request main_pset, // IN: The name of the PSet, this res change is associated with op_handles, // IN: The MPI_rc_op_handles describing the operations of the request new_pset_attributes // IN: The MPI_Info object(s) containing the attributes for the new PSets ); } /* QUERY RESOURCE CHANGE */ if (/* Ready to receive resource change, e.g. every 10th iteration */){ /* Receive the PSets created by this res. change and find the one which caches the 'MAIN_PSET' attribute */ // NEW API MPI_Session_Dyn_Recv_res_change( main_pset, // IN: The name for which resource change information should be queried main_pset, // IN: The name of the PSet, across which this query is collective/consistant (could be mpi://self if only one process does the lookup and then bcasts this info) rc_psets, // OUT: (char**) array of PSet names, which were created by this res. change &num_psets // OUT: The number of PSets created by this res. change (0 if no res change) ); if(num_psets > 0){ // If there was a resource change /* Find the new main PSet. This information is cached on one of the received rc_psets*/ for(int i = 0; i < num_psets && !flag; i++){ // Check for 'MAIN PSET' attribute MPI_Session_Get_Pset_info(session, rc_psets[i], &info); MPI_Info_get(info, "MAIN_PSET", MPI_PSET_MAX_NAME_LEN, new_main_pset, &flag); if(flag){ // We have found the name of the new main pset // Check if this process is included in new main PSet. If not, it needs to finalize MPI_Session_Get_Pset_info(session, new_main_pset, &main_info); MPI_Info_get(main_info, "MPI_PSET_IS_PROC_INCLUDED", sizeof(incl_flag), &incl_flag, &flag2); if(!incl_flag){ goto: Finalization } // Check if this process is the primary process of the new main PSet MPI_Info_get(main_info, "MPI_PSET_IS_PRIMARY_PROC", &primary_proc_flag); // Pset --> communicator MPI_Session_group_from_pset(new_main_pset, &group); MPI_Comm_create_from_group(group, &comm); strcpy(main_pset, new_main_pset, ...); } } } } } // END OF MAIN LOOP Finalization: MPI_Session_finalize(); return 0; }