From: Willy Tarreau Date: Sat, 28 Apr 2007 20:40:08 +0000 (+0200) Subject: [MAJOR] changed TV_ETERNITY to ~0 instead of 0 X-Git-Tag: v1.3.10~30 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a6a6a93e5609e7aaab31af58aaada2221ef78ec4;p=thirdparty%2Fhaproxy.git [MAJOR] changed TV_ETERNITY to ~0 instead of 0 The fact that TV_ETERNITY was 0 was very awkward because it required that comparison functions handled the special case. Now it is ~0 and all comparisons are performed on unsigned values, so that it is naturally greater than any other value. A performance gain of about 2-5% has been noticed. --- diff --git a/include/common/time.h b/include/common/time.h index 36c5ca5a2b..cb1e40b5ae 100644 --- a/include/common/time.h +++ b/include/common/time.h @@ -26,7 +26,18 @@ #include #include -#define TIME_ETERNITY -1 +/* eternity when exprimed in timeval */ +#ifndef TV_ETERNITY +#define TV_ETERNITY (~0UL) +#endif + +/* eternity when exprimed in ms */ +#ifndef TV_ETERNITY_MS +#define TV_ETERNITY_MS (-1) +#endif + +#define TIME_ETERNITY (TV_ETERNITY_MS) + /* returns the lowest delay amongst and , and respects TIME_ETERNITY */ #define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old))) @@ -72,7 +83,6 @@ REGPRM2 int tv_cmp2_ms(const struct timeval *tv1, const struct timeval *tv2); */ REGPRM2 unsigned long tv_remain2(const struct timeval *tv1, const struct timeval *tv2); - /* sets to the current time */ REGPRM1 static inline struct timeval *tv_now(struct timeval *tv) { @@ -87,13 +97,13 @@ REGPRM1 static inline struct timeval *tv_now(struct timeval *tv) */ REGPRM2 static inline int tv_cmp(const struct timeval *tv1, const struct timeval *tv2) { - if (tv1->tv_sec < tv2->tv_sec) + if ((unsigned)tv1->tv_sec < (unsigned)tv2->tv_sec) return -1; - else if (tv1->tv_sec > tv2->tv_sec) + else if ((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec) return 1; - else if (tv1->tv_usec < tv2->tv_usec) + else if ((unsigned)tv1->tv_usec < (unsigned)tv2->tv_usec) return -1; - else if (tv1->tv_usec > tv2->tv_usec) + else if ((unsigned)tv1->tv_usec > (unsigned)tv2->tv_usec) return 1; else return 0; @@ -104,11 +114,11 @@ REGPRM2 static inline int tv_cmp(const struct timeval *tv1, const struct timeval */ REGPRM2 static inline int tv_cmp_ge(const struct timeval *tv1, const struct timeval *tv2) { - if (tv1->tv_sec > tv2->tv_sec) + if ((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec) return 1; - if (tv1->tv_sec < tv2->tv_sec) + if ((unsigned)tv1->tv_sec < (unsigned)tv2->tv_sec) return 0; - if (tv1->tv_usec >= tv2->tv_usec) + if ((unsigned)tv1->tv_usec >= (unsigned)tv2->tv_usec) return 1; return 0; } @@ -122,7 +132,7 @@ REGPRM2 static inline unsigned long tv_diff(const struct timeval *tv1, const str unsigned long ret; ret = (tv2->tv_sec - tv1->tv_sec) * 1000; - if (tv2->tv_usec > tv1->tv_usec) + if ((unsigned)tv2->tv_usec > (unsigned)tv1->tv_usec) ret += (tv2->tv_usec - tv1->tv_usec) / 1000; else ret -= (tv1->tv_usec - tv2->tv_usec) / 1000; @@ -142,7 +152,7 @@ REGPRM2 static inline unsigned long tv_remain(const struct timeval *tv1, const s return 0; /* event elapsed */ ret = (tv2->tv_sec - tv1->tv_sec) * 1000; - if (tv2->tv_usec > tv1->tv_usec) + if ((unsigned)tv2->tv_usec > (unsigned)tv1->tv_usec) ret += (tv2->tv_usec - tv1->tv_usec) / 1000; else ret -= (tv1->tv_usec - tv2->tv_usec) / 1000; @@ -151,42 +161,75 @@ REGPRM2 static inline unsigned long tv_remain(const struct timeval *tv1, const s /* - * zeroes a struct timeval + * sets a struct timeval to its highest value so that it can never happen + * note that only tv_usec is necessary to detect it since a tv_usec > 999999 + * is normally not possible. + * */ REGPRM1 static inline struct timeval *tv_eternity(struct timeval *tv) { - tv->tv_sec = tv->tv_usec = 0; + tv->tv_sec = tv->tv_usec = TV_ETERNITY; return tv; } /* - * returns 1 if tv is null, else 0 + * sets a struct timeval to 0 + * */ -REGPRM1 static inline int tv_iseternity(const struct timeval *tv) -{ - if ((tv->tv_sec | tv->tv_usec) == 0) - return 1; - else - return 0; +REGPRM1 static inline struct timeval *tv_zero(struct timeval *tv) { + tv->tv_sec = tv->tv_usec = 0; + return tv; } /* - * returns the first event between tv1 and tv2 into tvmin. - * a zero tv is ignored. tvmin is returned. + * returns non null if tv is [eternity], otherwise 0. */ -REGPRM3 static inline const struct timeval *tv_min(struct timeval *tvmin, - const struct timeval *tv1, - const struct timeval *tv2) -{ +#define tv_iseternity(tv) ((tv)->tv_usec == TV_ETERNITY) - if (tv_cmp2(tv1, tv2) <= 0) - *tvmin = *tv1; - else - *tvmin = *tv2; +/* + * returns non null if tv is [0], otherwise 0. + */ +#define tv_iszero(tv) (((tv)->tv_sec | (tv)->tv_usec) == 0) - return tvmin; -} +/* + * compares and : returns 1 if is before , otherwise 0. + * This should be very fast because it's used in schedulers. + * It has been optimized to return 1 (so call it in a loop which continues + * as long as tv1<=tv2) + */ + +#define tv_isbefore(tv1, tv2) \ + (unlikely((unsigned)(tv1)->tv_sec < (unsigned)(tv2)->tv_sec) ? 1 : \ + (unlikely((unsigned)(tv1)->tv_sec > (unsigned)(tv2)->tv_sec) ? 0 : \ + unlikely((unsigned)(tv1)->tv_usec < (unsigned)(tv2)->tv_usec))) + +/* + * returns the first event between and into . + * a zero tv is ignored. is returned. If is known + * to be the same as or , it is recommended to use + * tv_bound instead. + */ +#define tv_min(tvmin, tv1, tv2) ({ \ + if (tv_isbefore(tv1, tv2)) { \ + *tvmin = *tv1; \ + } \ + else { \ + *tvmin = *tv2; \ + } \ + tvmin; \ +}) + +/* + * returns the first event between and into . + * a zero tv is ignored. is returned. This function has been + * optimized to be called as tv_min(a,a,b) or tv_min(b,a,b). + */ +#define tv_bound(tv1, tv2) ({ \ + if (tv_isbefore(tv2, tv1)) \ + *tv1 = *tv2; \ + tv1; \ +}) #endif /* _COMMON_TIME_H */ diff --git a/src/proto_http.c b/src/proto_http.c index 00277f5ca7..86dbc999f0 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -524,7 +524,6 @@ static http_meth_t find_http_meth(const char *str, const int len) } - /* Processes the client and server jobs of a session task, then * puts it back to the wait queue in a clean state, or * cleans up its resources if it must be deleted. Returns @@ -546,14 +545,14 @@ int process_session(struct task *t) } while (fsm_resync); if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) { - struct timeval min1, min2; s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE; s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE; - tv_min(&min1, &s->req->rex, &s->req->wex); - tv_min(&min2, &s->rep->rex, &s->rep->wex); - tv_min(&min1, &min1, &s->req->cex); - tv_min(&t->expire, &min1, &min2); + t->expire = s->req->rex; + tv_min(&t->expire, &s->req->rex, &s->req->wex); + tv_bound(&t->expire, &s->req->cex); + tv_bound(&t->expire, &s->rep->rex); + tv_bound(&t->expire, &s->rep->wex); /* restore t to its place in the task list */ task_queue(t); diff --git a/src/task.c b/src/task.c index a0bf7af60b..a2ca0404bd 100644 --- a/src/task.c +++ b/src/task.c @@ -12,8 +12,8 @@ #include #include -#include #include +#include #include #include @@ -106,7 +106,7 @@ int wake_expired_tasks() tree64_foreach(&timer_wq, data, stack, slen) { task = LIST_ELEM(data, struct task *, qlist); - if (unlikely(tv_cmp_ge(&task->expire, &now) > 0)) { + if (!tv_isbefore(&task->expire, &now)) { next_time = tv_remain(&now, &task->expire); break; } diff --git a/src/time.c b/src/time.c index 1c5732f3eb..d94e364730 100644 --- a/src/time.c +++ b/src/time.c @@ -41,19 +41,21 @@ REGPRM3 struct timeval *tv_delayfrom(struct timeval *tv, const struct timeval *f */ REGPRM2 int tv_cmp_ms(const struct timeval *tv1, const struct timeval *tv2) { - if (tv1->tv_sec == tv2->tv_sec) { - if (tv2->tv_usec >= tv1->tv_usec + 1000) + if ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) { + if ((unsigned)tv2->tv_usec >= (unsigned)tv1->tv_usec + 1000) return -1; - else if (tv1->tv_usec >= tv2->tv_usec + 1000) + else if ((unsigned)tv1->tv_usec >= (unsigned)tv2->tv_usec + 1000) return 1; else return 0; } - else if ((tv2->tv_sec > tv1->tv_sec + 1) || - ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000))) + else if (((unsigned)tv2->tv_sec > (unsigned)tv1->tv_sec + 1) || + (((unsigned)tv2->tv_sec == (unsigned)tv1->tv_sec + 1) && + ((unsigned)tv2->tv_usec + 1000000 >= (unsigned)tv1->tv_usec + 1000))) return -1; - else if ((tv1->tv_sec > tv2->tv_sec + 1) || - ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000))) + else if (((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec + 1) || + (((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec + 1) && + ((unsigned)tv1->tv_usec + 1000000 >= (unsigned)tv2->tv_usec + 1000))) return 1; else return 0; @@ -61,45 +63,32 @@ REGPRM2 int tv_cmp_ms(const struct timeval *tv1, const struct timeval *tv2) /* * compares and : returns 0 if tv1 < tv2, 1 if tv1 >= tv2, - * considering that 0 is the eternity. + * assuming that TV_ETERNITY is greater than everything. */ REGPRM2 int tv_cmp_ge2(const struct timeval *tv1, const struct timeval *tv2) { - if (unlikely(tv_iseternity(tv1))) + if ((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec) return 1; - if (unlikely(tv_iseternity(tv2))) - return 0; /* same */ - - if (tv1->tv_sec > tv2->tv_sec) - return 1; - if (tv1->tv_sec < tv2->tv_sec) + if ((unsigned)tv1->tv_sec < (unsigned)tv2->tv_sec) return 0; - if (tv1->tv_usec >= tv2->tv_usec) + if ((unsigned)tv1->tv_usec >= (unsigned)tv2->tv_usec) return 1; return 0; } /* * compares and : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2, - * considering that 0 is the eternity. + * assuming that TV_ETERNITY is greater than everything. */ REGPRM2 int tv_cmp2(const struct timeval *tv1, const struct timeval *tv2) { - if (unlikely(tv_iseternity(tv1))) - if (unlikely(tv_iseternity(tv2))) - return 0; /* same */ - else - return 1; /* tv1 later than tv2 */ - else if (likely(tv_iseternity(tv2))) - return -1; /* tv2 later than tv1 */ - - if (tv1->tv_sec > tv2->tv_sec) + if ((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec) return 1; - else if (tv1->tv_sec < tv2->tv_sec) + else if ((unsigned)tv1->tv_sec < (unsigned)tv2->tv_sec) return -1; - else if (tv1->tv_usec > tv2->tv_usec) + else if ((unsigned)tv1->tv_usec > (unsigned)tv2->tv_usec) return 1; - else if (tv1->tv_usec < tv2->tv_usec) + else if ((unsigned)tv1->tv_usec < (unsigned)tv2->tv_usec) return -1; else return 0; @@ -107,7 +96,7 @@ REGPRM2 int tv_cmp2(const struct timeval *tv1, const struct timeval *tv2) /* * compares and modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2, - * considering that 0 is the eternity. + * assuming that TV_ETERNITY is greater than everything. */ REGPRM2 int tv_cmp2_ms(const struct timeval *tv1, const struct timeval *tv2) { @@ -119,19 +108,21 @@ REGPRM2 int tv_cmp2_ms(const struct timeval *tv1, const struct timeval *tv2) else if (tv_iseternity(tv2)) return -1; /* tv2 later than tv1 */ - if (tv1->tv_sec == tv2->tv_sec) { - if (tv1->tv_usec >= tv2->tv_usec + 1000) + if ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) { + if ((unsigned)tv1->tv_usec >= (unsigned)tv2->tv_usec + 1000) return 1; - else if (tv2->tv_usec >= tv1->tv_usec + 1000) + else if ((unsigned)tv2->tv_usec >= (unsigned)tv1->tv_usec + 1000) return -1; else return 0; } - else if ((tv1->tv_sec > tv2->tv_sec + 1) || - ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000))) + else if (((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec + 1) || + (((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec + 1) && + ((unsigned)tv1->tv_usec + 1000000 >= (unsigned)tv2->tv_usec + 1000))) return 1; - else if ((tv2->tv_sec > tv1->tv_sec + 1) || - ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000))) + else if (((unsigned)tv2->tv_sec > (unsigned)tv1->tv_sec + 1) || + (((unsigned)tv2->tv_sec == (unsigned)tv1->tv_sec + 1) && + ((unsigned)tv2->tv_usec + 1000000 >= (unsigned)tv1->tv_usec + 1000))) return -1; else return 0; @@ -153,7 +144,7 @@ REGPRM2 unsigned long tv_remain2(const struct timeval *tv1, const struct timeval return 0; /* event elapsed */ ret = (tv2->tv_sec - tv1->tv_sec) * 1000; - if (tv2->tv_usec > tv1->tv_usec) + if ((unsigned)tv2->tv_usec > (unsigned)tv1->tv_usec) ret += (tv2->tv_usec - tv1->tv_usec) / 1000; else ret -= (tv1->tv_usec - tv2->tv_usec) / 1000; @@ -180,7 +171,7 @@ REGPRM2 unsigned long tv_delta(const struct timeval *tv1, const struct timeval * tv2 = tmp; } ret = (tv1->tv_sec - tv2->tv_sec) * 1000; - if (tv1->tv_usec > tv2->tv_usec) + if ((unsigned)tv1->tv_usec > (unsigned)tv2->tv_usec) ret += (tv1->tv_usec - tv2->tv_usec) / 1000; else ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;