Skip to content

Commit c3550f4

Browse files
authored
Auto discover available host resources and dynamically set internal limits (#1438)
1 parent f17001e commit c3550f4

File tree

6 files changed

+89
-9
lines changed

6 files changed

+89
-9
lines changed

manager/src/main/java/io/aklivity/zilla/manager/internal/commands/install/ZpmInstall.java

+3
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,9 @@ private void linkModules(
716716
extraModuleNames.add("java.instrument");
717717
}
718718

719+
extraModuleNames.add("java.management");
720+
extraModuleNames.add("jdk.management");
721+
719722
Stream<String> moduleNames = Stream.concat(modules.stream().map(m -> m.name), extraModuleNames.stream());
720723

721724
List<String> args = new ArrayList<>(Arrays.asList(

runtime/binding-tcp/src/main/java/io/aklivity/zilla/runtime/binding/tcp/internal/TcpBinding.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.concurrent.ConcurrentMap;
2121

2222
import io.aklivity.zilla.runtime.binding.tcp.internal.config.TcpServerBindingConfig;
23+
import io.aklivity.zilla.runtime.binding.tcp.internal.util.OperatingSystem;
2324
import io.aklivity.zilla.runtime.engine.EngineContext;
2425
import io.aklivity.zilla.runtime.engine.binding.Binding;
2526
import io.aklivity.zilla.runtime.engine.binding.BindingContext;
@@ -62,6 +63,8 @@ public BindingContext supply(
6263
private TcpServerBindingConfig supplyServer(
6364
long bindingId)
6465
{
65-
return servers.computeIfAbsent(bindingId, TcpServerBindingConfig::new);
66+
return OperatingSystem.detect() == OperatingSystem.OS.MACOS
67+
? servers.computeIfAbsent(bindingId, TcpServerBindingConfig::new)
68+
: new TcpServerBindingConfig(bindingId);
6669
}
6770
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2021-2024 Aklivity Inc.
3+
*
4+
* Aklivity licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
package io.aklivity.zilla.runtime.binding.tcp.internal.util;
17+
18+
public final class OperatingSystem
19+
{
20+
public enum OS
21+
{
22+
MACOS, LINUX, UNKNOWN
23+
}
24+
25+
private OperatingSystem()
26+
{
27+
// no instances
28+
}
29+
30+
public static OS detect()
31+
{
32+
OS os = OS.UNKNOWN;
33+
String osName = System.getProperty("os.name").toLowerCase();
34+
if (osName.contains("mac"))
35+
{
36+
os = OS.MACOS;
37+
}
38+
else if (osName.contains("nix") || osName.contains("nux") || osName.contains("aix"))
39+
{
40+
os = OS.LINUX;
41+
}
42+
43+
return os;
44+
}
45+
}

runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/EngineConfiguration.java

+33-8
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
import static java.util.concurrent.TimeUnit.MILLISECONDS;
1919
import static java.util.concurrent.TimeUnit.NANOSECONDS;
2020
import static java.util.concurrent.TimeUnit.SECONDS;
21+
import static org.agrona.BitUtil.findNextPositivePowerOfTwo;
2122

2223
import java.io.File;
2324
import java.lang.invoke.MethodHandle;
2425
import java.lang.invoke.MethodHandles;
2526
import java.lang.invoke.MethodType;
27+
import java.lang.management.ManagementFactory;
2628
import java.net.InetAddress;
2729
import java.net.MalformedURLException;
2830
import java.net.URI;
@@ -37,6 +39,8 @@
3739

3840
import org.agrona.LangUtil;
3941

42+
import com.sun.management.OperatingSystemMXBean;
43+
4044
import io.aklivity.zilla.runtime.engine.internal.layouts.BudgetsLayout;
4145

4246
public class EngineConfiguration extends Configuration
@@ -55,6 +59,7 @@ public class EngineConfiguration extends Configuration
5559
public static final PropertyDef<Path> ENGINE_CACHE_DIRECTORY;
5660
public static final PropertyDef<HostResolver> ENGINE_HOST_RESOLVER;
5761
public static final IntPropertyDef ENGINE_WORKER_CAPACITY;
62+
public static final DoublePropertyDef ENGINE_MEMORY_PERCENTAGE;
5863
public static final IntPropertyDef ENGINE_BUFFER_POOL_CAPACITY;
5964
public static final IntPropertyDef ENGINE_BUFFER_SLOT_CAPACITY;
6065
public static final IntPropertyDef ENGINE_STREAMS_BUFFER_CAPACITY;
@@ -101,13 +106,13 @@ public class EngineConfiguration extends Configuration
101106
ENGINE_CACHE_DIRECTORY = config.property(Path.class, "cache.directory", EngineConfiguration::cacheDirectory, "cache");
102107
ENGINE_HOST_RESOLVER = config.property(HostResolver.class, "host.resolver",
103108
EngineConfiguration::decodeHostResolver, EngineConfiguration::defaultHostResolver);
104-
ENGINE_WORKER_CAPACITY = config.property("worker.capacity", 64);
109+
ENGINE_MEMORY_PERCENTAGE = config.property("memory.percentage", 0.75);
110+
ENGINE_WORKER_CAPACITY = config.property("worker.capacity", EngineConfiguration::defaultWorkersCapacity);
105111
ENGINE_BUFFER_POOL_CAPACITY = config.property("buffer.pool.capacity", EngineConfiguration::defaultBufferPoolCapacity);
106112
ENGINE_BUFFER_SLOT_CAPACITY = config.property("buffer.slot.capacity", 64 * 1024);
107113
ENGINE_STREAMS_BUFFER_CAPACITY = config.property("streams.buffer.capacity",
108114
EngineConfiguration::defaultStreamsBufferCapacity);
109-
ENGINE_EVENTS_BUFFER_CAPACITY = config.property("events.buffer.capacity",
110-
EngineConfiguration::defaultEventsBufferCapacity);
115+
ENGINE_EVENTS_BUFFER_CAPACITY = config.property("events.buffer.capacity", 4 * 64 * 1024);
111116
ENGINE_BUDGETS_BUFFER_CAPACITY = config.property("budgets.buffer.capacity",
112117
EngineConfiguration::defaultBudgetsBufferCapacity);
113118
ENGINE_COUNTERS_BUFFER_CAPACITY = config.property("counters.buffer.capacity", 1024 * 1024);
@@ -356,17 +361,37 @@ private static int defaultStreamsBufferCapacity(
356361
return ENGINE_BUFFER_SLOT_CAPACITY.get(config) * ENGINE_WORKER_CAPACITY.getAsInt(config);
357362
}
358363

359-
private static int defaultEventsBufferCapacity(
364+
private static int defaultBudgetsBufferCapacity(
360365
Configuration config)
361366
{
362-
return ENGINE_BUFFER_SLOT_CAPACITY.get(config) * ENGINE_WORKER_CAPACITY.getAsInt(config);
367+
// more consistent with original defaults
368+
return BudgetsLayout.SIZEOF_BUDGET_ENTRY * 512 * ENGINE_WORKER_CAPACITY.getAsInt(config);
363369
}
364370

365-
private static int defaultBudgetsBufferCapacity(
371+
private static int defaultWorkersCapacity(
366372
Configuration config)
367373
{
368-
// more consistent with original defaults
369-
return BudgetsLayout.SIZEOF_BUDGET_ENTRY * 512 * ENGINE_WORKER_CAPACITY.getAsInt(config);
374+
OperatingSystemMXBean osBean =
375+
(OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
376+
377+
final int numberOfCores = osBean.getAvailableProcessors();
378+
final long totalMemorySize = osBean.getTotalMemorySize();
379+
380+
final int slotCapacity = ENGINE_BUFFER_SLOT_CAPACITY.get(config);
381+
final double percentMemory = ENGINE_MEMORY_PERCENTAGE.get(config);
382+
383+
long maxAllowedForBuffers = (long) (percentMemory * totalMemorySize);
384+
385+
// Streams + Pool
386+
long bufferCapacity = slotCapacity + slotCapacity;
387+
long eventsBufferCapacity = ENGINE_EVENTS_BUFFER_CAPACITY.get(config);
388+
long budgetBufferCapacity = BudgetsLayout.SIZEOF_BUDGET_ENTRY * 512L;
389+
long totalBufferCapacity = numberOfCores * (bufferCapacity + budgetBufferCapacity + eventsBufferCapacity);
390+
int newWorkersCapacity = (int) (maxAllowedForBuffers / totalBufferCapacity);
391+
392+
newWorkersCapacity = findNextPositivePowerOfTwo(newWorkersCapacity);
393+
394+
return newWorkersCapacity;
370395
}
371396

372397
private static URL configURL(

runtime/engine/src/main/moditect/module-info.java

+2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@
4949
requires org.leadpony.justify;
5050
requires com.fasterxml.jackson.dataformat.yaml;
5151
requires com.fasterxml.jackson.databind;
52+
requires jdk.management;
5253
requires jdk.unsupported;
54+
requires java.management;
5355
requires java.net.http;
5456
requires org.slf4j;
5557
requires io.aklivity.zilla.runtime.common;

runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/EngineRule.java

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import static io.aklivity.zilla.runtime.engine.EngineConfiguration.ENGINE_ROUTED_DELAY_MILLIS;
2323
import static io.aklivity.zilla.runtime.engine.EngineConfiguration.ENGINE_SYNTHETIC_ABORT;
2424
import static io.aklivity.zilla.runtime.engine.EngineConfiguration.ENGINE_WORKERS;
25+
import static io.aklivity.zilla.runtime.engine.EngineConfiguration.ENGINE_WORKER_CAPACITY;
2526
import static java.nio.file.FileVisitOption.FOLLOW_LINKS;
2627
import static java.nio.file.Files.exists;
2728
import static java.util.Collections.synchronizedList;
@@ -94,6 +95,7 @@ public EngineRule()
9495
configure(ENGINE_SYNTHETIC_ABORT, true);
9596
configure(ENGINE_ROUTED_DELAY_MILLIS, 500L);
9697
configure(ENGINE_WORKERS, 1);
98+
configure(ENGINE_WORKER_CAPACITY, 64);
9799
}
98100

99101
public EngineRule directory(

0 commit comments

Comments
 (0)