Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions cmd/juno/juno.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ const (
defaultRemoteDB = ""
defaultRPCMaxBlockScan = math.MaxUint
defaultCacheSizeMb = 1024
maxAutoCacheSizeMb = 8192
cacheMemoryFraction = 4
defaultDBMaxHandlesFloor = 1024
defaultDBMaxHandlesCeiling = 1_048_576
defaultGwAPIKey = ""
Expand Down Expand Up @@ -234,8 +236,10 @@ const (
maxVMQueueUsage = "Maximum number for requests to queue after reaching max-vms before starting to reject incoming requests"
remoteDBUsage = "gRPC URL of a remote Juno node"
rpcMaxBlockScanUsage = "Maximum number of blocks scanned in single starknet_getEvents call"
dbCacheSizeUsage = "Determines the amount of memory (in megabytes) allocated for caching data in the database."
dbMaxHandlesUsage = "A soft limit on the number of open files that can be used by the DB. " +
dbCacheSizeUsage = "Determines the amount of memory (in megabytes) allocated for " +
"caching data in the database. When not set, defaults to a quarter of total " +
"memory (host RAM or cgroup limit), between 1024 and 8192"
dbMaxHandlesUsage = "A soft limit on the number of open files that can be used by the DB. " +
"When not set, defaults to half of the process fd limit (min 1024, max 1048576)"
//nolint: gosec // usage text, not a credential
gwAPIKeyUsage = "API key for gateway endpoints to avoid throttling"
Expand Down Expand Up @@ -281,7 +285,8 @@ const (
"may consume; a compilation exceeding it is aborted. Enforced on Linux only. " +
"0 disables the limit."
maxCompilationReserveMemory = "Memory (in MB) excluded from the compilations memory budget when " +
"calculating the default for `max-concurrent-compilations`"
"calculating the default for `max-concurrent-compilations`. The DB cache size is " +
"excluded on top of this reserve"
pruneModeUsage = "Enables block-data and state-history pruning. Pruning is " +
"disabled by default; passing this flag (with or without a value) turns " +
"it on. The value is the size of the retention window in blocks, counted " +
Expand Down Expand Up @@ -592,7 +597,7 @@ func NewCmd(config *node.Config, run func(*cobra.Command, []string) error) *cobr

// --- Database ---
junoCmd.Flags().String(dbPathF, defaultDBPath, dbPathUsage)
junoCmd.Flags().Uint(dbCacheSizeF, defaultCacheSizeMb, dbCacheSizeUsage)
junoCmd.Flags().Uint(dbCacheSizeF, defaultDBCacheSize(), dbCacheSizeUsage)
junoCmd.Flags().Int(dbMaxHandlesF, defaultDBMaxHandles(), dbMaxHandlesUsage)
junoCmd.Flags().String(
dbCompactionConcurrencyF, defaultDBCompactionConcurrency, dbCompactionConcurrencyUsage,
Expand Down Expand Up @@ -716,6 +721,16 @@ func NewCmd(config *node.Config, run func(*cobra.Command, []string) error) *cobr
return junoCmd
}

// defaultDBCacheSize gives the DB block cache a quarter of the memory this
// process can use, clamped to [defaultCacheSizeMb, maxAutoCacheSizeMb].
func defaultDBCacheSize() uint {
return dbCacheSizeForMemoryMB(utils.AvailableMemoryMB())
}

func dbCacheSizeForMemoryMB(memMB uint64) uint {
return min(max(uint(memMB/cacheMemoryFraction), defaultCacheSizeMb), maxAutoCacheSizeMb)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

important (re-anchored after the rebase — the original comment was marked outdated) — the lower clamp isn't memory-aware, which is the one range where being memory-aware matters most.

For any memMB < 4096 the result is pinned at defaultCacheSizeMb (1024):

detected memory resulting cache share
1024 MB 1024 MB 100%
2048 MB 1024 MB 50%
4096 MB 1024 MB 25%

pebble.NewCache is a ceiling the process grows into, so a 1–2 GB cgroup (small k8s pods, CI containers) ends up with a block cache at half or all of its limit. This is not a regression — the fixed 1024 default had the same property — but this function is now the thing that claims to scale with memory, so it's the right place to close the gap:

Suggested change
return min(max(uint(memMB/cacheMemoryFraction), defaultCacheSizeMb), maxAutoCacheSizeMb)
quarter := uint(memMB / cacheMemoryFraction)
return min(max(quarter, min(defaultCacheSizeMb, uint(memMB))), maxAutoCacheSizeMb)

If the flat 1024 floor is deliberate, saying so in the doc comment above (and logging a warning when the floor exceeds a quarter of detected memory) would at least make it visible to operators of small containers.

Separately: defaultCacheSizeMb is no longer the default, only the floor — minAutoCacheSizeMb would pair with maxAutoCacheSizeMb and keep the doc comment on line 721 self-explanatory.

}
Comment on lines +730 to +732

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

important — the lower clamp isn't memory-aware, which is the one case where being memory-aware matters most.

For any memMB < 4096 the result is pinned at defaultCacheSizeMb (1024), so:

container limit resulting cache share of memory
1024 MB 1024 MB 100%
2048 MB 1024 MB 50%
4096 MB 1024 MB 25%

A 1–2 GB cgroup (small k8s pods, CI containers) gets a block cache equal to half or all of its limit, and since pebble.NewCache is the ceiling the process grows into it, this ends in an OOM kill. The pre-PR fixed default had the same flaw, but this function is exactly where it should be fixed — otherwise the flag advertises "scales to available memory" while ignoring memory below 4 GB.

Consider bounding the floor too:

func dbCacheSizeForMemoryMB(memMB uint64) uint {
	quarter := uint(memMB / cacheMemoryFraction)
	return min(max(quarter, min(defaultCacheSizeMb, uint(memMB))), maxAutoCacheSizeMb)
}

or, if the 1024 floor is deliberate, say so in the comment and log a warning when the floor exceeds a quarter of detected memory so operators of small containers see it.

Separately: defaultCacheSizeMb is no longer the default, only the floor — minAutoCacheSizeMb would pair with maxAutoCacheSizeMb and keep the doc comment on line 720 self-explanatory.

Comment on lines +730 to +732

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

important (standing item, re-anchored after this rebase) — and a correction to the fix I suggested earlier: the snippet I proposed in my previous review does not actually fix the case it describes. Please ignore it.

The problem stands: for any memMB < 4096 the result is pinned at defaultCacheSizeMb (1024), so a 1 GB cgroup gets a block cache equal to 100% of its limit and a 2 GB cgroup 50%. pebble.NewCache is a ceiling the process grows into, so small k8s pods / CI containers are the ones most likely to OOM. Not a regression (the fixed 1024 default had the same property), but this function is now what claims to scale with memory.

Why my earlier suggestion was wrong — min(max(quarter, min(defaultCacheSizeMb, uint(memMB))), maxAutoCacheSizeMb):

memMB quarter min(1024, memMB) result share
1024 256 1024 1024 100%
2048 512 1024 1024 50%

min(defaultCacheSizeMb, memMB) only bites below 1024 MB of total memory, so both rows in my own table come out unchanged. Bounding the floor by memory isn't enough — it has to be bounded by a fraction of memory, i.e. the floor must not be allowed to exceed what the quarter rule would grant. Concretely, either drop the floor when memory can't afford it:

// dbCacheSizeForMemoryMB gives the cache a quarter of memMB, capped at
// maxAutoCacheSizeMb. The minAutoCacheSizeMb floor only applies when memory is
// large enough for it to stay within the quarter budget, so a small container
// does not get a cache the size of its whole limit.
func dbCacheSizeForMemoryMB(memMB uint64) uint {
	quarter := uint(memMB / cacheMemoryFraction)
	if quarter < minAutoCacheSizeMb {
		return max(quarter, minCacheSizeMb) // e.g. 64; pebble's own floor is 8 MB
	}
	return min(quarter, maxAutoCacheSizeMb)
}

…or keep the flat floor deliberately (defensible — a 1–2 GB host can't sync Juno anyway), and in that case say so in the doc comment on line 724 and log a warning when the floor exceeds a quarter of detected memory, so operators of memory-capped containers can see why the process is being killed. Either way, cmd/juno/juno_internal_test.go should get rows for memMB = 512 and memMB = 2048 to pin the chosen behaviour down.

Separately (unchanged): defaultCacheSizeMb is no longer the default, only the floor — minAutoCacheSizeMb would pair with maxAutoCacheSizeMb and keep the doc comment above self-explanatory.


// defaultDBMaxHandles gives the DB half of the process fd limit, clamped to
// [defaultDBMaxHandlesFloor, defaultDBMaxHandlesCeiling].
func defaultDBMaxHandles() int {
Expand Down
20 changes: 20 additions & 0 deletions cmd/juno/juno_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ import (
"github.com/stretchr/testify/assert"
)

func TestDBCacheSizeForMemoryMB(t *testing.T) {
tests := []struct {
name string
memMB uint64
want uint
}{
{name: "zero memory clamps to floor", memMB: 0, want: defaultCacheSizeMb},
{name: "quarter below floor clamps to floor", memMB: 4095, want: defaultCacheSizeMb},
{name: "quarter equals floor", memMB: 4096, want: defaultCacheSizeMb},
{name: "quarter within bounds", memMB: 8192, want: 2048},
{name: "quarter equals cap", memMB: 32768, want: maxAutoCacheSizeMb},
{name: "quarter above cap clamps to cap", memMB: 65536, want: maxAutoCacheSizeMb},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, dbCacheSizeForMemoryMB(tt.memMB))
})
}
}

func TestDBMaxHandlesForFDLimit(t *testing.T) {
tests := []struct {
name string
Expand Down
9 changes: 5 additions & 4 deletions cmd/juno/juno_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func TestConfigPrecedence(t *testing.T) {
defaultRPCMaxConcurrentRequests := uint(256000)
defaultRPCMaxRequestQueue := uint(256000)
defaultRPCMaxBlockScan := uint(math.MaxUint)
defaultMaxCacheSize := uint(1024)
defaultMaxCacheSize := min(max(uint(utils.AvailableMemoryMB()/4), 1024), 8192)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit — this re-implements dbCacheSizeForMemoryMB with hardcoded literals (4, 1024, 8192) in an external test package, so the clamp constants now live in three places (juno.go, here, generate-config.js). Changing cacheMemoryFraction breaks this test for the wrong reason. defaultMaxHandles on the next line has the same issue and is pre-existing, so if you'd rather not export a helper just for tests it's fine to leave — but a short comment pointing at dbCacheSizeForMemoryMB as the source of truth would help the next person.

defaultMaxHandles := max(int(min(fdLimit/2, 1_048_576)), 1024)
defaultDBMemtableSize := uint(256)
defaultDBMemtableCount := uint(2)
Expand Down Expand Up @@ -224,7 +224,7 @@ func TestConfigPrecedence(t *testing.T) {
"custom network all flags": {
inputArgs: []string{
"--log-level", "debug", "--http-port", "4576", "--http-host", "0.0.0.0",
"--db-path", "/home/.juno", "--pprof", "--db-cache-size", "1024",
"--db-path", "/home/.juno", "--pprof",
"--cn-name", "custom", "--cn-feeder-url", "http://awesome.feeder", "--cn-gateway-url", "http://awesome.gateway",
"--cn-l1-chain-id", "0x1", "--cn-l2-chain-id", "SN_AWESOME",
"--cn-unverifiable-range", "0,10",
Expand Down Expand Up @@ -416,7 +416,8 @@ http-port: 4576
"all flags without config file": {
inputArgs: []string{
"--log-level", "debug", "--http-port", "4576", "--http-host", "0.0.0.0",
"--db-path", "/home/.juno", "--network", "sepolia-integration", "--pprof", "--db-cache-size", "1024",
"--db-path", "/home/.juno", "--network", "sepolia-integration", "--pprof",
"--db-cache-size", "2222",
},
expectedConfig: &node.Config{
LogLevel: "debug",
Expand All @@ -443,7 +444,7 @@ http-port: 4576
RPCMaxConcurrentRequests: defaultRPCMaxConcurrentRequests,
RPCMaxRequestQueue: defaultRPCMaxRequestQueue,
RPCMaxBlockScan: defaultRPCMaxBlockScan,
DBCacheSize: defaultMaxCacheSize,
DBCacheSize: 2222,
DBMaxHandles: defaultMaxHandles,
DBMemtableSize: defaultDBMemtableSize,
DBMemtableCount: defaultDBMemtableCount,
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/_config-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@

| Config Option | Default Value | Description |
| - | - | - |
| `db-cache-size` | `1024` | Determines the amount of memory (in megabytes) allocated for caching data in the database |
| `db-cache-size` | `quarter of total memory (min 1024, max 8192)` | Determines the amount of memory (in megabytes) allocated for caching data in the database. When not set, defaults to a quarter of total memory (host RAM or cgroup limit), between 1024 and 8192 |
| `db-compaction-concurrency` | | DB compaction concurrency range. Format: N (lower=1, upper=N) or M,N (lower=M, upper=N). Default: 1,GOMAXPROCS/2 |
| `db-compression` | `zstd` | Database compression profile. Options: zstd, snappy, minlz. Use zstd for low storage |
| `db-max-handles` | `half of process fd limit (min 1024, max 1048576)` | A soft limit on the number of open files that can be used by the DB. When not set, defaults to half of the process fd limit (min 1024, max 1048576) |
Expand All @@ -105,7 +105,7 @@
| `max-compilation-cpu-time` | `10` | Maximum CPU time (in seconds) each Sierra compilation process may consume; a compilation exceeding it is aborted. Enforced on Linux only. 0 disables the limit |
| `max-compilation-memory` | `4 * 1024` | Maximum memory (in MB) each Sierra compilation process may use; a compilation exceeding it is aborted. Enforced on Linux only. 0 disables the limit |
| `max-compilation-queue` | `2 * max-concurrent-compilations` | Maximum number of compilation requests to queue after reaching max-concurrent-compilations before starting to reject incoming requests |
| `max-concurrent-compilations` | `CPU Cores` | Maximum concurrent Sierra compilations |
| `max-concurrent-compilations` | `auto (memory-aware)` | Maximum concurrent Sierra compilations. Default is set based on available hardware resources. Derived as `min(cpu_cores, (available_memory - node_memory_reserve - db_cache_size) / max_compilation_memory)`, at least 1 |
| `max-vm-queue` | `2 * max-vms` | Maximum number for requests to queue after reaching max-vms before starting to reject incoming requests |
| `max-vms` | `3 * CPU Cores` | Maximum number for VM instances to be used for RPC calls concurrently |
| `versioned-constants-file` | | Use custom versioned constants from provided file |
Expand Down
8 changes: 4 additions & 4 deletions docs/docs/tuning.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ Note that this effectively improve syncing speed while behind the tip of the cha

## Database Cache Size

Set by the `--db-cache-size` flag (default: 1024 MB), this determines the amount of memory allocated for caching frequently accessed data from the database.
Set by the `--db-cache-size` flag (default: a quarter of total memory — host RAM or cgroup limit — between 1024 and 8192 MB), this determines the amount of memory allocated for caching frequently accessed data from the database.

A larger cache reduces disk reads and improves query performance. On systems with ample memory, increasing this value (e.g., 2048 or 4096 MB) can significantly improve RPC response times and overall node performance.
A larger cache reduces disk reads and improves query performance. The default already scales with memory; on machines with more than 32 GB of RAM, raising it past the 8192 MB cap holds more of the database in memory and can improve RPC response times.

## Sierra Compilation Limits

Expand Down Expand Up @@ -95,12 +95,12 @@ The CPU time limit counts seconds of CPU actually consumed by the compilation pr
- `--max-concurrent-compilations`(default: unset): controls how many compilations run at once. Any non-negative integer is used directly (`0` disables compilations). Left unset (the default), Juno derives a safe value so concurrent compilations cannot exhaust RAM:

```
limit = min((available_memory - node_memory_reserve) / max_compilation_memory, cpu_cores), at least 1.
limit = min((available_memory - node_memory_reserve - db_cache_size) / max_compilation_memory, cpu_cores), at least 1.
```

- `--max-compilation-queue` (default: unset): How many requests wait once the concurrency limit is reached before new ones are rejected. Unset uses twice the concurrency limit (`0` disables the queue).

- `--node-memory-reserve` (default: 4096 MB): Memory kept for the rest of the node, excluded from the compilation budget.
- `--node-memory-reserve` (default: 4096 MB): Memory kept for the rest of the node, excluded from the compilation budget. The DB cache size is excluded on top of this reserve, since the cache fills to its ceiling on a synced node.

The available memory respects container limits (cgroups), so inside a memory-capped container the value reflects the container, not the host. On non-Linux, where the per-compilation memory limit does not apply, the limit is simply the CPU core count.

Expand Down
6 changes: 5 additions & 1 deletion docs/generate-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ const extractConfigs = (codebase) => {
if (configName === "db-max-handles") {
defaultValue = "half of process fd limit (min 1024, max 1048576)";
}
// Same for db-cache-size — computed from total memory at startup.
if (configName === "db-cache-size") {
defaultValue = "quarter of total memory (min 1024, max 8192)";
}
if (configName === "max-vms") {
defaultValue = "3 * CPU Cores";
}
Expand All @@ -116,7 +120,7 @@ const extractConfigs = (codebase) => {
if (configName === "max-concurrent-compilations") {
defaultValue = "auto (memory-aware)";
description +=
". Derived as `min(cpu_cores, (available_memory - node_memory_reserve) / max_compilation_memory)`, at least 1";
". Derived as `min(cpu_cores, (available_memory - node_memory_reserve - db_cache_size) / max_compilation_memory)`, at least 1";
}
if (configName === "max-compilation-queue") {
defaultValue = "2 * max-concurrent-compilations";
Expand Down
8 changes: 7 additions & 1 deletion node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
"github.com/NethermindEth/juno/starknet/compiler"
adaptfeeder "github.com/NethermindEth/juno/starknetdata/feeder"
"github.com/NethermindEth/juno/sync"
"github.com/NethermindEth/juno/utils"
"github.com/NethermindEth/juno/utils/log"
"github.com/NethermindEth/juno/vm"
"github.com/consensys/gnark-crypto/ecc/stark-curve/ecdsa"
Expand Down Expand Up @@ -331,7 +332,12 @@ func New(cfg *Config, version string, logLevel *log.Level) (*Node, error) {
var nodeVM vm.VM
var throttledVM *ThrottledVM

maxConcurrentComp, maxQueuedComp := calculateCompilerConcurrencyBudget(cfg, logger)
maxConcurrentComp, maxQueuedComp := calculateCompilerConcurrencyBudget(
cfg,
uint64(runtime.GOMAXPROCS(0)),
utils.AvailableMemoryMB(),
logger,
)
compiler := compiler.New(
&compiler.Config{
MaxMemory: uint64(cfg.MaxCompilationMemory) * 1024 * 1024,
Expand Down
4 changes: 2 additions & 2 deletions node/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (
statetestutils "github.com/NethermindEth/juno/core/state/testutils"
"github.com/NethermindEth/juno/db/pebblev2"
"github.com/NethermindEth/juno/node"
"github.com/NethermindEth/juno/starknet/compiler"
adaptfeeder "github.com/NethermindEth/juno/starknetdata/feeder"
"github.com/NethermindEth/juno/sync"
"github.com/NethermindEth/juno/utils"
"github.com/NethermindEth/juno/utils/log"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -89,7 +89,7 @@ func TestNewNodeRunsOneAtATimeOnLowMemory(t *testing.T) {
// MaxConcurrentCompilations left unset: derive, then floor to 1.
MaxCompilationMemory: 4096,
// Reserve more than the machine has, so nothing fits.
NodeMemoryReserve: uint(compiler.AvailableMemoryMB() + 4096),
NodeMemoryReserve: uint(utils.AvailableMemoryMB() + 4096),
}

_, err := node.New(config, "v0.3", log.NewLevel(log.INFO))
Expand Down
20 changes: 15 additions & 5 deletions node/throttled_compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package node

import (
"context"
"runtime"

"github.com/NethermindEth/juno/starknet"
"github.com/NethermindEth/juno/starknet/compiler"
Expand Down Expand Up @@ -41,14 +40,24 @@ func (tc *ThrottledCompiler) Compile(

// calculateCompilerConcurrencyBudget determines safe limits for concurrent compilations
// if this were not explicitly set
func calculateCompilerConcurrencyBudget(cfg *Config, logger log.StructuredLogger) (uint64, uint64) {
func calculateCompilerConcurrencyBudget(
cfg *Config,
cores uint64,
availableMemoryMB uint64,
logger log.StructuredLogger,
) (uint64, uint64) {
// A remote DB allocates no local pebble cache, so none of it is reserved.
dbCacheSizeMB := uint64(cfg.DBCacheSize)
if cfg.RemoteDB != "" {
dbCacheSizeMB = 0
}
Comment thread
infrmtcs marked this conversation as resolved.

maxConcurrency := cfg.MaxConcurrentCompilations
availableMemoryMB := compiler.AvailableMemoryMB()
if !cfg.MaxConcurrentCompilationsExplicit {
maxConcurrency = compiler.ConcurrencyLimit(
uint64(runtime.GOMAXPROCS(0)),
cores,
availableMemoryMB,
uint64(cfg.NodeMemoryReserve),
uint64(cfg.NodeMemoryReserve)+dbCacheSizeMB,
uint64(cfg.MaxCompilationMemory),
)
}
Expand All @@ -63,6 +72,7 @@ func calculateCompilerConcurrencyBudget(cfg *Config, logger log.StructuredLogger
zap.Uint64("queueSize", queueSize),
zap.Uint64("availableMemoryMB", availableMemoryMB),
zap.Uint("nodeMemoryReserveMB", cfg.NodeMemoryReserve),
zap.Uint64("dbCacheSizeMB", dbCacheSizeMB),
zap.Uint("maxCompilationMemoryMB", cfg.MaxCompilationMemory),
)
return maxConcurrency, queueSize
Expand Down
86 changes: 86 additions & 0 deletions node/throttled_compiler_internal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package node

import (
"testing"

"github.com/NethermindEth/juno/utils/log"
"github.com/stretchr/testify/assert"
)

func TestCalculateCompilerConcurrencyBudget(t *testing.T) {
tests := []struct {
name string
cfg Config
cores uint64
memMB uint64
wantConc uint64
wantQueue uint64
}{
{
name: "db cache is reserved on top of node reserve",
cfg: Config{MaxCompilationMemory: 4096, NodeMemoryReserve: 4096, DBCacheSize: 8192},
cores: 64,
memMB: 65536,
wantConc: 13, // (65536 - 4096 - 8192) / 4096
wantQueue: 26,
},
{
name: "remote db ignores the local cache size",
cfg: Config{
MaxCompilationMemory: 4096, NodeMemoryReserve: 4096, DBCacheSize: 8192,
RemoteDB: "localhost:9090",
},
cores: 64,
memMB: 65536,
wantConc: 15, // (65536 - 4096) / 4096
wantQueue: 30,
},
{
name: "reserve plus cache covering all memory floors to 1",
cfg: Config{MaxCompilationMemory: 4096, NodeMemoryReserve: 4096, DBCacheSize: 8192},
cores: 64,
memMB: 12288,
wantConc: 1,
wantQueue: 2,
},
{
name: "no compilation memory limit uses core count",
cfg: Config{MaxCompilationMemory: 0, NodeMemoryReserve: 4096, DBCacheSize: 8192},
cores: 64,
memMB: 65536,
wantConc: 64,
wantQueue: 128,
},
{
name: "explicit setting bypasses derivation",
cfg: Config{
MaxConcurrentCompilations: 5, MaxConcurrentCompilationsExplicit: true,
MaxCompilationMemory: 4096, NodeMemoryReserve: 4096, DBCacheSize: 8192,
},
cores: 64,
memMB: 65536,
wantConc: 5,
wantQueue: 10,
},
{
name: "explicit queue bypasses derivation",
cfg: Config{
MaxCompilationMemory: 4096, NodeMemoryReserve: 4096, DBCacheSize: 8192,
MaxCompilationQueue: 7, MaxCompilationQueueExplicit: true,
},
cores: 64,
memMB: 65536,
wantConc: 13,
wantQueue: 7,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
conc, queue := calculateCompilerConcurrencyBudget(
&tt.cfg, tt.cores, tt.memMB, log.NewNopZapLogger(),
)
assert.Equal(t, tt.wantConc, conc)
assert.Equal(t, tt.wantQueue, queue)
})
}
}
18 changes: 0 additions & 18 deletions starknet/compiler/concurrency.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,5 @@
package compiler

import (
"github.com/KimMachineGun/automemlimit/memlimit"
"github.com/pbnjay/memory"
)

const megabyte = 1 << 20

// AvailableMemoryMB returns the RAM this process can use, in MB.
// It checks if the memory is limited by the cgroup limit, otherwise it uses the host RAM.
func AvailableMemoryMB() uint64 {
hostMemory := memory.TotalMemory()
cgroupLimit, err := memlimit.FromCgroup()
if err == nil && cgroupLimit > 0 && cgroupLimit < hostMemory {
return cgroupLimit / megabyte
}
return hostMemory / megabyte
}

// ConcurrencyLimit returns how many compilations fit in memory, capped by maxConcurrency.
// Memory is in MB. A 0 maxMemoryPerCompilation means no memory limit.
// Returns 1 when no compilation fits memory.
Expand Down
4 changes: 0 additions & 4 deletions starknet/compiler/concurrency_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,3 @@ func TestConcurrencyLimit(t *testing.T) {
})
}
}

func TestAvailableMemoryMB(t *testing.T) {
assert.NotZero(t, compiler.AvailableMemoryMB())
}
Loading
Loading