00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <stdlib.h>
00014 #include <stdio.h>
00015 #include <string.h>
00016 #include <l4/sys/ipc.h>
00017 #include <l4/sys/types.h>
00018 #include <l4/cpu_reserve/utcb_stat.h>
00019 #include <l4/cpu_reserve/utcb_watch.h>
00020 #include <l4/env/errno.h>
00021 #include <l4/rt_mon/histogram.h>
00022 #include <l4/log/l4log.h>
00023 #include <l4/util/macros.h>
00024 #include <l4/util/util.h>
00025 #include <l4/thread/thread.h>
00026
00027 static void watch_thread(void*arg);
00028
00029
00030 typedef struct utcb_list_t{
00031 l4_threadid_t thread;
00032 l4cpu_reserve_utcb_t *utcb;
00033 int ts_count;
00034 rt_mon_histogram_t **hists;
00035 unsigned long period;
00036 unsigned long long release;
00037 int ts_num;
00038 char name[L4CPU_RESERVE_UTCB_NAME_LEN];
00039 struct utcb_list_t *next;
00040 } utcb_list_t;
00041
00042
00043 typedef enum watch_cmd_val_t {
00044 WATCH_CMD_INV,
00045 WATCH_CMD_ADD,
00046 WATCH_CMD_DEL,
00047 } watch_cmd_t;
00048
00049
00050 typedef struct{
00051 l4_threadid_t thread;
00052 l4cpu_reserve_utcb_t *utcb;
00053 char name[L4CPU_RESERVE_UTCB_NAME_LEN];
00054 unsigned maxtime;
00055 int ts_count;
00056 } watch_arg_t;
00057
00058
00059 static utcb_list_t *utcb_list;
00060
00061
00062 static l4_threadid_t watch_thread_id;
00063
00064
00065
00066
00067
00068
00069
00070 int l4cpu_reserve_utcb_watch_add(l4_threadid_t thread,
00071 l4cpu_reserve_utcb_t *utcb,
00072 const char*name,
00073 unsigned maxtime,
00074 int ts_count){
00075 l4_umword_t dummy;
00076 l4_msgdope_t result;
00077 int err, ans;
00078 watch_arg_t arg;
00079
00080 arg.thread = thread;
00081 arg.utcb = utcb;
00082 strncpy(arg.name, name, L4CPU_RESERVE_UTCB_NAME_LEN);
00083 arg.name[L4CPU_RESERVE_UTCB_NAME_LEN-1]=0;
00084 arg.maxtime = maxtime;
00085 arg.ts_count = ts_count;
00086
00087 if((err=l4_ipc_call(watch_thread_id, L4_IPC_SHORT_MSG,
00088 WATCH_CMD_ADD,
00089 (l4_umword_t)&arg,
00090 L4_IPC_SHORT_MSG, (l4_umword_t *)&ans, &dummy,
00091 L4_IPC_NEVER, &result))!=0) return err;
00092 return ans;
00093 }
00094
00095 int l4cpu_reserve_utcb_watch_del(const l4cpu_reserve_utcb_t *utcb){
00096 l4_umword_t dummy;
00097 l4_msgdope_t result;
00098 int err, ans;
00099
00100 if((err=l4_ipc_call(watch_thread_id, L4_IPC_SHORT_MSG,
00101 WATCH_CMD_DEL,
00102 (l4_umword_t)utcb,
00103 L4_IPC_SHORT_MSG, (l4_umword_t *)&ans, &dummy,
00104 L4_IPC_NEVER, &result))!=0) return err;
00105 return ans;
00106 }
00107
00108 int l4cpu_reserve_utcb_watch_init(int poll_interval){
00109 l4thread_t w;
00110
00111 if((w=l4thread_create_named(watch_thread, ".watcher",
00112 (void*)poll_interval,
00113 L4THREAD_CREATE_ASYNC))<0){
00114 l4env_perror("create watcher", -w);
00115 return w;
00116 }
00117 watch_thread_id = l4thread_l4_id(w);
00118 return 0;
00119 }
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 static int watch_add_utcb_do(watch_arg_t*arg){
00130 int err=0, i;
00131 utcb_list_t *l;
00132
00133 if(arg->ts_count==0) return -L4_EINVAL;
00134 if((l=calloc(sizeof(*l),1))==0) return -L4_ENOMEM;
00135
00136 l->thread = arg->thread;
00137 l->ts_count = arg->ts_count;
00138 strncpy(l->name, arg->name, L4CPU_RESERVE_UTCB_NAME_LEN);
00139
00140 if((l->hists = calloc(sizeof(rt_mon_histogram_t*),
00141 arg->ts_count))==0){
00142 err = -L4_ENOMEM;
00143 goto e_utcb;
00144 }
00145 for(i=0;i<arg->ts_count;i++){
00146 char buf[L4CPU_RESERVE_UTCB_NAME_LEN];
00147 if(arg->ts_count>2){
00148 snprintf(buf, sizeof(buf), l4util_idfmt"/%d",
00149 l4util_idstr(arg->thread), i);
00150 } else {
00151 snprintf(buf, sizeof(buf), "%s /%s",
00152 arg->name, i?"RT":"BE");
00153 }
00154 l->hists[i] = rt_mon_hist_create(0, arg->maxtime, 200, buf,
00155 "us", "cnt", RT_MON_TSC_TO_US_TIME);
00156 }
00157
00158 l->utcb = arg->utcb;
00159 l->next = utcb_list;
00160 utcb_list = l;
00161
00162 return 0;
00163
00164 e_utcb:
00165 free(l);
00166 return err;
00167 }
00168
00169
00170
00171 static int watch_del_utcb_do(const l4cpu_reserve_utcb_t *utcb){
00172 utcb_list_t *l, *o=0;
00173
00174 for(l=utcb_list; l; l=l->next){
00175 if(l->utcb==utcb){
00176
00177 int i;
00178 for(i=0; i<l->ts_count;i++){
00179 rt_mon_hist_free(l->hists[i]);
00180 }
00181 free(l->hists);
00182 if (o)
00183 o->next = l->next;
00184 else
00185 utcb_list = l->next;
00186 free(l);
00187 return 0;
00188 }
00189 o=l;
00190 }
00191 return -L4_ENOTFOUND;
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201 static void watch_insert_sample(utcb_list_t *l, int id, long time){
00202 rt_mon_hist_insert_data(l->hists[id], time, 1);
00203
00204
00205
00206
00207 }
00208
00209
00210
00211
00212
00213
00214
00215 static int watch_add_res_entry(utcb_list_t *l, int id,
00216 unsigned long long release,
00217 long time){
00218 int i;
00219
00220
00221 if(id>l->ts_count) return -1;
00222
00223 if(l->release!=release){
00224
00225 l->release = release;
00226 l->ts_num=0;
00227 l->period++;
00228 }
00229 for(i=l->ts_num; i<id; i++){
00230 if(i) watch_insert_sample(l, i, 0);
00231 }
00232 watch_insert_sample(l, id, time);
00233 if(id>l->ts_num) l->ts_num = id;
00234 return 0;
00235 }
00236
00237
00238
00239
00240
00241
00242
00243 static void watch_add_period_entry(utcb_list_t *l, int id,
00244 unsigned long long release,
00245 long time){
00246 int i;
00247
00248 if(watch_add_res_entry(l, id, release, time)) return;
00249
00250 for(i=l->ts_num+1; i<l->ts_count; i++){
00251 watch_insert_sample(l, i, 0);
00252 }
00253 l->ts_num = l->ts_count;
00254 }
00255
00256
00257
00258
00259
00260
00261
00262 static void watch_add_lost(utcb_list_t *l, int count){
00263 int i;
00264
00265 for(i=0;i<l->ts_count;i++){
00266 rt_mon_hist_insert_lost(l->hists[i], count);
00267 }
00268 }
00269
00270
00271
00272 static void print_sched_event(int id, l4cpu_reserve_utcb_elem_t*stat)
00273 __attribute__((unused));
00274 static void print_sched_event(int id, l4cpu_reserve_utcb_elem_t*stat){
00275 printf("(%2d): type=%s, id=%d, release=%d, used=%d\n",
00276 id, l4cpu_reserve_utcb_stat_itoa(stat->type), stat->id,
00277 (int)stat->release, (int)stat->left);
00278 }
00279
00280
00281
00282 static void watch_eval_utcbs(void){
00283 utcb_list_t *l;
00284 l4cpu_reserve_utcb_t *utcb;
00285 int i;
00286
00287 for(l=utcb_list; l; l=l->next){
00288 utcb = l->utcb;
00289 for(i = utcb->tail ; i!=utcb->head ;
00290 i = (i + 1) % L4CPU_RESERVE_UTCB_STAT_COUNT) {
00291
00292
00293
00294
00295 if(utcb->stat[i].release){
00296 switch(utcb->stat[i].type){
00297 case L4_UTCB_PERIOD_OVERRUN:
00298 case L4_UTCB_NEXT_PERIOD:
00299 watch_add_period_entry(l, utcb->stat[i].id,
00300 utcb->stat[i].release,
00301 utcb->stat[i].left);
00302 break;
00303 case L4_UTCB_RESERVATION_OVERRUN:
00304 case L4_UTCB_NEXT_RESERVATION:
00305 watch_add_res_entry(l, utcb->stat[i].id,
00306 utcb->stat[i].release,
00307 utcb->stat[i].left);
00308 break;
00309 }
00310 }
00311 }
00312 if(utcb->full){
00313 watch_add_lost(l, utcb->full);
00314 utcb->full=0;
00315 }
00316 utcb->tail = i;
00317 }
00318 }
00319
00320
00321
00322
00323
00324
00325 static void watch_thread(void*arg){
00326 int err=0;
00327 l4_msgdope_t result;
00328 l4_threadid_t sender;
00329 l4_umword_t dw1;
00330 watch_cmd_t cmd;
00331 l4_timeout_t to;
00332
00333 to = l4_timeout(L4_IPC_TIMEOUT_NEVER, l4util_micros2l4to((int)arg));
00334
00335 while(1){
00336 if(err==L4_IPC_RETIMEOUT) watch_eval_utcbs();
00337 err = l4_ipc_wait(&sender, L4_IPC_SHORT_MSG,
00338 (l4_umword_t*)&cmd, &dw1, to, &result);
00339 while(1){
00340 if(err) break;
00341 if(!l4_task_equal(sender, watch_thread_id)) break;
00342 switch(cmd){
00343 case WATCH_CMD_ADD:
00344 dw1=watch_add_utcb_do((watch_arg_t*)dw1);
00345 break;
00346 case WATCH_CMD_DEL:
00347 dw1=watch_del_utcb_do((l4cpu_reserve_utcb_t*)dw1);
00348 break;
00349 default:
00350 dw1=-L4_EINVAL;
00351 }
00352 err = l4_ipc_reply_and_wait(sender, L4_IPC_SHORT_MSG,
00353 dw1, 0,
00354 &sender,
00355 L4_IPC_SHORT_MSG,
00356 (l4_umword_t*)&cmd, &dw1,
00357 to, &result);
00358 }
00359 }
00360 }
00361