Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

RKTask.cc

Go to the documentation of this file.
00001 /*
00002  * RKTask.cc
00003  *
00004  * Copyright (c) 2003, 2004 The University of Utah and the Flux Group.
00005  * All rights reserved.
00006  *
00007  * This file is licensed under the terms of the GNU Public License.  
00008  * See the file "license.terms" for restrictions on redistribution 
00009  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
00010  */
00011 
00012 /**
00013  * @file RKTask.cc
00014  *
00015  * Implementation of the RKTask class.
00016  */
00017 
00018 #include "config.h"
00019 
00020 #include <string.h>
00021 
00022 #include <iostream>
00023 #include <fstream>
00024 #include <iomanip>
00025 
00026 #include <assert_pp.h>
00027 #include <time_util.h>
00028 #include <instrumentation.h>
00029 
00030 #include "RKTask.hh"
00031 
00032 #include "rk_util.h"
00033 
00034 using namespace std;
00035 
00036 #define INSTR_rktask_change_cpu LRTIME_INSTR
00037 #define INSTR_rktask_change_cpu_data "rktask_change_cpu", "The wall clock time needed to run ChangeTaskCPU"
00038 
00039 #if defined(INSTR_rktask_change_cpu_data)
00040 static struct iPoint INSTR_rktask_change_cpu_point = {
00041     INSTR_rktask_change_cpu_data
00042 };
00043 #endif
00044 
00045 #if !defined(__XSTRING)
00046 /**
00047  * Convert a macro argument to a string.
00048  *
00049  * @param x The macro to expand to a string.
00050  */
00051 #define __XSTRING(x) __STRING(x)
00052 #endif
00053 
00054 /**
00055  * "Repair" the system by deleting any resource sets that have a CPU reserve
00056  * but no processes.
00057  */
00058 static void rktRepairResourceSets(void)
00059 {
00060 #define MAX_RK_SETS 128
00061     static rk_resource_set_t rk_sets[MAX_RK_SETS];
00062     
00063     unsigned int lpc, actual;
00064 
00065     actual = rk_resource_sets_get_list(rk_sets, MAX_RK_SETS);
00066     for( lpc = 0; lpc < actual; lpc++ )
00067     {
00068         int proc_count = rk_resource_set_get_num_procs(rk_sets[lpc]);
00069         rk_reserve_t cr = rk_resource_set_get_cpu_rsv(rk_sets[lpc]);
00070         
00071         if( (proc_count == 0) && (cr != NULL_RESERVE) )
00072         {
00073             rk_resource_set_destroy(rk_sets[lpc]);
00074             rk_sets[lpc] = NULL_RESOURCE_SET;
00075         }
00076     }
00077 #undef MAX_RK_SETS
00078 }
00079 
00080 RKTask::RKTask(const Broker::TaskParameters &tp)
00081     throw (CORBA::SystemException,
00082            Broker::DuplicateTaskParameter,
00083            Broker::InvalidTaskParameter,
00084            Broker::MissingTaskParameter)
00085 {
00086     unsigned int lpc;
00087 
00088     gettimeofday(&this->rkt_StartTime, NULL);
00089     this->rkt_LastReservationLog = this->rkt_StartTime;
00090     this->rkt_ReservationLog = NULL;
00091     
00092     memset(&this->rkt_CPUReserveSpec, 0, sizeof(this->rkt_CPUReserveSpec));
00093     this->rkt_CPUReserveSpec.compute_time = microsec_to_timespec(100);
00094     this->rkt_CPUReserve = NULL_RESERVE;
00095 
00096     /* Process the arguments */
00097     for( lpc = 0; lpc < tp.length(); lpc++ )
00098     {
00099         if( strcasecmp(tp[lpc].name.in(), "name") == 0 )
00100         {
00101             const char *name;
00102 
00103             if( this->rkt_Name != NULL )
00104             {
00105                 throw Broker::DuplicateTaskParameter("name");
00106             }
00107             else if( tp[lpc].value >>= name )
00108             {
00109                 if( strlen(name) >= RK_NAME_LEN )
00110                 {
00111                     throw Broker::InvalidTaskParameter(
00112                         "'name' is too long, only "
00113                         __XSTRING(RK_NAME_LEN)
00114                         " characters are allowed",
00115                         tp[lpc]);
00116                 }
00117                 else
00118                 {
00119                     this->rkt_Name = name;
00120                 }
00121             }
00122             else
00123             {
00124                 throw Broker::InvalidTaskParameter("'name' not a string",
00125                                                    tp[lpc]);
00126             }
00127         }
00128         else if( (strcasecmp(tp[lpc].name.in(), "res_log") == 0) ||
00129                  (strcasecmp(tp[lpc].name.in(), "res-log") == 0) ||
00130                  (strcasecmp(tp[lpc].name.in(), "res log") == 0) )
00131         {
00132             const char *res_log;
00133             
00134             if( this->rkt_ReservationLog != NULL )
00135             {
00136                 throw Broker::DuplicateTaskParameter("res log");
00137             }
00138             else if( tp[lpc].value >>= res_log )
00139             {
00140                 this->rkt_ReservationLog = new ofstream(res_log);
00141                 (*this->rkt_ReservationLog) << setfill('0');
00142                 (*this->rkt_ReservationLog)
00143                     << "# start: "
00144                     << (long)this->rkt_StartTime.tv_sec
00145                     << "."
00146                     << setw(6) << (long)this->rkt_StartTime.tv_usec
00147                     << endl;
00148             }
00149             else
00150             {
00151                 throw Broker::InvalidTaskParameter("'res log' not a string",
00152                                                    tp[lpc]);
00153             }
00154         }
00155     }
00156     
00157     /* Make sure we have everything we need. */
00158     if( this->rkt_Name == NULL )
00159     {
00160         throw Broker::MissingTaskParameter("name");
00161     }
00162 }
00163 
00164 RKTask::~RKTask()
00165 {
00166     if( !CORBA::is_nil(this->rkt_Manager.in()) )
00167     {
00168         this->EndCPUScheduling();
00169     }
00170     if( this->rkt_ReservationLog != NULL )
00171     {
00172         delete this->rkt_ReservationLog;
00173     }
00174 }
00175 
00176 char *RKTask::Name(void)
00177     throw (CORBA::SystemException)
00178 {
00179     CORBA::String_var retval;
00180 
00181     retval = this->rkt_Name;
00182     return( retval._retn() );
00183 }
00184 
00185 CORBA::ULong RKTask::Period(void)
00186     throw (CORBA::SystemException)
00187 {
00188     CORBA::ULong retval;
00189 
00190     retval = timespec_to_microsec(&this->rkt_CPUReserveSpec.period);
00191     return( retval );
00192 }
00193 
00194 CORBA::ULong RKTask::Deadline(void)
00195     throw (CORBA::SystemException)
00196 {
00197     CORBA::ULong retval;
00198 
00199     retval = timespec_to_microsec(&this->rkt_CPUReserveSpec.deadline);
00200     return( retval );
00201 }
00202 
00203 void RKTask::SetManager(Broker::Manager_ptr manager)
00204     throw (CORBA::SystemException)
00205 {
00206     this->rkt_Manager = Broker::Manager::_duplicate(manager);
00207 }
00208 
00209 void RKTask::BeginCPUScheduling(const Broker::ScheduleParameters &cs)
00210     throw (CORBA::SystemException,
00211            Broker::DuplicateScheduleParameter,
00212            Broker::InvalidScheduleParameter,
00213            Broker::MissingScheduleParameter)
00214 {
00215     CORBA::ULongLong start = 0, period = ~0, deadline = ~0;
00216     rk_reserve_mode_t rsv_mode = RSV_SOFT;
00217     unsigned int lpc;
00218     const char *str;
00219     pid_t pid = -1;
00220     
00221     if( this->rkt_CPUReserve != NULL_RESERVE )
00222     {
00223         throw CORBA::BAD_INV_ORDER();
00224     }
00225     
00226     /* Process the arguments. */
00227     for( lpc = 0; lpc < cs.length(); lpc++ )
00228     {
00229         if( strcasecmp(cs[lpc].name.in(), "reserve-mode") == 0 )
00230         {
00231             const char *str;
00232 
00233             if( cs[lpc].value >>= str )
00234             {
00235                 if( strcasecmp(str, "soft") == 0 )
00236                 {
00237                     rsv_mode = RSV_SOFT;
00238                 }
00239                 else if( strcasecmp(str, "hard") == 0 )
00240                 {
00241                     rsv_mode = RSV_HARD;
00242                 }
00243                 else
00244                 {
00245                     throw Broker::InvalidScheduleParameter(
00246                         "'reserve-mode' not 'hard' or 'soft'", cs[lpc]);
00247                 }
00248             }
00249             else
00250             {
00251                 throw Broker::InvalidScheduleParameter(
00252                         "'reserve-mode' not a string", cs[lpc]);
00253             }
00254         }
00255         else if( strcasecmp(cs[lpc].name.in(), "start") == 0 )
00256         {
00257             if( ((cs[lpc].value >>= str) && string_to_microsec(&start, str)) )
00258             {
00259             }
00260             else
00261             {
00262                 throw Broker::InvalidScheduleParameter("'start' is not a time",
00263                                                        cs[lpc]);
00264             }
00265         }
00266         else if( strcasecmp(cs[lpc].name.in(), "pid") == 0 )
00267         {
00268             CORBA::Long c_pid;
00269             const char *str;
00270 
00271             if( pid != -1 )
00272             {
00273                 throw Broker::DuplicateScheduleParameter("pid");
00274             }
00275             else if( cs[lpc].value >>= c_pid )
00276             {
00277                 pid = c_pid;
00278             }
00279             else if( (cs[lpc].value >>= str) &&
00280                      (sscanf(str, "%d", &pid) == 1) )
00281             {
00282             }
00283             else
00284             {
00285                 throw Broker::InvalidScheduleParameter("'pid' not a long",
00286                                                        cs[lpc]);
00287             }
00288             if( pid < 0 )
00289             {
00290                 pid = -1;
00291                 throw Broker::InvalidScheduleParameter("'pid' not a long",
00292                                                        cs[lpc]);
00293             }
00294         }
00295         else if( strcasecmp(cs[lpc].name.in(), "period") == 0 )
00296         {
00297             CORBA::ULong period_ul;
00298             
00299             if( period != ~0ULL )
00300             {
00301                 throw Broker::DuplicateScheduleParameter("period");
00302             }
00303             else if( cs[lpc].value >>= period_ul )
00304             {
00305                 period = period_ul;
00306             }
00307             else if( (cs[lpc].value >>= str) &&
00308                      string_to_microsec(&period, str) )
00309             {
00310             }
00311             else
00312             {
00313                 throw Broker::InvalidScheduleParameter(
00314                         "'period' is not a time",
00315                         cs[lpc]);
00316             }
00317         }
00318         else if( strcasecmp(cs[lpc].name.in(), "deadline") == 0 )
00319         {
00320             CORBA::ULong deadline_ul;
00321             
00322             if( deadline != ~0ULL )
00323             {
00324                 throw Broker::DuplicateScheduleParameter("deadline");
00325             }
00326             else if( cs[lpc].value >>= deadline_ul )
00327             {
00328                 deadline = deadline_ul;
00329             }
00330             else if( (cs[lpc].value >>= str) &&
00331                      string_to_microsec(&deadline, str) )
00332             {
00333             }
00334             else
00335             {
00336                 throw Broker::InvalidScheduleParameter(
00337                         "'deadline' is not a time",
00338                         cs[lpc]);
00339             }
00340         }
00341     }
00342     
00343     /* Make sure we have everything we need */
00344     if( period == ~0ULL )
00345     {
00346         throw Broker::MissingScheduleParameter("period");
00347     }
00348     if( pid == -1 )
00349     {
00350         throw Broker::MissingScheduleParameter("pid");
00351     }
00352     
00353     /* ... and derive the rest. */
00354     if( deadline == ~0ULL )
00355     {
00356         deadline = period;
00357     }
00358 
00359     /* Clean house first, then */
00360     rktRepairResourceSets();
00361 
00362     /* ... go ahead and find/create a resource set for the process. */
00363     if( (this->rkt_ResourceSet = rk_proc_get_rset(pid)) != NULL_RESOURCE_SET )
00364     {
00365         /* We'll just manage the existing resource set. */
00366         this->rkt_OwnsResourceSet = 0;
00367     }
00368     else if( (this->rkt_ResourceSet =
00369               rk_resource_set_get_by_name(this->rkt_Name.in())) !=
00370              NULL_RESOURCE_SET )
00371     {
00372         this->rkt_OwnsResourceSet = 0;
00373     }
00374     else if( (this->rkt_ResourceSet =
00375               rk_resource_set_create(this->rkt_Name.in())) !=
00376              NULL_RESOURCE_SET )
00377     {
00378         this->rkt_OwnsResourceSet = 1;
00379     }
00380     else
00381     {
00382         cerr << strerror(errno) << ": rk_resource_set_create" << endl;
00383         throw CORBA::NO_MEMORY(); // XXX
00384     }
00385 
00386     rk_reserve_t old_reserve;
00387     
00388     /* Check for an existing reserve. */
00389     if( (old_reserve = rk_resource_set_get_cpu_rsv(this->rkt_ResourceSet))
00390         != NULL_RESERVE )
00391     {
00392         if( rk_resource_set_get_num_procs(this->rkt_ResourceSet) == 0 )
00393         {
00394             /*
00395              * Assume something went horribly wrong.  Destroy the reserve
00396              * in preparation for adding our own reserve.
00397              */
00398             if( rk_cpu_reserve_delete(this->rkt_ResourceSet) == -1 )
00399             {
00400                 cerr << strerror(errno)
00401                      << ": rk_cpu_reserve_delete"
00402                      << endl;
00403             }
00404         }
00405         else
00406         {
00407             Broker::NamedValue nv;
00408             
00409             /* Someone else is using this set... */
00410             this->rkt_ResourceSet = NULL_RESOURCE_SET;
00411             nv.name = "name";
00412             nv.value <<= this->rkt_Name;
00413             throw Broker::InvalidScheduleParameter("name", nv);
00414         }
00415     }
00416     if( rk_resource_set_attach_process(this->rkt_ResourceSet, pid) == 0 )
00417     {
00418         /*
00419          * Joy, we'll attach a CPU reservation later in BeginCPUScheduling
00420          */
00421     }
00422     else if( errno != EBUSY )
00423     {
00424         /* No joy, something went wrong. */
00425         rk_resource_set_destroy(this->rkt_ResourceSet);
00426         this->rkt_ResourceSet = NULL_RESOURCE_SET;
00427         throw CORBA::NO_MEMORY(); // XXX
00428     }
00429     else
00430     {
00431         /* This process is already attached. */
00432     }
00433     
00434     /* XXX Do more checking here... */
00435     if( (this->rkt_CPUReserveSpec.compute_time.tv_sec == 0) &&
00436         (this->rkt_CPUReserveSpec.compute_time.tv_nsec == 0) )
00437     {
00438         this->rkt_CPUReserveSpec.compute_time = microsec_to_timespec(100);
00439     }
00440     this->rkt_CPUReserveSpec.period = microsec_to_timespec(period);
00441     this->rkt_CPUReserveSpec.deadline = microsec_to_timespec(deadline);
00442     this->rkt_CPUReserveSpec.reserve_type.sch_mode = rsv_mode;
00443     this->rkt_CPUReserveSpec.reserve_type.enf_mode = rsv_mode;
00444     this->rkt_CPUReserveSpec.reserve_type.rep_mode = rsv_mode;
00445     this->rkt_CPUReserveSpec.processor = RK_ANY_CPU;
00446 
00447     switch( int rc = rk_cpu_reserve_create(this->rkt_ResourceSet,
00448                                            &this->rkt_CPUReserve,
00449                                            &this->rkt_CPUReserveSpec) )
00450     {
00451     case 0:
00452         break;
00453     case -1:
00454         cerr << strerror(errno) << ":rk_cpu_reserve_create" << endl;
00455         throw Broker::InvalidScheduleParameter();
00456     default:
00457         cerr << rc << endl;
00458         throw Broker::Internal("Unhandled return value at: "
00459                                __FILE__
00460                                ":"
00461                                __STRING(__LINE__));
00462     }
00463 }
00464 
00465 void RKTask::EndCPUScheduling(void)
00466     throw (CORBA::SystemException)
00467 {
00468     if( this->rkt_CPUReserve == NULL_RESERVE )
00469     {
00470         throw CORBA::BAD_INV_ORDER();
00471     }
00472 
00473     if( this->rkt_ReservationLog != NULL )
00474     {
00475         struct timeval tv, st, diff;
00476         
00477         timersub(&this->rkt_LastReservationLog,
00478                  &this->rkt_StartTime,
00479                  &diff);
00480         st.tv_sec = 0;
00481         st.tv_usec = 0;
00482         gettimeofday(&tv, NULL);
00483         timersub(&tv, &this->rkt_StartTime, &diff);
00484         (*this->rkt_ReservationLog)
00485             << (long)diff.tv_sec
00486             << "."
00487             << setw(6) << (long)diff.tv_usec
00488             << " "
00489             << (long)st.tv_sec
00490             << "."
00491             << setw(6) << (long)st.tv_usec
00492             << endl;
00493         this->rkt_LastReservationLog = tv;
00494     }
00495     
00496     rk_cpu_reserve_delete(this->rkt_ResourceSet);
00497     this->rkt_CPUReserve = NULL_RESERVE;
00498     if( this->rkt_OwnsResourceSet )
00499     {
00500         rk_resource_set_destroy(this->rkt_ResourceSet);
00501     }
00502     this->rkt_ResourceSet = NULL_RESOURCE_SET;
00503 }
00504 
00505 CORBA::ULong RKTask::GetComputeTime(void)
00506     throw (CORBA::SystemException)
00507 {
00508     CORBA::ULong retval;
00509 
00510     retval = timespec_to_microsec(&this->rkt_CPUReserveSpec.compute_time);
00511     return( retval );
00512 }
00513 
00514 void RKTask::SetComputeTime(CORBA::ULong usecs)
00515     throw (CORBA::SystemException)
00516 {
00517     struct timespec old_ct;
00518 
00519     if( usecs == 0 )
00520     {
00521         throw CORBA::BAD_PARAM();
00522     }
00523     
00524     old_ct = this->rkt_CPUReserveSpec.compute_time;
00525     this->rkt_CPUReserveSpec.compute_time = microsec_to_timespec(usecs);
00526 
00527     if( this->rkt_CPUReserve != NULL_RESERVE )
00528     {
00529         switch( rk_cpu_reserve_ctl(this->rkt_ResourceSet,
00530                                    &this->rkt_CPUReserveSpec) )
00531         {
00532         case 0:
00533             if( this->rkt_ReservationLog != NULL )
00534             {
00535                 struct timeval tv, st, diff;
00536                 
00537                 timersub(&this->rkt_LastReservationLog,
00538                          &this->rkt_StartTime,
00539                          &diff);
00540                 st.tv_sec = usecs / 1000000;
00541                 st.tv_usec = usecs % 1000000;
00542                 gettimeofday(&tv, NULL);
00543                 timersub(&tv, &this->rkt_StartTime, &diff);
00544                 (*this->rkt_ReservationLog)
00545                     << (long)diff.tv_sec
00546                     << "."
00547                     << setw(6) << (long)diff.tv_usec
00548                     << " "
00549                     << (long)st.tv_sec
00550                     << "."
00551                     << setw(6) << (long)st.tv_usec
00552                     << endl;
00553                 this->rkt_LastReservationLog = tv;
00554             }
00555             break;
00556         case -1:
00557             switch( errno )
00558             {
00559             case EINVAL:
00560                 ensure(0);
00561                 break;
00562             case ENODEV:
00563                 ensure(0);
00564                 break;
00565             case ENOSPC:
00566                 cerr << "** SetComputeTime failed! "
00567                      << usecs
00568                      << endl;
00569                 break;
00570             case EFAULT:
00571                 ensure(0);
00572                 break;
00573             case EACCES:
00574                 cerr << "** No permission to change compute time? "
00575                      << usecs
00576                      << endl;
00577                 break;
00578             case ENOSYS:
00579                 ensure(0);
00580                 break;
00581             }
00582             this->rkt_CPUReserveSpec.compute_time = old_ct;
00583             throw CORBA::BAD_PARAM();
00584         }
00585     }
00586     else
00587     {
00588         /* We're not scheduling at the moment, just remember the value. */
00589         if( this->rkt_ReservationLog != NULL )
00590         {
00591             struct timeval tv, st, diff;
00592             
00593             timersub(&this->rkt_LastReservationLog,
00594                      &this->rkt_StartTime,
00595                      &diff);
00596             st.tv_sec = usecs / 1000000;
00597             st.tv_usec = usecs % 1000000;
00598             gettimeofday(&tv, NULL);
00599             timersub(&tv, &this->rkt_StartTime, &diff);
00600             (*this->rkt_ReservationLog)
00601                 << (long)diff.tv_sec
00602                 << "."
00603                 << setw(6) << (long)diff.tv_usec
00604                 << " "
00605                 << (long)st.tv_sec
00606                 << "."
00607                 << setw(6) << (long)st.tv_usec
00608                 << endl;
00609             this->rkt_LastReservationLog = tv;
00610         }
00611     }
00612 }
00613 
00614 void RKTask::ReportCPU(Broker::RealTimeTask_ptr rtt,
00615                        CORBA::ULong status,
00616                        CORBA::ULong advice)
00617     throw (CORBA::SystemException)
00618 {
00619     INSTR_rktask_change_cpu(&INSTR_rktask_change_cpu_point, {
00620         CORBA::ULong ct;
00621         
00622         if( CORBA::is_nil(this->rkt_Manager.in()) )
00623         {
00624             throw CORBA::BAD_INV_ORDER();
00625         }
00626         if( CORBA::is_nil(rtt) )
00627         {
00628             throw CORBA::BAD_PARAM();
00629         }
00630         if( advice == 0 )
00631         {
00632             throw CORBA::BAD_PARAM();
00633         }
00634         
00635         ct = timespec_to_microsec(&this->rkt_CPUReserveSpec.compute_time);
00636         this->rkt_Manager->ChangeTaskCPU(rtt, ct, status, advice);
00637     });
00638 }

Generated on Fri Oct 22 07:50:24 2004 for CPU Broker by  doxygen 1.3.9.1