Skip to content

Commit

Permalink
feat: user defined heap size (#27)
Browse files Browse the repository at this point in the history
* refactor: use bytes instead of words for defining heap size

Added some debug logs to track heap size and freed bytes during GC

* feat: user defined `heapSize`

* chore: update `prepare` script to build package

* chore: yarn uses `prepack` instead

* chore: f**k it we will just have a release branch with `/dist`
  • Loading branch information
shenyih0ng authored Apr 12, 2024
1 parent c847e08 commit 90a45a6
Show file tree
Hide file tree
Showing 7 changed files with 20 additions and 15 deletions.
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@
"autocomplete": "node ./scripts/updateAutocompleteDocs.js",
"build_sicp_package": "./scripts/build_sicp_package.sh",
"publish_sicp_package": "./scripts/publish_sicp_package.sh",
"benchmark": "jest --runInBand --testPathPattern='.*benchmark.*' --testPathIgnorePatterns='/dist/'",
"prepare": "husky install"
"benchmark": "jest --runInBand --testPathPattern='.*benchmark.*' --testPathIgnorePatterns='/dist/'"
},
"devDependencies": {
"@types/jest": "^29.0.0",
Expand Down
4 changes: 2 additions & 2 deletions src/go-slang/ece.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { PREDECLARED_FUNCTIONS, PREDECLARED_IDENTIFIERS } from './lib/predeclare
import { Scheduler } from './scheduler'
import { BuiltinOp, CallExpression, Instruction, NodeType, SourceFile } from './types'

export function evaluate(program: SourceFile, slangContext: SlangContext): Value {
export function evaluate(program: SourceFile, heapSize: number, slangContext: SlangContext): Value {
const scheduler = new Scheduler(slangContext)

const C = new Stack<Instruction | HeapAddress>()
Expand All @@ -18,7 +18,7 @@ export function evaluate(program: SourceFile, slangContext: SlangContext): Value
// `SourceFile` is the root node of the AST which has latest (monotonically increasing) uid of all AST nodes
// Therefore, the next uid to be used to track AST nodes is the uid of SourceFile + 1
const A = new AstMap((program.uid as number) + 1)
const H = new Heap(A, scheduler)
const H = new Heap(A, scheduler, heapSize)

// inject predeclared functions into the global environment
const B = new Map<number, (...args: any[]) => any>()
Expand Down
4 changes: 2 additions & 2 deletions src/go-slang/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { resolvedErrorPromise } from '../runner'
import { evaluate } from './ece'
import { SourceFile } from './types'

export async function goRunner(program: any, context: Context): Promise<Result> {
const value = evaluate(program as SourceFile, context)
export async function goRunner(program: any, heapSize: number, context: Context): Promise<Result> {
const value = evaluate(program as SourceFile, heapSize, context)
if (context.errors.length > 0) {
return resolvedErrorPromise
}
Expand Down
8 changes: 4 additions & 4 deletions src/go-slang/lib/heap/config.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/* Set of default configurations for the heap used in the Go ECE */

// The default size of the heap in words
// Total heap size (in bytes) = DEFAULT_HEAP_SIZE * WORD_SIZE
export const DEFAULT_HEAP_SIZE = 4096 // in words

// The smallest addressable unit in the heap
// We can think of it as the heap containing N number of words, each of size WORD_SIZE
export const WORD_SIZE = 8 // in bytes

// The default size of the heap in words
// Total heap size (in bytes)
export const DEFAULT_HEAP_SIZE = 4096 * WORD_SIZE

// The byte offset to the size of a heap object within a tagged pointer
export const SIZE_OFFSET = 5 // in bytes
11 changes: 7 additions & 4 deletions src/go-slang/lib/heap/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ export class Heap {
// NOTE: this is hacky and should be refactored
private scheduler: Scheduler

constructor(astMap: AstMap, scheduler: Scheduler, n_words?: number) {
constructor(astMap: AstMap, scheduler: Scheduler, heapSize: number = DEFAULT_HEAP_SIZE) {
this.astMap = astMap
this.scheduler = scheduler

const totalBytes = (n_words ?? DEFAULT_HEAP_SIZE) * WORD_SIZE
this.memory = new DataView(new ArrayBuffer(totalBytes))
console.log(`[Heap]: Initializing heap with size ${heapSize} bytes.`) // DEBUG
this.memory = new DataView(new ArrayBuffer(heapSize))

const buddyAllocSize = Math.ceil(Math.log2(totalBytes))
const buddyAllocSize = Math.ceil(Math.log2(heapSize))

this.buddyBlocks = Array.from({ length: buddyAllocSize + 1 }, () => new Set())
// initialize the block with the maximum size (= size of the entire heap)
Expand Down Expand Up @@ -382,11 +382,14 @@ export class Heap {
}
}

let _totalFreedWords = 0 // DEBUG
this.buddyBlockMap.forEach((_, addr) => {
if (!activeHeapAddresses.has(addr) && this.tag(addr) !== PointerTag.AstNode) {
_totalFreedWords += this.size(addr) + 1
this.buddyFree(addr)
}
})
console.log(`[Heap]: GC freed ${_totalFreedWords * WORD_SIZE} bytes of memory.`) // DEBUG

// retry allocation
alloc_heap_addr = this.buddyAlloc((size + 1) * WORD_SIZE)
Expand Down
4 changes: 3 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export interface IOptions {
executionMethod: ExecutionMethod
variant: Variant
originalMaxExecTime: number
heapSize: number
useSubst: boolean
isPrelude: boolean
throwInfiniteLoops: boolean
Expand Down Expand Up @@ -234,7 +235,8 @@ export async function runFilesInContext(
if (program === null) {
return resolvedErrorPromise
}
return goRunner(program, context)
const { heapSize } = options
return goRunner(program, heapSize!, context)
}

if (
Expand Down
1 change: 1 addition & 0 deletions src/runner/sourceRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const DEFAULT_SOURCE_OPTIONS: Readonly<IOptions> = {
executionMethod: 'auto',
variant: Variant.DEFAULT,
originalMaxExecTime: 1000,
heapSize: 32768,
useSubst: false,
isPrelude: false,
throwInfiniteLoops: true,
Expand Down

0 comments on commit 90a45a6

Please sign in to comment.