00001 #define QOS_DEBUG_LEVEL QOS_LEVEL_NODEBUG
00002 #include <linux/aquosa/qos_debug.h>
00003 #include <aquosa/qres_lib.h>
00004 #include <aquosa/qmgr_util.h>
00005
00006 #include <sys/time.h>
00007 #include <time.h>
00008 #include <stdio.h>
00009 #include <sched.h>
00010 #include <string.h>
00011
00012 #define NUM_JOBS 1000
00013
00014 #define C_MIN 10000ul
00015 #define C_MAX 20000ul
00016 #define APP_T 40000ul
00017
00018 #define Q_MIN 1000ul
00019 #define Q_MAX 2000ul
00020 #define SRV_P 4000ul
00021
00022
00023 unsigned long c[NUM_JOBS];
00024
00025
00026 unsigned long cr[NUM_JOBS];
00027
00028
00029 unsigned long cs[NUM_JOBS];
00030
00031
00032 signed long em[NUM_JOBS];
00033
00034
00035 signed long e[NUM_JOBS];
00036
00037
00038 unsigned long s[NUM_JOBS];
00039
00040
00041 unsigned long f[NUM_JOBS];
00042
00043
00044 unsigned long q[NUM_JOBS];
00045
00047 signed long timespec_sub_us(struct timespec *ts2, struct timespec *ts1) {
00048 return (ts2->tv_sec - ts1->tv_sec) * 1000000l + ((signed long) (ts2->tv_nsec - ts1->tv_nsec)) / 1000l;
00049 }
00050
00054 unsigned long count_and_wait(unsigned long duration_usec) {
00055 unsigned long counted_sheeps = 0;
00056 unsigned long elapsed_usecs;
00057 struct timespec ts1, ts2;
00058 qos_log_debug("Counting ? sheeps for %lu usecs ...", duration_usec);
00059 clock_gettime(CLOCK_MONOTONIC, &ts1);
00060 do {
00061 clock_gettime(CLOCK_MONOTONIC, &ts2);
00062 elapsed_usecs = timespec_sub_us(&ts2, &ts1);
00063 counted_sheeps++;
00064 } while (elapsed_usecs < duration_usec);
00065 qos_log_debug("Counted %lu sheeps in %lu usecs", counted_sheeps, elapsed_usecs);
00066 return counted_sheeps;
00067 }
00068
00073 unsigned long count(unsigned long sheeps) {
00074 unsigned long counted_sheeps = 0;
00075 unsigned long elapsed_usecs;
00076 struct timespec ts1, ts2;
00077
00078 qos_log_debug("Counting %lu sheeps for ? usecs ...", sheeps);
00079 clock_gettime(CLOCK_MONOTONIC, &ts1);
00080 do {
00081 clock_gettime(CLOCK_MONOTONIC, &ts2);
00082 elapsed_usecs = timespec_sub_us(&ts2, &ts1);
00083 counted_sheeps++;
00084 } while (counted_sheeps < sheeps);
00085 qos_log_debug("Counted %lu sheeps in %lu usecs", counted_sheeps, elapsed_usecs);
00086 return elapsed_usecs;
00087 }
00088
00089 int job = 0;
00090 struct timespec ts1;
00091
00092 qres_sid_t sid;
00093 qres_params_t params = {
00094 .Q_min = 0,
00095 .Q = 0,
00096 .P = SRV_P,
00097 .flags = 0,
00098 .timeout = 0
00099 };
00100
00101 struct timespec foo_ts;
00102
00103 int job_fn_setup(void *app_data) {
00104 struct timespec ts2;
00105 if (job == 0) {
00106 clock_gettime(CLOCK_MONOTONIC, &ts1);
00107 ts2 = ts1;
00108 }
00109
00110
00111 clock_gettime(CLOCK_MONOTONIC, &foo_ts);
00112 s[job] = timespec_sub_us(&ts2, &ts1);
00113 qos_log_debug("Starting job %d at %ld", job, s[job]);
00114
00115 count(cs[job]);
00116
00117
00118 clock_gettime(CLOCK_MONOTONIC, &ts2);
00119 f[job] = timespec_sub_us(&ts2, &ts1);
00120 qos_log_debug("Ending job %d at %lu", job, f[job]);
00121
00122
00123 cr[job] = f[job] - s[job];
00124
00125
00126 e[job] = f[job] - (job + 1) * APP_T;
00127
00128 job = (job + 1) % NUM_JOBS;
00129 params.Q = q[job];
00130 qos_chk_ok_do(qres_set_params(sid, ¶ms), exit(-1));
00131
00132 return job == 0;
00133 }
00134
00135 int job_fn(void *app_data) {
00136 struct timespec ts2;
00137 if (job == 0) {
00138 clock_gettime(CLOCK_MONOTONIC, &ts1);
00139 ts2 = ts1;
00140 }
00141
00142 clock_gettime(CLOCK_MONOTONIC, &ts2);
00143 s[job] = timespec_sub_us(&ts2, &ts1);
00144 qos_log_debug("Starting job %d at %ld", job, s[job]);
00145
00146 count(cs[job]);
00147
00148
00149 clock_gettime(CLOCK_MONOTONIC, &ts2);
00150 f[job] = timespec_sub_us(&ts2, &ts1);
00151 qos_log_debug("Ending job %d at %lu", job, f[job]);
00152
00153
00154 e[job] = f[job] - (job + 1) * APP_T;
00155
00156 job = (job + 1) % NUM_JOBS;
00157 params.Q = q[job];
00158 qos_chk_ok_do(qres_set_params(sid, ¶ms), exit(-1));
00159
00160 return job == 0;
00161 }
00162
00163 qos_rv start_periodic(qmgr_period_spec_t *p_ps, struct timespec *p_ts) {
00164 qos_rv rv = QOS_E_GENERIC;
00165
00166 p_ps->job_id = 1;
00167
00168
00169
00170 qos_log_debug("getting current time...");
00171 qos_chk_go(clock_gettime(CLOCK_MONOTONIC, &p_ps->deadline_ts) == 0,
00172 err, "clock_gettime() failed: %s", strerror(errno));
00173
00174 qos_log_debug("read time: %09lu.%09lu", p_ps->deadline_ts.tv_sec, p_ps->deadline_ts.tv_nsec);
00175
00176 p_ps->period_ts = *p_ts;
00177 timespec_add(&p_ps->deadline_ts, &p_ps->deadline_ts, &p_ps->period_ts);
00178 qos_log_debug("end of %dth period: %09lu.%09lu", p_ps->job_id,
00179 p_ps->deadline_ts.tv_sec, p_ps->deadline_ts.tv_nsec);
00180
00181 return QOS_OK;
00182
00183 err:
00184
00185 return rv;
00186 }
00187
00188 qos_rv wait_periodic(qmgr_period_spec_t *p_ps) {
00189 struct timespec now;
00190 struct timespec delta;
00191
00192 p_ps->job_id++;
00193
00194 if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) {
00195 qos_log_err("clock_gettime() failed: %s", strerror(errno));
00196 return QOS_E_GENERIC;
00197 }
00198
00199 timespec_sub(&delta, &p_ps->deadline_ts, &now);
00200 qos_log_debug("delta time: %09ld.%09lu", delta.tv_sec, delta.tv_nsec);
00201 if (delta.tv_sec > 0 || (delta.tv_sec == 0 && delta.tv_nsec > 0)) {
00202 qos_log_debug("Sleeping...");
00203 if (nanosleep(&delta, NULL) < 0) {
00204 qos_log_err("nanosleep() failed: %s", strerror(errno));
00205 return QOS_E_GENERIC;
00206 }
00207 } else
00208 qos_log_warn("We are late: not waiting...");
00209
00210 timespec_add(&p_ps->deadline_ts, &p_ps->deadline_ts, &p_ps->period_ts);
00211 qos_log_debug("end of %dth period: %09lu.%09lu", p_ps->job_id,
00212 p_ps->deadline_ts.tv_sec, p_ps->deadline_ts.tv_nsec);
00213
00214 return QOS_OK;
00215 }
00216
00217 int main(int argc, char *argv[]) {
00218 unsigned long sheeps_per_sec;
00219 unsigned long elapsed;
00220 int i;
00221 struct sched_param sp = {
00222 .sched_priority = 20
00223 };
00224
00225 long period_nsec = APP_T * 1000;
00226 struct timespec ts, ts_setup;
00227
00228 clock_getres(CLOCK_MONOTONIC, &ts);
00229 printf("# Requested period: %lu nsec\n", period_nsec);
00230 printf("# Timer resolution: %lu sec and %lu nsec\n", ts.tv_sec, ts.tv_nsec);
00231 unsigned long timer_res = ts.tv_sec * 1000000000ul + ts.tv_nsec;
00232 unsigned long new_period_nsec = period_nsec / timer_res * timer_res;
00233 while (new_period_nsec < period_nsec)
00234 new_period_nsec += timer_res;
00235 period_nsec = new_period_nsec;
00236 printf("# Real period: %lu nsec\n", period_nsec);
00237
00238 srand(time(NULL));
00239
00240 sheeps_per_sec = count_and_wait(1000000ul);
00241 elapsed = count(sheeps_per_sec);
00242 printf("# sheeps_per_sec = %lu\n", sheeps_per_sec);
00243 printf("# elapsed = %lu\n", elapsed);
00244
00245 qos_chk_do(sched_setscheduler(0, SCHED_RR, &sp) >= 0, perror("Could not gain RT priority"), "");
00246
00247 for (i = 0; i < NUM_JOBS; ++i) {
00248 c[i] = C_MIN + (unsigned long) ((C_MAX - C_MIN) * (rand() / (RAND_MAX + 1.0)));
00249 cs[i] = count_and_wait(c[i]);
00250 qos_log_debug("Random c_k=%lu requires %lu cycles", c[i], cs[i]);
00251 }
00252
00253
00254 for (i = 0; i < NUM_JOBS; ++i) {
00255 c[i] = C_MIN + (unsigned long) ((C_MAX - C_MIN) * (rand() / (RAND_MAX + 1.0)));
00256 cs[i] = count_and_wait(c[i]);
00257 qos_log_debug("Random c_k=%lu requires %lu cycles", c[i], cs[i]);
00258 }
00259
00260 sp.sched_priority = 0;
00261 qos_chk_do(sched_setscheduler(0, SCHED_OTHER, &sp) >= 0, perror("Could not drop RT priority"), "");
00262
00263
00264 for (i = 0; i < NUM_JOBS; ++i) {
00265 q[i] = Q_MIN + (qres_time_t) ((Q_MAX - Q_MIN) * (rand() / (RAND_MAX + 1.0)));
00266 qos_log_debug("Computed random budget: %lu", q[i]);
00267 }
00268
00269
00270 qos_chk_ok_do(qres_init(), exit(-1));
00271 params.Q = q[0];
00272 qos_chk_ok_do(qres_create_server(¶ms, &sid), exit(-1));
00273
00274 int eot;
00275 qmgr_period_spec_t ps;
00276
00277
00278 ts_setup = (struct timespec) {
00279 .tv_sec = 0,
00280 .tv_nsec = 1000
00281 };
00282
00283
00284 qos_chk_ok_exit(start_periodic(&ps, &ts_setup));
00285 eot = job_fn_setup(NULL);
00286 while (! eot) {
00287 qos_chk_ok_exit(wait_periodic(&ps));
00288 eot = job_fn_setup(NULL);
00289 }
00290
00291 qos_chk_ok_do(qres_attach_thread(sid, 0, 0), exit(-1));
00292
00293 ts = (struct timespec) {
00294 .tv_sec = period_nsec / 1000000000L,
00295 .tv_nsec = period_nsec % 1000000000L
00296 };
00297
00298
00299 qos_chk_ok_exit(start_periodic(&ps, &ts));
00300
00301 eot = job_fn(NULL);
00302 while (! eot) {
00303 qos_chk_ok_exit(wait_periodic(&ps));
00304 eot = job_fn(NULL);
00305 }
00306
00307 qos_chk_ok_do(qres_cleanup(), exit(-1));
00308
00309
00310 signed long e_k = 0;
00311 for (i = 0; i < NUM_JOBS; ++i) {
00312 em[i] = e_k = cr[i] * SRV_P / q[i] - APP_T + (e_k >= 0 ? e_k : 0);
00313 }
00314
00315 printf("#%11s%12s%12s%12s%12s%12s%12s%12s%12s%12s%12s\n", "Start", "Comp time", "Real Comp", "Period", "Cycles", "Budget", "Srv P", "End Time", "Real eps", "Ideal eps", "Diff");
00316 for (i = 0; i < NUM_JOBS; ++i) {
00317 printf("%12ld%12ld%12ld%12ld%12ld%12ld%12ld%12ld%12ld%12ld%12ld\n", s[i], c[i], cr[i], APP_T, cs[i], q[i], SRV_P, f[i], e[i], em[i], e[i] - em[i]);
00318 }
00319
00320 return 0;
00321 }