Skip to content

Commit

Permalink
[GC] Reccord when the last GC cycle took place.
Browse files Browse the repository at this point in the history
  • Loading branch information
deadalnix committed Oct 16, 2024
1 parent 2edae16 commit eff1d1c
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 38 deletions.
120 changes: 120 additions & 0 deletions sdlib/core/stdc/time.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
module core.stdc.time;

import sys.posix.types;

extern(C):

enum clock_t CLOCKS_PER_SEC = 1000000;

// Identifier for system-wide realtime clock.
enum CLOCK_REALTIME = 0;
// Monotonic system-wide clock.
enum CLOCK_MONOTONIC = 1;
// High-resolution timer from the CPU.
enum CLOCK_PROCESS_CPUTIME_ID = 2;
// Thread-specific CPU-time clock.
enum CLOCK_THREAD_CPUTIME_ID = 3;
// Monotonic system-wide clock, not adjusted for frequency scaling.
enum CLOCK_MONOTONIC_RAW = 4;
// Identifier for system-wide realtime clock, updated only on ticks.
enum CLOCK_REALTIME_COARSE = 5;
// Monotonic system-wide clock, updated only on ticks.
enum CLOCK_MONOTONIC_COARSE = 6;
// Monotonic system-wide clock that includes time spent in suspension.
enum CLOCK_BOOTTIME = 7;
// Like CLOCK_REALTIME but also wakes suspended system.
enum CLOCK_REALTIME_ALARM = 8;
// Like CLOCK_BOOTTIME but also wakes suspended system.
enum CLOCK_BOOTTIME_ALARM = 9;
// Like CLOCK_REALTIME but in International Atomic Time.
enum CLOCK_TAI = 11;

// Flag to indicate time is absolute.
enum TIMER_ABSTIME = 1;

// TODO: timex, clock_adjtime

struct tm {
// Seconds. [0-60] (1 leap second)
int tm_sec;
// Minutes. [0-59]
int tm_min;
// Hours. [0-23]
int tm_hour;
// Day. [1-31]
int tm_mday;
// Month. [0-11]
int tm_mon;
// Year - 1900.
int tm_year;
// Day of week. [0-6]
int tm_wday;
// Days in year.[0-365]
int tm_yday;
// DST. [-1/0/1]
int tm_isdst;

// Seconds east of UTC.
c_long tm_gmtoff;
// Timezone abbreviation.
const char* tm_zone;
}

struct timespec {
// Seconds.
time_t tv_sec;

// XXX: Not sure what the right type is here,
// C headers are very confusing on that one.
// Nanoseconds.
__syscall_slong_t tv_nsec;
}

struct itimerspec {
timespec it_interval;
timespec it_value;
}

clock_t clock();

// Complains about redefinition of the module name.
// time_t time(time_t* __timer);

double difftime(time_t __time1, time_t __time0);

time_t mktime(tm* __tp);

// TODO: strftime, strptime, strftime_l, strptime_l

tm* gmtime(const time_t* __timer);
tm* localtime(const time_t* __timer);

// TODO: gmtime_r, localtime_r
// TODO: asctime, ctime
// TODO: asctime_r, ctime_r

void tzset();

// TODO: timegm, timelocal, dysize

int nanosleep(const timespec* __requested_time, timespec* __remaining);

int clock_getres(clockid_t __clock_id, timespec* __res);
int clock_gettime(clockid_t __clock_id, timespec* __tp);
int clock_settime(clockid_t __clock_id, const timespec* __tp);
int clock_nanosleep(clockid_t __clock_id, int __flags, const timespec* __req,
timespec* __rem);
int clock_getcpuclockid(pid_t __pid, clockid_t* __clock_id);

int timer_create(clockid_t __clock_id, sigevent* __evp, timer_t* __timerid);
int timer_delete(timer_t __timerid);
int timer_settime(timer_t __timerid, int __flags, const itimerspec* __value,
itimerspec* __ovalue);
int timer_gettime(timer_t __timerid, itimerspec* __value);
int timer_getoverrun(timer_t __timerid);

