diff options
| author | Nick Barnes | 2003-01-03 14:22:35 +0000 |
|---|---|---|
| committer | Nick Barnes | 2003-01-03 14:22:35 +0000 |
| commit | ca4af46f1dd7d22eda401bbfaa2609e41af7aa65 (patch) | |
| tree | 6f7ec5b952c31d78738e2196beee5747fae946fd /mps/code | |
| parent | c006b14a175be8e468b884eb73349046c9a22e0c (diff) | |
| download | emacs-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.c | 122 | ||||
| -rw-r--r-- | mps/code/mpm.h | 2 | ||||
| -rw-r--r-- | mps/code/mpmst.h | 4 | ||||
| -rw-r--r-- | mps/code/mps.h | 2 | ||||
| -rw-r--r-- | mps/code/mpsi.c | 6 | ||||
| -rw-r--r-- | mps/code/steptest.c | 13 |
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 | ||
| 567 | Bool 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. */ | ||
| 566 | static 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 | |||
| 608 | Bool 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 | ||
| 474 | extern Bool (ArenaStep)(Globals globals, double interval); | 474 | extern Bool (ArenaStep)(Globals globals, double interval, double multiplier); |
| 475 | extern void ArenaClamp(Globals globals); | 475 | extern void ArenaClamp(Globals globals); |
| 476 | extern void ArenaRelease(Globals globals); | 476 | extern void ArenaRelease(Globals globals); |
| 477 | extern void ArenaPark(Globals globals); | 477 | extern 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); | |||
| 240 | extern void mps_arena_park(mps_arena_t); | 240 | extern void mps_arena_park(mps_arena_t); |
| 241 | extern mps_res_t mps_arena_start_collect(mps_arena_t); | 241 | extern mps_res_t mps_arena_start_collect(mps_arena_t); |
| 242 | extern mps_res_t mps_arena_collect(mps_arena_t); | 242 | extern mps_res_t mps_arena_collect(mps_arena_t); |
| 243 | extern mps_bool_t mps_arena_step(mps_arena_t, double); | 243 | extern mps_bool_t mps_arena_step(mps_arena_t, double, double); |
| 244 | extern void mps_space_clamp(mps_space_t); | 244 | extern void mps_space_clamp(mps_space_t); |
| 245 | extern void mps_space_release(mps_space_t); | 245 | extern void mps_space_release(mps_space_t); |
| 246 | extern void mps_space_park(mps_space_t); | 246 | extern 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 | ||
| 364 | mps_bool_t mps_arena_step(mps_arena_t mps_arena, double time) | 364 | mps_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 | ||
| 276 | static void test_step(mps_arena_t arena) | 276 | static 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(); |