aboutsummaryrefslogtreecommitdiffstats
path: root/mps/code
diff options
context:
space:
mode:
authorNick Barnes2003-01-03 14:22:35 +0000
committerNick Barnes2003-01-03 14:22:35 +0000
commitca4af46f1dd7d22eda401bbfaa2609e41af7aa65 (patch)
tree6f7ec5b952c31d78738e2196beee5747fae946fd /mps/code
parentc006b14a175be8e468b884eb73349046c9a22e0c (diff)
downloademacs-ca4af46f1dd7d22eda401bbfaa2609e41af7aa65.tar.gz
emacs-ca4af46f1dd7d22eda401bbfaa2609e41af7aa65.zip
Second cut at opportunism.
Copied from Perforce Change: 37580 ServerID: perforce.ravenbrook.com
Diffstat (limited to 'mps/code')
-rw-r--r--mps/code/global.c122
-rw-r--r--mps/code/mpm.h2
-rw-r--r--mps/code/mpmst.h4
-rw-r--r--mps/code/mps.h2
-rw-r--r--mps/code/mpsi.c6
-rw-r--r--mps/code/steptest.c13
6 files changed, 71 insertions, 78 deletions
diff --git a/mps/code/global.c b/mps/code/global.c
index 39745fb90c8..db4a9f2fd0d 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -185,9 +185,7 @@ Bool GlobalsCheck(Globals arenaGlobals)
185 185
186 CHECKL(arena->tracedSize >= 0.0); 186 CHECKL(arena->tracedSize >= 0.0);
187 CHECKL(arena->tracedTime >= 0.0); 187 CHECKL(arena->tracedTime >= 0.0);
188 CHECKL(arena->savedStepTime >= 0.0); 188 CHECKL(arena->lastWorldCollect >= 0);
189 CHECKL(arena->lastStep >= 0);
190 CHECKL(arena->lastCollected >= 0);
191 189
192 /* can't write a check for arena->epoch */ 190 /* can't write a check for arena->epoch */
193 191
@@ -269,9 +267,7 @@ Res GlobalsInit(Globals arenaGlobals)
269 arena->flippedTraces = TraceSetEMPTY; /* <code/trace.c> */ 267 arena->flippedTraces = TraceSetEMPTY; /* <code/trace.c> */
270 arena->tracedSize = 0.0; 268 arena->tracedSize = 0.0;
271 arena->tracedTime = 0.0; 269 arena->tracedTime = 0.0;
272 arena->savedStepTime = 0.0; 270 arena->lastWorldCollect = mps_clock();
273 arena->lastStep = mps_clock();
274 arena->lastCollected = mps_clock();
275 arena->insideShield = FALSE; /* <code/shield.c> */ 271 arena->insideShield = FALSE; /* <code/shield.c> */
276 arena->shCacheI = (Size)0; 272 arena->shCacheI = (Size)0;
277 arena->shCacheLimit = (Size)1; 273 arena->shCacheLimit = (Size)1;
@@ -558,13 +554,58 @@ void ArenaPoll(Globals globals)
558 554
559 globals->insidePoll = TRUE; 555 globals->insidePoll = TRUE;
560 556
561 (void)ArenaStep(globals, 0.0); 557 (void)ArenaStep(globals, 0.0, 0.0);
562 558
563 globals->insidePoll = FALSE; 559 globals->insidePoll = FALSE;
564} 560}
565#endif 561#endif
566 562
567Bool ArenaStep(Globals globals, double interval) 563/* Work out whether we have enough time here to collect the world,
564 * and whether much time has passed since the last time we did that
565 * opportunistically. */
566static Bool arenaShouldCollectWorld(Arena arena,
567 double interval,
568 double multiplier,
569 Word now,
570 Word clocks_per_sec)
571{
572 double scanRate;
573 Size arenaSize;
574 double arenaScanTime;
575 double sinceLastWorldCollect;
576
577 /* don't collect the world if we're not given any time */
578 if ((interval > 0.0) && (multiplier > 0.0)) {
579 /* don't collect the world if we're already collecting. */
580 if (arena->busyTraces == TraceSetEMPTY) {
581 /* don't collect the world if it's very small */
582 arenaSize = ArenaCommitted(arena) - ArenaSpareCommitted(arena);
583 if (arenaSize > 1000000) {
584 /* how long would it take to collect the world? */
585 if ((arena->tracedSize > 1000000.0) &&
586 (arena->tracedTime > 1.0))
587 scanRate = arena->tracedSize / arena->tracedTime;
588 else
589 scanRate = 25000000.0; /* a reasonable default. */
590 arenaScanTime = arenaSize / scanRate;
591 arenaScanTime += 0.1; /* for overheads. */
592
593 /* how long since we last collected the world? */
594 sinceLastWorldCollect = ((now - arena->lastWorldCollect) /
595 (double) clocks_per_sec);
596 /* have to be offered enough time, and it has to be a long time
597 * since we last did it. */
598 if ((interval * multiplier > arenaScanTime) &&
599 sinceLastWorldCollect > arenaScanTime * 10.0) {
600 return TRUE;
601 }
602 }
603 }
604 }
605 return FALSE;
606}
607
608Bool ArenaStep(Globals globals, double interval, double multiplier)
568{ 609{
569 double size; 610 double size;
570 Size scanned; 611 Size scanned;
@@ -575,16 +616,24 @@ Bool ArenaStep(Globals globals, double interval)
575 616
576 AVERT(Globals, globals); 617 AVERT(Globals, globals);
577 AVER(interval >= 0.0); 618 AVER(interval >= 0.0);
619 AVER(multiplier >= 0.0);
578 620
579 arena = GlobalsArena(globals); 621 arena = GlobalsArena(globals);
580 clocks_per_sec = mps_clocks_per_sec(); 622 clocks_per_sec = mps_clocks_per_sec();
581 623
582 start = mps_clock(); 624 start = mps_clock();
583 end = start + interval * clocks_per_sec; 625 end = start + (Word)(interval * clocks_per_sec);
584 AVER(end >= start); 626 AVER(end >= start);
585 627
586 stepped = FALSE; 628 stepped = FALSE;
587 629
630 if (arenaShouldCollectWorld(arena, interval, multiplier,
631 start, clocks_per_sec)) {
632 ArenaStartCollect(globals);
633 arena->lastWorldCollect = start;
634 stepped = TRUE;
635 }
636
588 /* loop while there is work to do and time on the clock. */ 637 /* loop while there is work to do and time on the clock. */
589 do { 638 do {
590 scanned = TracePoll(globals); 639 scanned = TracePoll(globals);
@@ -597,61 +646,6 @@ Bool ArenaStep(Globals globals, double interval)
597 646
598 if (stepped) { 647 if (stepped) {
599 arena->tracedTime += (now - start) / (double) clocks_per_sec; 648 arena->tracedTime += (now - start) / (double) clocks_per_sec;
600 arena->savedStepTime = 0.0;
601 arena->lastStep = now;
602 } else if (interval > 0.0) {
603 /* All the CPU time since we last took a sensible step has been
604 * spent in the mutator. If this is large, the mutator is busy
605 * and doing an opportunistic collect-world is not a good idea.
606 * But if it is small, and we have accumulated a lot of step time
607 * since then, then the mutator is offering us a lot of time in
608 * comparison to the amount of time it is taking, and can be
609 * considered idle for our purposes.
610 *
611 * Here 'large' and 'small' can be assessed by comparing amounts
612 * of time to the amount of time it would take to scan the arena.
613 *
614 * The problem here is spotting when we are idle. Suppose that
615 * the mutator was busy a while ago, and there was a collection: a
616 * non-trivial step. Then the mutator continued for a while but
617 * then went idle. The continuing calls to mps_arena_step()
618 * continue to save up time but it never looks as if the mutator
619 * is really idle.
620 *
621 * So we need a better heuristic. If we save up enough time, we
622 * can probably kick off a collection anyway, regardless of
623 * apparent mutator busyness.
624 */
625 double scanRate;
626 Size arenaSize;
627 double arenaScanTime;
628 double sinceLastStep;
629
630 arena->savedStepTime += interval;
631
632 if ((arena->tracedSize > 1000000.0) &&
633 (arena->tracedTime > 1.0))
634 scanRate = arena->tracedSize / arena->tracedTime;
635 else
636 scanRate = 25000000.0; /* a reasonable default. */
637
638 arenaSize = ArenaCommitted(arena) - ArenaSpareCommitted(arena);
639 arenaScanTime = arenaSize / scanRate;
640 if (arenaScanTime < 1.0)
641 arenaScanTime = 1.0; /* clamp below to avoid being too eager */
642 sinceLastStep = (now - arena->lastStep) / (double) clocks_per_sec;
643 if ((arena->lastStep > arena->lastCollected) &&
644 ((arena->savedStepTime > arenaScanTime * 4.0) ||
645 ((arena->savedStepTime > arenaScanTime) &&
646 ((sinceLastStep < arenaScanTime / 10.0))))) {
647 /* either we've accumulated masses of step time since the last
648 * step, or the mutator seems idle and we've accumulated quite a
649 * bit. */
650 ArenaStartCollect(globals);
651 arena->savedStepTime = 0.0;
652 arena->lastStep = now;
653 arena->lastCollected = now;
654 }
655 } 649 }
656 650
657 size = globals->fillMutatorSize; 651 size = globals->fillMutatorSize;
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index 851b17b3763..c2b88250774 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -471,7 +471,7 @@ extern void (ArenaPoll)(Globals globals);
471/* .nogc.why: ScriptWorks doesn't use MM-provided incremental GC, so */ 471/* .nogc.why: ScriptWorks doesn't use MM-provided incremental GC, so */
472/* doesn't need to poll when allocating. */ 472/* doesn't need to poll when allocating. */
473 473
474extern Bool (ArenaStep)(Globals globals, double interval); 474extern Bool (ArenaStep)(Globals globals, double interval, double multiplier);
475extern void ArenaClamp(Globals globals); 475extern void ArenaClamp(Globals globals);
476extern void ArenaRelease(Globals globals); 476extern void ArenaRelease(Globals globals);
477extern void ArenaPark(Globals globals); 477extern void ArenaPark(Globals globals);
diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h
index 2a7d68b28de..2518efff660 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -677,9 +677,7 @@ typedef struct ArenaStruct {
677 /* policy fields */ 677 /* policy fields */
678 double tracedSize; 678 double tracedSize;
679 double tracedTime; 679 double tracedTime;
680 double savedStepTime; 680 Word lastWorldCollect;
681 Word lastStep;
682 Word lastCollected;
683 681
684 RingStruct greyRing[RankLIMIT]; /* ring of grey segments at each rank */ 682 RingStruct greyRing[RankLIMIT]; /* ring of grey segments at each rank */
685 STATISTIC_DECL(Count writeBarrierHitCount); /* write barrier hits */ 683 STATISTIC_DECL(Count writeBarrierHitCount); /* write barrier hits */
diff --git a/mps/code/mps.h b/mps/code/mps.h
index 731ebe4925b..3a032e5d332 100644
--- a/mps/code/mps.h
+++ b/mps/code/mps.h
@@ -240,7 +240,7 @@ extern void mps_arena_release(mps_arena_t);
240extern void mps_arena_park(mps_arena_t); 240extern void mps_arena_park(mps_arena_t);
241extern mps_res_t mps_arena_start_collect(mps_arena_t); 241extern mps_res_t mps_arena_start_collect(mps_arena_t);
242extern mps_res_t mps_arena_collect(mps_arena_t); 242extern mps_res_t mps_arena_collect(mps_arena_t);
243extern mps_bool_t mps_arena_step(mps_arena_t, double); 243extern mps_bool_t mps_arena_step(mps_arena_t, double, double);
244extern void mps_space_clamp(mps_space_t); 244extern void mps_space_clamp(mps_space_t);
245extern void mps_space_release(mps_space_t); 245extern void mps_space_release(mps_space_t);
246extern void mps_space_park(mps_space_t); 246extern void mps_space_park(mps_space_t);
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index 58777f5cdd8..e8eda64e5b4 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -361,12 +361,14 @@ mps_res_t mps_arena_collect(mps_space_t mps_space)
361 return res; 361 return res;
362} 362}
363 363
364mps_bool_t mps_arena_step(mps_arena_t mps_arena, double time) 364mps_bool_t mps_arena_step(mps_arena_t mps_arena,
365 double interval,
366 double multiplier)
365{ 367{
366 Bool b; 368 Bool b;
367 Arena arena = (Arena)mps_arena; 369 Arena arena = (Arena)mps_arena;
368 ArenaEnter(arena); 370 ArenaEnter(arena);
369 b = ArenaStep(ArenaGlobals(arena), time); 371 b = ArenaStep(ArenaGlobals(arena), interval, multiplier);
370 ArenaLeave(arena); 372 ArenaLeave(arena);
371 return b; 373 return b;
372} 374}
diff --git a/mps/code/steptest.c b/mps/code/steptest.c
index 34b78a344e5..d9e6bf6fd9b 100644
--- a/mps/code/steptest.c
+++ b/mps/code/steptest.c
@@ -26,7 +26,7 @@
26#define objCOUNT 2000000 26#define objCOUNT 2000000
27#define clockSetFREQ 10000 27#define clockSetFREQ 10000
28#define multiStepFREQ 500000 28#define multiStepFREQ 500000
29#define multiStepSTEPS 100 29#define multiStepMULT 100
30 30
31#define genCOUNT 3 31#define genCOUNT 3
32#define gen1SIZE 750 /* kB */ 32#define gen1SIZE 750 /* kB */
@@ -273,11 +273,11 @@ static mps_addr_t make(void)
273 273
274/* call mps_arena_step() */ 274/* call mps_arena_step() */
275 275
276static void test_step(mps_arena_t arena) 276static void test_step(mps_arena_t arena, double multiplier)
277{ 277{
278 mps_bool_t res; 278 mps_bool_t res;
279 double t1 = my_clock(); 279 double t1 = my_clock();
280 res = mps_arena_step(arena, 0.1); 280 res = mps_arena_step(arena, 0.1, multiplier);
281 t1 = time_since(t1); 281 t1 = time_since(t1);
282 if (res) { 282 if (res) {
283 if (t1 > max_step_time) 283 if (t1 > max_step_time)
@@ -301,7 +301,7 @@ static void *test(void *arg, size_t s)
301 mps_chain_t chain; 301 mps_chain_t chain;
302 mps_root_t exactRoot, ambigRoot; 302 mps_root_t exactRoot, ambigRoot;
303 unsigned long objs; 303 unsigned long objs;
304 size_t i, j; 304 size_t i;
305 mps_message_t message; 305 mps_message_t message;
306 size_t live, condemned, not_condemned; 306 size_t live, condemned, not_condemned;
307 size_t messages; 307 size_t messages;
@@ -376,11 +376,10 @@ static void *test(void *arg, size_t s)
376 ++objs; 376 ++objs;
377 377
378 if (objs % step_frequencies[test_number] == 0) 378 if (objs % step_frequencies[test_number] == 0)
379 test_step(arena); 379 test_step(arena, 0.0);
380 380
381 if (objs % multiStepFREQ == 0) 381 if (objs % multiStepFREQ == 0)
382 for (j=0; j<multiStepSTEPS; ++j) 382 test_step(arena, multiStepMULT);
383 test_step(arena);
384 383
385 if (objs % clockSetFREQ == 0) 384 if (objs % clockSetFREQ == 0)
386 set_clock_timing(); 385 set_clock_timing();