mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-21 08:21:32 +00:00
gc tweaking to gain a few percent of performance
This commit is contained in:
@@ -23,28 +23,39 @@ proc nimLoadLibraryError(path: string) {.compilerproc, noinline.}
|
||||
|
||||
proc setStackBottom(theStackBottom: pointer) {.compilerRtl, noinline.}
|
||||
|
||||
|
||||
# Support for thread local storage:
|
||||
when false:
|
||||
when defined(windows):
|
||||
proc TlsAlloc(): int32 {.importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
|
||||
proc TlsSetValue(dwTlsIndex: int32, lpTlsValue: pointer) {.
|
||||
importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
|
||||
proc TlsGetValue(dwTlsIndex: int32): pointer {.
|
||||
importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
|
||||
|
||||
else:
|
||||
type
|
||||
Tpthread_key {.importc: "pthread_key_t", header: "<sys/types.h>".} = int
|
||||
when defined(windows):
|
||||
type
|
||||
TThreadVarSlot {.compilerproc.} = distinct int32
|
||||
|
||||
proc pthread_getspecific(a1: Tpthread_key): pointer {.
|
||||
importc: "pthread_getspecific", header: "<pthread.h>".}
|
||||
proc pthread_key_create(a1: ptr Tpthread_key,
|
||||
a2: proc (x: pointer) {.noconv.}): int32 {.
|
||||
importc: "pthread_key_create", header: "<pthread.h>".}
|
||||
proc pthread_key_delete(a1: Tpthread_key): int32 {.
|
||||
importc: "pthread_key_delete", header: "<pthread.h>".}
|
||||
proc TlsAlloc(): TThreadVarSlot {.
|
||||
importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
|
||||
proc TlsSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
|
||||
importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
|
||||
proc TlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
|
||||
importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
|
||||
|
||||
proc ThreadVarAlloc(): TThreadVarSlot {.compilerproc, inline.} =
|
||||
result = TlsAlloc()
|
||||
proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {.compilerproc.} =
|
||||
TlsSetValue(s, value)
|
||||
proc ThreadVarGetValue(s: TThreadVarSlot): pointer {.compilerproc.} =
|
||||
result = TlsGetValue(s)
|
||||
|
||||
else:
|
||||
type
|
||||
Tpthread_key {.importc: "pthread_key_t",
|
||||
header: "<sys/types.h>".} = distinct int
|
||||
TThreadVarSlot {.compilerproc.} = Tpthread_key
|
||||
|
||||
proc pthread_setspecific(a1: Tpthread_key, a2: pointer): int32 {.
|
||||
importc: "pthread_setspecific", header: "<pthread.h>".}
|
||||
proc pthread_getspecific(a1: Tpthread_key): pointer {.
|
||||
importc: "pthread_getspecific", header: "<pthread.h>".}
|
||||
proc pthread_key_create(a1: ptr Tpthread_key,
|
||||
destruct: proc (x: pointer) {.noconv.}): int32 {.
|
||||
importc: "pthread_key_create", header: "<pthread.h>".}
|
||||
proc pthread_key_delete(a1: Tpthread_key): int32 {.
|
||||
importc: "pthread_key_delete", header: "<pthread.h>".}
|
||||
|
||||
proc pthread_setspecific(a1: Tpthread_key, a2: pointer): int32 {.
|
||||
importc: "pthread_setspecific", header: "<pthread.h>".}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -21,8 +21,6 @@ proc rawWrite(f: TFile, s: string) =
|
||||
|
||||
proc nimLoadLibraryError(path: string) =
|
||||
# carefully written to avoid memory allocation:
|
||||
#stdout.write("could not load: ")
|
||||
#quit(path)
|
||||
stdout.rawWrite("could not load: ")
|
||||
stdout.rawWrite(path)
|
||||
stdout.rawWrite("\n")
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
const
|
||||
CycleIncrease = 2 # is a multiplicative increase
|
||||
InitialCycleThreshold = 4*1024*1024 # X MB because cycle checking is slow
|
||||
ZctThreshold = 256 # we collect garbage if the ZCT's size
|
||||
ZctThreshold = 500 # we collect garbage if the ZCT's size
|
||||
# reaches this threshold
|
||||
# this seems to be a good value
|
||||
|
||||
@@ -294,31 +294,32 @@ proc initGC() =
|
||||
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
|
||||
var d = cast[TAddress](dest)
|
||||
case n.kind
|
||||
of nkNone: assert(false)
|
||||
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
|
||||
of nkList:
|
||||
for i in 0..n.len-1: forAllSlotsAux(dest, n.sons[i], op)
|
||||
of nkCase:
|
||||
var m = selectBranch(dest, n)
|
||||
if m != nil: forAllSlotsAux(dest, m, op)
|
||||
of nkNone: assert(false)
|
||||
|
||||
proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) =
|
||||
var d = cast[TAddress](dest)
|
||||
if dest == nil: return # nothing to do
|
||||
if ntfNoRefs notin mt.flags:
|
||||
case mt.Kind
|
||||
of tyArray, tyArrayConstr, tyOpenArray:
|
||||
for i in 0..(mt.size div mt.base.size)-1:
|
||||
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
|
||||
of tyRef, tyString, tySequence: # leaf:
|
||||
doOperation(cast[ppointer](d)[], op)
|
||||
of tyObject, tyTuple, tyPureObject:
|
||||
forAllSlotsAux(dest, mt.node, op)
|
||||
of tyArray, tyArrayConstr, tyOpenArray:
|
||||
for i in 0..(mt.size div mt.base.size)-1:
|
||||
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
|
||||
else: nil
|
||||
|
||||
proc forAllChildren(cell: PCell, op: TWalkOp) =
|
||||
assert(cell != nil)
|
||||
assert(cell.typ != nil)
|
||||
assert cell.typ.kind in {tyRef, tySequence, tyString}
|
||||
case cell.typ.Kind
|
||||
of tyRef: # common case
|
||||
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
|
||||
@@ -329,14 +330,57 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
|
||||
for i in 0..s.len-1:
|
||||
forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
|
||||
GenericSeqSize), cell.typ.base, op)
|
||||
of tyString: nil
|
||||
else: assert(false)
|
||||
else: nil
|
||||
|
||||
proc checkCollection {.inline.} =
|
||||
# checks if a collection should be done
|
||||
if recGcLock == 0:
|
||||
collectCT(gch)
|
||||
|
||||
proc addNewObjToZCT(res: PCell) {.inline.} =
|
||||
# we check the last 8 entries (cache line) for a slot that could be reused.
|
||||
# In 63% of all cases we succeed here! But we have to optimize the heck
|
||||
# out of this small linear search so that ``newObj`` is not slowed down.
|
||||
#
|
||||
# Slots to try cache hit
|
||||
# 1 32%
|
||||
# 4 59%
|
||||
# 8 63%
|
||||
# 16 66%
|
||||
# all slots 68%
|
||||
var L = gch.zct.len
|
||||
var d = gch.zct.d
|
||||
when true:
|
||||
# loop unrolled for performance:
|
||||
template replaceZctEntry(i: expr) =
|
||||
c = d[i]
|
||||
if c.refcount >=% rcIncrement:
|
||||
c.refcount = c.refcount and not colorMask
|
||||
d[i] = res
|
||||
return
|
||||
if L > 8:
|
||||
var c: PCell
|
||||
replaceZctEntry(L-1)
|
||||
replaceZctEntry(L-2)
|
||||
replaceZctEntry(L-3)
|
||||
replaceZctEntry(L-4)
|
||||
replaceZctEntry(L-5)
|
||||
replaceZctEntry(L-6)
|
||||
replaceZctEntry(L-7)
|
||||
replaceZctEntry(L-8)
|
||||
add(gch.zct, res)
|
||||
else:
|
||||
d[L] = res
|
||||
inc(gch.zct.len)
|
||||
else:
|
||||
for i in countdown(L-1, max(0, L-8)):
|
||||
var c = d[i]
|
||||
if c.refcount >=% rcIncrement:
|
||||
c.refcount = c.refcount and not colorMask
|
||||
d[i] = res
|
||||
return
|
||||
add(gch.zct, res)
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
# generates a new object and sets its reference counter to 0
|
||||
aquire(gch)
|
||||
@@ -354,18 +398,7 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
res.refcount = rcZct # refcount is zero, but mark it to be in the ZCT
|
||||
assert(isAllocatedPtr(allocator, res))
|
||||
# its refcount is zero, so add it to the ZCT:
|
||||
block addToZCT:
|
||||
# we check the last 8 entries (cache line) for a slot
|
||||
# that could be reused
|
||||
var L = gch.zct.len
|
||||
var d = gch.zct.d
|
||||
for i in countdown(L-1, max(0, L-8)):
|
||||
var c = d[i]
|
||||
if c.refcount >=% rcIncrement:
|
||||
c.refcount = c.refcount and not colorMask
|
||||
d[i] = res
|
||||
break addToZCT
|
||||
add(gch.zct, res)
|
||||
addNewObjToZCT(res)
|
||||
when logGC: writeCell("new cell", res)
|
||||
gcTrace(res, csAllocated)
|
||||
release(gch)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
||||
Reference in New Issue
Block a user