--- libev/ev.c 2008/05/06 23:42:16 1.234 +++ libev/ev.c 2008/05/07 14:45:17 1.235 @@ -761,6 +761,88 @@ /*****************************************************************************/ +/* + * at the moment we allow libev the luxury of two heaps, + * a small-code-size 2-heap one and a ~1.5kb larger 4-heap + * which is more cache-efficient. + * the difference is about 5% with 50000+ watchers. + */ +#define USE_4HEAP !EV_MINIMAL +#if USE_4HEAP + +#define HEAP0 3 /* index of first element in heap */ + +/* towards the root */ +void inline_speed +upheap (WT *heap, int k) +{ + WT w = heap [k]; + + for (;;) + { + int p = ((k - HEAP0 - 1) / 4) + HEAP0; + + if (p >= HEAP0 || heap [p]->at <= w->at) + break; + + heap [k] = heap [p]; + ev_active (heap [k]) = k; + k = p; + } + + heap [k] = w; + ev_active (heap [k]) = k; +} + +/* away from the root */ +void inline_speed +downheap (WT *heap, int N, int k) +{ + WT w = heap [k]; + WT *E = heap + N + HEAP0; + + for (;;) + { + ev_tstamp minat; + WT *minpos; + WT *pos = heap + 4 * (k - HEAP0) + HEAP0; + + // find minimum child + if (expect_true (pos +3 < E)) + { + (minpos = pos + 0), (minat = (*minpos)->at); + if (pos [1]->at < minat) (minpos = pos + 1), (minat = (*minpos)->at); + if (pos [2]->at < minat) (minpos = pos + 2), (minat = (*minpos)->at); + if (pos [3]->at < minat) (minpos = pos + 3), (minat = (*minpos)->at); + } + else + { + if (pos >= E) + break; + + (minpos = pos + 0), (minat = (*minpos)->at); + if (pos + 1 < E && pos [1]->at < minat) (minpos = pos + 1), (minat = (*minpos)->at); + if (pos + 2 < E && pos [2]->at < minat) (minpos = pos + 2), (minat = (*minpos)->at); + if (pos + 3 < E && pos [3]->at < minat) (minpos = pos + 3), (minat = (*minpos)->at); + } + + if (w->at <= minat) + break; + + ev_active (*minpos) = k; + heap [k] = *minpos; + + k = minpos - heap; + } + + heap [k] = w; + ev_active (heap [k]) = k; +} + +#else // 4HEAP + +#define HEAP0 1 + /* towards the root */ void inline_speed upheap (WT *heap, int k) @@ -797,21 +879,22 @@ if (c > N) break; - c += c < N && heap [c]->at > heap [c + 1]->at + c += c + 1 < N && heap [c]->at > heap [c + 1]->at ? 1 : 0; if (w->at <= heap [c]->at) break; heap [k] = heap [c]; - ev_active (heap [k]) = k; - + ((W)heap [k])->active = k; + k = c; } heap [k] = w; ev_active (heap [k]) = k; } +#endif void inline_size adjustheap (WT *heap, int N, int k) @@ -1488,9 +1571,9 @@ void inline_size timers_reify (EV_P) { - while (timercnt && ev_at (timers [1]) <= mn_now) + while (timercnt && ev_at (timers [HEAP0]) <= mn_now) { - ev_timer *w = (ev_timer *)timers [1]; + ev_timer *w = (ev_timer *)timers [HEAP0]; /*assert (("inactive timer on timer heap detected", ev_is_active (w)));*/ @@ -1503,7 +1586,7 @@ if (ev_at (w) < mn_now) ev_at (w) = mn_now; - downheap (timers, timercnt, 1); + downheap (timers, timercnt, HEAP0); } else ev_timer_stop (EV_A_ w); /* nonrepeating: stop timer */ @@ -1516,9 +1599,9 @@ void inline_size periodics_reify (EV_P) { - while (periodiccnt && ev_at (periodics [1]) <= ev_rt_now) + while (periodiccnt && ev_at (periodics [HEAP0]) <= ev_rt_now) { - ev_periodic *w = (ev_periodic *)periodics [1]; + ev_periodic *w = (ev_periodic *)periodics [HEAP0]; /*assert (("inactive timer on periodic heap detected", ev_is_active (w)));*/ @@ -1534,7 +1617,7 @@ ev_at (w) = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval; if (ev_at (w) - ev_rt_now <= TIME_EPSILON) ev_at (w) += w->interval; assert (("ev_periodic timeout in the past detected while processing timers, negative interval?", ev_at (w) > ev_rt_now)); - downheap (periodics, periodiccnt, 1); + downheap (periodics, periodiccnt, HEAP0); } else ev_periodic_stop (EV_A_ w); /* nonrepeating: stop timer */ @@ -1560,8 +1643,8 @@ } /* now rebuild the heap */ - for (i = periodiccnt >> 1; i--; ) - downheap (periodics, periodiccnt, i); + for (i = periodiccnt >> 1; --i; ) + downheap (periodics, periodiccnt, i + HEAP0); } #endif @@ -1706,14 +1789,14 @@ if (timercnt) { - ev_tstamp to = ev_at (timers [1]) - mn_now + backend_fudge; + ev_tstamp to = ev_at (timers [HEAP0]) - mn_now + backend_fudge; if (waittime > to) waittime = to; } #if EV_PERIODIC_ENABLE if (periodiccnt) { - ev_tstamp to = ev_at (periodics [1]) - ev_rt_now + backend_fudge; + ev_tstamp to = ev_at (periodics [HEAP0]) - ev_rt_now + backend_fudge; if (waittime > to) waittime = to; } #endif @@ -1893,10 +1976,10 @@ assert (("ev_timer_start called with negative timer repeat value", w->repeat >= 0.)); - ev_start (EV_A_ (W)w, ++timercnt); - array_needsize (WT, timers, timermax, timercnt + 1, EMPTY2); - timers [timercnt] = (WT)w; - upheap (timers, timercnt); + ev_start (EV_A_ (W)w, ++timercnt + HEAP0 - 1); + array_needsize (WT, timers, timermax, timercnt + HEAP0, EMPTY2); + timers [ev_active (w)] = (WT)w; + upheap (timers, ev_active (w)); /*assert (("internal timer heap corruption", timers [ev_active (w)] == w));*/ } @@ -1913,9 +1996,9 @@ assert (("internal timer heap corruption", timers [active] == (WT)w)); - if (expect_true (active < timercnt)) + if (expect_true (active < timercnt + HEAP0 - 1)) { - timers [active] = timers [timercnt]; + timers [active] = timers [timercnt + HEAP0 - 1]; adjustheap (timers, timercnt, active); } @@ -1965,10 +2048,10 @@ else ev_at (w) = w->offset; - ev_start (EV_A_ (W)w, ++periodiccnt); - array_needsize (WT, periodics, periodicmax, periodiccnt + 1, EMPTY2); - periodics [periodiccnt] = (WT)w; - upheap (periodics, periodiccnt); + ev_start (EV_A_ (W)w, ++periodiccnt + HEAP0 - 1); + array_needsize (WT, periodics, periodicmax, periodiccnt + HEAP0, EMPTY2); + periodics [ev_active (w)] = (WT)w; + upheap (periodics, ev_active (w)); /*assert (("internal periodic heap corruption", periodics [ev_active (w)] == w));*/ } @@ -1985,9 +2068,9 @@ assert (("internal periodic heap corruption", periodics [active] == (WT)w)); - if (expect_true (active < periodiccnt)) + if (expect_true (active < periodiccnt + HEAP0 - 1)) { - periodics [active] = periodics [periodiccnt]; + periodics [active] = periodics [periodiccnt + HEAP0 - 1]; adjustheap (periodics, periodiccnt, active); }