int timespec_get(timespec* __ts, int __base);
int timespec_getres(timespec* __ts, int __base);

tm* getdate(const char* __string);
int getdate_r(const char* __string, tm* __resbufp);
53 changes: 26 additions & 27 deletions sdlib/d/gc/collector.d
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ struct Collector {
return threadCache.emap;
}

bool maybeRunGCCycle(ref size_t delta, ref size_t target) {
return gCollectorState.maybeRunGCCycle(this, delta, target);
bool maybeRunGCCycle() {
return gCollectorState.maybeRunGCCycle(this);
}

void runGCCycle() {
Expand Down Expand Up @@ -110,50 +110,50 @@ private:
size_t baseline = DefaultHeapSize;
size_t peak = DefaultHeapSize;

/**
* Data about the last collection cycle.
*/
ulong lastCollectionStart;
ulong lastCollectionStop;

public:
bool maybeRunGCCycle(ref Collector collector, ref size_t delta,
ref size_t target) shared {
bool maybeRunGCCycle(ref Collector collector) shared {
// Do not unnecessarily create contention on this mutex.
if (!mutex.tryLock()) {
delta = 0;
target = 0;
return false;
}

scope(exit) mutex.unlock();
return (cast(CollectorState*) &this)
.maybeRunGCCycleImpl(collector, delta, target);
return (cast(CollectorState*) &this).maybeRunGCCycleImpl(collector);
}

private:
bool maybeRunGCCycleImpl(ref Collector collector, ref size_t delta,
ref size_t target) {
if (!needCollection(delta)) {
target = delta;
bool maybeRunGCCycleImpl(ref Collector collector) {
assert(mutex.isHeld(), "mutex not held!");

auto total = Arena.computeUsedPageCount();
if (total < nextTarget) {
return false;
}

collector.runGCCycleLocked();

target = updateTargetPageCount();
runGCCycle(collector);
return true;
}

bool needCollection(ref size_t delta) {
auto total = Arena.computeUsedPageCount();
void runGCCycle(ref Collector collector) {
assert(mutex.isHeld(), "mutex not held!");

if (total >= nextTarget) {
// How much did we overshoot?
delta = total - nextTarget;
return true;
}
import d.gc.time;
lastCollectionStart = getMonotonicTime();
scope(exit) updateTargetPageCount();

// How many more pages before we need a collection.
delta = nextTarget - total;
return false;
collector.runGCCycleLocked();
}

size_t updateTargetPageCount() {
void updateTargetPageCount() {
import d.gc.time;
lastCollectionStop = getMonotonicTime();

auto total = Arena.computeUsedPageCount();

// This creates a low pass filter.
Expand All @@ -179,7 +179,6 @@ private:
target = min(target, tpeak);

nextTarget = max(target, minHeapTarget);
return nextTarget - total;
}
}

Expand Down
4 changes: 1 addition & 3 deletions sdlib/d/gc/tcache.d
Original file line number Diff line number Diff line change
Expand Up @@ -596,11 +596,9 @@ private:
return;
}

size_t delta, target;

import d.gc.collector;
auto collector = Collector(&this);
auto didRun = collector.maybeRunGCCycle(delta, target);
auto didRun = collector.maybeRunGCCycle();

nextGCRun = allocated + BlockSize;
}
Expand Down
23 changes: 23 additions & 0 deletions sdlib/d/gc/time.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module d.gc.time;

import core.stdc.time;

enum ulong Microsecond = 10;
enum ulong Millisecond = 1000 * Microsecond;
enum ulong Second = 1000 * Millisecond;
enum ulong Minute = 60 * Second;
enum ulong Hour = 60 * Minute;
enum ulong Day = 24 * Hour;
enum ulong Week = 7 * Day;

ulong getMonotonicTime() {
timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
import core.stdc.stdlib, core.stdc.stdio;
printf("clock_gettime failed!");
exit(1);
}

// We convert the time to use 100ns as a base time unit.
return (ts.tv_sec * Second) + (ts.tv_nsec / 100);
}
6 changes: 4 additions & 2 deletions sdlib/sys/mman.d
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import sys.mman;

import sys.posix.types;

extern(C):

// XXX: this is a bad port of mman header.
// We should be able to use actual prot of C header soon.
alias off_t = long; // Good for now.

enum Prot {
None = 0x0,
Expand Down Expand Up @@ -65,7 +68,6 @@ version(linux) {
}
}

extern(C):
void* mmap(void* addr, size_t length, int prot, int flags, int fd,
off_t offset);
int munmap(void* addr, size_t length);
Expand Down
94 changes: 88 additions & 6 deletions sdlib/sys/posix/types.d
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,95 @@ module sys.posix.types;
alias c_long = long;
alias c_ulong = ulong;

alias ssize_t = c_long;

alias pid_t = int;
// Type of device numbers.
alias dev_t = ulong;
// Type of user identifications.
alias uid_t = uint;
// Type of group identifications.
alias gid_t = uint;

// Type of file serial numbers.
alias ino_t = __syscall_ulong_t;
// Type of file serial numbers (LFS).
alias ino64_t = ulong;
// Type of file attribute bitmasks.
alias mode_t = uint;

alias clock_t = c_long;
// Type of file link counts.
alias nlink_t = __syscall_ulong_t;
// Type of file sizes and offsets.
alias off_t = __syscall_slong_t;
// Type of file sizes and offsets (LFS).
alias off64_t = long;
// Type of process identifications.
alias pid_t = int;
// Type of file system IDs.
// TODO: fsid_t
// Type of CPU usage counts.
alias clock_t = __syscall_slong_t;
// Type for resource measurement.
alias rlim_t = __syscall_ulong_t;
// Type for resource measurement (LFS).
alias rlim64_t = ulong;
// General type for IDs.
alias id_t = uint;
// Seconds since the Epoch.
alias time_t = __syscall_slong_t;
// Count of microseconds.
alias useconds_t = uint;
// Signed count of microseconds.
alias suseconds_t = __syscall_slong_t;
alias suseconds64_t = long;

// The type of a disk address.
alias daddr_t = int;
// Type of an IPC key.
alias key_t = int;

// Clock ID used in clock and timer functions.
alias clockid_t = int;

// Timer ID returned by `timer_create'.
alias timer_t = void*;

// Type to represent block size.
alias blksize_t = __syscall_slong_t;

// Types from the Large File Support interface.

// Type to count number of disk blocks.
alias blkcnt_t = __syscall_slong_t;
alias blkcnt64_t = long;

// Type to count file system blocks.
alias fsblkcnt_t = __syscall_ulong_t;
alias fsblkcnt64_t = ulong;

// Type to count file system nodes.
alias fsfilcnt_t = __syscall_ulong_t;
alias fsfilcnt64_t = ulong;

// Type of miscellaneous file system fields.
alias fsword_t = __syscall_slong_t;

// Type of a byte count, or error.
alias ssize_t = c_long;

// Signed long type used in system calls.
alias __syscall_slong_t = c_long;
// Unsigned long type used in system calls.
alias __syscall_ulong_t = c_ulong;

/* These few don't really vary by system, they always correspond
to one of the other defined types. */
// Type of file sizes and offsets (LFS).
alias loff_t = off64_t;
alias caddr_t = char*;

/* C99: An integer type that can be accessed as an atomic entity,
even in the presence of asynchronous interrupts.
It is not currently necessary for this to be machine-specific. */
alias sig_atomic_t = int;

/* Seconds since the Epoch, visible to user code when time_t is too
narrow only for consistency with the old way of widening too-narrow
types. User code should never use time64_t. */
alias time64_t = long;

0 comments on commit eff1d1c

Please sign in to comment.