Skip to content

Commit 8200fa5

Browse files
authored
Add apply-load mode for searching ledger limits. (#5031)
# Description Add apply-load mode for searching ledger limits. The new mode finds the ledger limits that allow applying the maximum possible TPL that still allows closing ledgers within the configured time limit, e.g. find how many Soroswap-like transactions can be applied within N ms, and what are the respective ledger limits (with some rounding to get nicer numbers). # Checklist - [ ] Reviewed the [contributing](https://github.com/stellar/stellar-core/blob/master/CONTRIBUTING.md#submitting-changes) document - [ ] Rebased on top of master (no merge commits) - [ ] Ran `clang-format` v8.0.0 (via `make format` or the Visual Studio extension) - [ ] Compiles - [ ] Ran all tests - [ ] If change impacts performance, include supporting evidence per the [performance document](https://github.com/stellar/stellar-core/blob/master/performance-eval/performance-eval.md)
2 parents c8c7a75 + 6c0bcc7 commit 8200fa5

File tree

12 files changed

+751
-270
lines changed

12 files changed

+751
-270
lines changed

Builds/VisualStudio/stellar-core.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,7 @@ exit /b 0
756756
<ClCompile Include="..\..\src\util\BinaryFuseFilter.cpp" />
757757
<ClCompile Include="..\..\src\util\DebugMetaUtils.cpp" />
758758
<ClCompile Include="..\..\src\util\FileSystemException.cpp" />
759+
<ClCompile Include="..\..\src\util\MetricsRegistry.cpp" />
759760
<ClCompile Include="..\..\src\util\ProtocolVersion.cpp" />
760761
<ClCompile Include="..\..\src\util\LogSlowExecution.cpp" />
761762
<ClCompile Include="..\..\src\util\RandHasher.cpp" />
@@ -1175,6 +1176,7 @@ exit /b 0
11751176
<ClInclude Include="..\..\src\util\BufferedAsioCerealOutputArchive.h" />
11761177
<ClInclude Include="..\..\src\util\DebugMetaUtils.h" />
11771178
<ClInclude Include="..\..\src\util\Decoder.h" />
1179+
<ClInclude Include="..\..\src\util\MetricsRegistry.h" />
11781180
<ClInclude Include="..\..\src\util\ProtocolVersion.h" />
11791181
<ClInclude Include="..\..\src\util\numeric128.h" />
11801182
<ClInclude Include="..\..\src\util\RandHasher.h" />

Builds/VisualStudio/stellar-core.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,9 @@
14321432
<ClCompile Include="..\..\src\util\SimpleTimer.cpp">
14331433
<Filter>util</Filter>
14341434
</ClCompile>
1435+
<ClCompile Include="..\..\src\util\MetricsRegistry.cpp">
1436+
<Filter>util</Filter>
1437+
</ClCompile>
14351438
</ItemGroup>
14361439
<ItemGroup>
14371440
<ClInclude Include="..\..\lib\util\cpptoml.h">
@@ -2542,6 +2545,9 @@
25422545
<ClInclude Include="..\..\src\util\SimpleTimer.h">
25432546
<Filter>util</Filter>
25442547
</ClInclude>
2548+
<ClInclude Include="..\..\src\util\MetricsRegistry.h">
2549+
<Filter>util</Filter>
2550+
</ClInclude>
25452551
</ItemGroup>
25462552
<ItemGroup>
25472553
<None Include="..\..\AUTHORS" />
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# This is the Stellar Core configuration example for using the load generation
2+
# (apply-load) tool for finding the maximum ledger limits by applying a number
3+
# of the equivalent 'model' transactions.
4+
#
5+
# The mode will find the maximum value of N, such that closing a ledger
6+
# with N 'model' transactions takes less than a certain target time. Then
7+
# it will find the actual ledger limits by multiplying the 'model' transaction
8+
# dimensions by N.
9+
#
10+
# This is not meant to be used in any production contexts.
11+
#
12+
# The core with this configuration should be run using `./stellar-core apply-load --mode limits-for-model-tx`
13+
14+
# Enable load generation
15+
ARTIFICIALLY_GENERATE_LOAD_FOR_TESTING=true
16+
17+
# Diagnostic events should generally be disabled, but can be enabled for debug
18+
ENABLE_SOROBAN_DIAGNOSTIC_EVENTS = false
19+
20+
# Target average ledger close time.
21+
APPLY_LOAD_TARGET_CLOSE_TIME_MS = 600
22+
23+
# Network configuration section
24+
25+
# Most of the network configuration will be inferred automatically from the 'model'
26+
# transaction (for transaction limits) and from the search itself (for the ledger)
27+
# limits. Only the following limits need to be set:
28+
29+
# Maximum number of Soroban transactions to apply. This is the upper bound for the
30+
# search.
31+
APPLY_LOAD_MAX_SOROBAN_TX_COUNT = 2000
32+
33+
# Number of the transaction clusters and thus apply threads. This will stay constant
34+
# during the search, unlike all the other ledger limits.
35+
APPLY_LOAD_LEDGER_MAX_DEPENDENT_TX_CLUSTERS = 8
36+
37+
# The following section contains various parameters for the generated load.
38+
39+
# Number of ledgers to close for benchmarking each iteration of search.
40+
# The average close time will then be compared to APPLY_LOAD_TARGET_CLOSE_TIME_MS.
41+
APPLY_LOAD_NUM_LEDGERS = 10
42+
43+
# Generate that many simple Classic payment transactions in every benchmark ledger.
44+
# Note, that this will affect the close time.
45+
APPLY_LOAD_CLASSIC_TXS_PER_LEDGER = 0
46+
47+
# Size of every synthetic data entry generated.
48+
# This setting affects both the size of the pre-generated Bucket List entries,
49+
# and the size of every entry that a Soroban transaction reads/writes.
50+
APPLY_LOAD_DATA_ENTRY_SIZE = 250
51+
52+
# Bucket list pre-generation
53+
54+
# The benchmark will pre-generate ledger entries using the simplified ledger
55+
# close process; the generated ledgers won't be reflected in the meta or
56+
# history checkpoints.
57+
58+
# Faster settings, more shallow BL (up to level 6)
59+
# Number of ledgers to close
60+
APPLY_LOAD_BL_SIMULATED_LEDGERS = 10000
61+
# Write a batch of entries every that many ledgers
62+
APPLY_LOAD_BL_WRITE_FREQUENCY = 1000
63+
# Write that many entries in every batch
64+
APPLY_LOAD_BL_BATCH_SIZE = 1000
65+
# Write entry batches in every ledger of this many last ledgers
66+
APPLY_LOAD_BL_LAST_BATCH_SIZE = 100
67+
# Write that many entries in every 'last' ledger
68+
APPLY_LOAD_BL_LAST_BATCH_LEDGERS = 300
69+
70+
# Slower settings, deeper BL (up to level 9)
71+
#APPLY_LOAD_BL_SIMULATED_LEDGERS = 300000
72+
#APPLY_LOAD_BL_WRITE_FREQUENCY = 10000
73+
#APPLY_LOAD_BL_BATCH_SIZE = 10000
74+
#APPLY_LOAD_BL_LAST_BATCH_LEDGERS = 300
75+
#APPLY_LOAD_BL_LAST_BATCH_SIZE = 100
76+
77+
# Settings for the generated 'model' transaction.
78+
# Unlike the 'limit-based' apply-load mode, only a single value
79+
# with `[1]` as distribution is allowed, thus only a single kind
80+
# of transaction will be generated.
81+
82+
# Number of *disk* reads a transaction performs. Every disk read is restoration,
83+
# so it's also a write (accounted for in NUM_RW_ENTRIES).
84+
APPLY_LOAD_NUM_DISK_READ_ENTRIES = [1]
85+
APPLY_LOAD_NUM_DISK_READ_ENTRIES_DISTRIBUTION = [1]
86+
87+
# Number of writes a transaction performs.
88+
APPLY_LOAD_NUM_RW_ENTRIES = [5]
89+
APPLY_LOAD_NUM_RW_ENTRIES_DISTRIBUTION = [1]
90+
91+
# Number of 80-byte events a transaction emits.
92+
APPLY_LOAD_EVENT_COUNT = [15]
93+
APPLY_LOAD_EVENT_COUNT_DISTRIBUTION = [1]
94+
95+
# Size of a generated transaction.
96+
APPLY_LOAD_TX_SIZE_BYTES = [1650]
97+
APPLY_LOAD_TX_SIZE_BYTES_DISTRIBUTION = [1]
98+
99+
# Number of instructions a transaction will use.
100+
APPLY_LOAD_INSTRUCTIONS = [4250000]
101+
APPLY_LOAD_INSTRUCTIONS_DISTRIBUTION = [1]
102+
103+
104+
# Minimal core config boilerplate
105+
106+
RUN_STANDALONE=true
107+
NODE_IS_VALIDATOR=true
108+
UNSAFE_QUORUM=true
109+
NETWORK_PASSPHRASE="Standalone Network ; February 2017"
110+
NODE_SEED="SDQVDISRYN2JXBS7ICL7QJAEKB3HWBJFP2QECXG7GZICAHBK4UNJCWK2 self"
111+
112+
[QUORUM_SET]
113+
THRESHOLD_PERCENT=100
114+
VALIDATORS=["$self"]

docs/software/commands.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,18 @@ Command options can only by placed after command.
2929
synthetic ledger close metadata emitted during the benchmark, and then use
3030
it for benchmarking the meta consumers.
3131
* This can only be used when `ARTIFICIALLY_GENERATE_LOAD_FOR_TESTING=true`
32+
* The command supports several modes:
33+
- **--mode limit-based**: the default mode that measures the
34+
ledger close time for applying transactions.
35+
- **--mode max-sac-tps**: determines maximum TPS for the load consisting
36+
only of fast SAC transfer
37+
- **--mode limits-for-model-tx**: determines maximum ledger limits for the
38+
load consisting only of a customizable 'model' transaction.
3239
* Load generation is configured in the Core config file. The relevant settings
3340
all begin with `APPLY_LOAD_`. See full example configurations with
3441
per-setting documentation in the `docs` directory
35-
(`apply-load.cfg`, `apply-load-for-meta.cfg`).
36-
* The command also supports the special mode for determining max apply 'TPS'
37-
using SAC transfers. It can be invoked by passing `max-sac-tps` as
38-
`apply-load` argument.
42+
(all the `apply-load-*.cfg` files demonstrate different modes and use
43+
cases).
3944

4045
* **calculate-asset-supply**: Calculates total supply of an asset from the live and hot archive bucket lists IF the total supply fits in a 64 bit signed integer. Also validates against totalCoins for the native asset. Uses `--code <CODE>` and `--issuer <ISSUER>` to specify the asset. Uses the native asset if neither `--code` nor `--issuer` is given.
4146
* **catchup <DESTINATION-LEDGER/LEDGER-COUNT>**: Perform catchup from history

src/main/CommandLine.cpp

Lines changed: 11 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,6 +1903,11 @@ applyLoadModeParser(std::string& modeArg, ApplyLoadMode& mode)
19031903
mode = ApplyLoadMode::MAX_SAC_TPS;
19041904
return "";
19051905
}
1906+
if (iequals(modeArg, "limits-for-model-tx"))
1907+
{
1908+
mode = ApplyLoadMode::FIND_LIMITS_FOR_MODEL_TX;
1909+
return "";
1910+
}
19061911
return "Unrecognized apply-load mode. Please select 'ledger-limits' "
19071912
"or 'max-sac-tps'.";
19081913
};
@@ -1931,7 +1936,11 @@ runApplyLoad(CommandLineArgs const& args)
19311936
config.TESTING_UPGRADE_MAX_TX_SET_SIZE = 1000;
19321937
config.LEDGER_PROTOCOL_VERSION =
19331938
Config::CURRENT_LEDGER_PROTOCOL_VERSION;
1934-
1939+
if (config.APPLY_LOAD_NUM_LEDGERS == 0)
1940+
{
1941+
throw std::runtime_error(
1942+
"APPLY_LOAD_NUM_LEDGERS must be greater than 0");
1943+
}
19351944
if (mode == ApplyLoadMode::MAX_SAC_TPS)
19361945
{
19371946
if (config.APPLY_LOAD_MAX_SAC_TPS_MIN_TPS >=
@@ -2024,109 +2033,7 @@ runApplyLoad(CommandLineArgs const& args)
20242033
{"ledger", "transaction", "total-apply"});
20252034
totalTxApplyTime.Clear();
20262035

2027-
if (mode == ApplyLoadMode::MAX_SAC_TPS)
2028-
{
2029-
al.findMaxSacTps();
2030-
return 0;
2031-
}
2032-
2033-
if (config.APPLY_LOAD_NUM_LEDGERS == 0)
2034-
{
2035-
throw std::runtime_error(
2036-
"APPLY_LOAD_NUM_LEDGERS must be greater than 0");
2037-
}
2038-
2039-
for (size_t i = 0; i < config.APPLY_LOAD_NUM_LEDGERS; ++i)
2040-
{
2041-
app.getBucketManager()
2042-
.getLiveBucketList()
2043-
.resolveAllFutures();
2044-
releaseAssert(app.getBucketManager()
2045-
.getLiveBucketList()
2046-
.futuresAllResolved());
2047-
al.benchmark();
2048-
}
2049-
2050-
CLOG_INFO(Perf, "Max ledger close: {} milliseconds",
2051-
ledgerClose.max());
2052-
CLOG_INFO(Perf, "Min ledger close: {} milliseconds",
2053-
ledgerClose.min());
2054-
CLOG_INFO(Perf, "Mean ledger close: {} milliseconds",
2055-
ledgerClose.mean());
2056-
CLOG_INFO(Perf, "stddev ledger close: {} milliseconds",
2057-
ledgerClose.std_dev());
2058-
2059-
CLOG_INFO(Perf, "Max CPU ins ratio: {}",
2060-
cpuInsRatio.max() / 1000000);
2061-
CLOG_INFO(Perf, "Mean CPU ins ratio: {}",
2062-
cpuInsRatio.mean() / 1000000);
2063-
2064-
CLOG_INFO(Perf, "Max CPU ins ratio excl VM: {}",
2065-
cpuInsRatioExclVm.max() / 1000000);
2066-
CLOG_INFO(Perf, "Mean CPU ins ratio excl VM: {}",
2067-
cpuInsRatioExclVm.mean() / 1000000);
2068-
CLOG_INFO(Perf, "stddev CPU ins ratio excl VM: {}",
2069-
cpuInsRatioExclVm.std_dev() / 1000000);
2070-
2071-
CLOG_INFO(Perf, "Ledger Max CPU ins ratio: {}",
2072-
ledgerCpuInsRatio.max() / 1000000);
2073-
CLOG_INFO(Perf, "Ledger Mean CPU ins ratio: {}",
2074-
ledgerCpuInsRatio.mean() / 1000000);
2075-
CLOG_INFO(Perf, "Ledger stddev CPU ins ratio: {}",
2076-
ledgerCpuInsRatio.std_dev() / 1000000);
2077-
2078-
CLOG_INFO(Perf, "Ledger Max CPU ins ratio excl VM: {}",
2079-
ledgerCpuInsRatioExclVm.max() / 1000000);
2080-
CLOG_INFO(Perf, "Ledger Mean CPU ins ratio excl VM: {}",
2081-
ledgerCpuInsRatioExclVm.mean() / 1000000);
2082-
CLOG_INFO(
2083-
Perf,
2084-
"Ledger stddev CPU ins ratio excl VM: {} milliseconds",
2085-
ledgerCpuInsRatioExclVm.std_dev() / 1000000);
2086-
// Utilization metrics are relevant only in limit-based
2087-
// mode.
2088-
if (mode == ApplyLoadMode::LIMIT_BASED)
2089-
{
2090-
CLOG_INFO(Perf,
2091-
"Tx count utilization min/avg/max {}/{}/{}%",
2092-
al.getTxCountUtilization().min() / 1000.0,
2093-
al.getTxCountUtilization().mean() / 1000.0,
2094-
al.getTxCountUtilization().max() / 1000.0);
2095-
CLOG_INFO(Perf,
2096-
"Instruction utilization min/avg/max {}/{}/{}%",
2097-
al.getInstructionUtilization().min() / 1000.0,
2098-
al.getInstructionUtilization().mean() / 1000.0,
2099-
al.getInstructionUtilization().max() / 1000.0);
2100-
CLOG_INFO(Perf, "Tx size utilization min/avg/max {}/{}/{}%",
2101-
al.getTxSizeUtilization().min() / 1000.0,
2102-
al.getTxSizeUtilization().mean() / 1000.0,
2103-
al.getTxSizeUtilization().max() / 1000.0);
2104-
CLOG_INFO(
2105-
Perf,
2106-
"Disk read bytes utilization min/avg/max {}/{}/{}%",
2107-
al.getDiskReadByteUtilization().min() / 1000.0,
2108-
al.getDiskReadByteUtilization().mean() / 1000.0,
2109-
al.getDiskReadByteUtilization().max() / 1000.0);
2110-
CLOG_INFO(Perf,
2111-
"Write bytes utilization min/avg/max {}/{}/{}%",
2112-
al.getDiskWriteByteUtilization().min() / 1000.0,
2113-
al.getDiskWriteByteUtilization().mean() / 1000.0,
2114-
al.getDiskWriteByteUtilization().max() / 1000.0);
2115-
CLOG_INFO(
2116-
Perf,
2117-
"Disk read entry utilization min/avg/max {}/{}/{}%",
2118-
al.getDiskReadEntryUtilization().min() / 1000.0,
2119-
al.getDiskReadEntryUtilization().mean() / 1000.0,
2120-
al.getDiskReadEntryUtilization().max() / 1000.0);
2121-
CLOG_INFO(Perf,
2122-
"Write entry utilization min/avg/max {}/{}/{}%",
2123-
al.getWriteEntryUtilization().min() / 1000.0,
2124-
al.getWriteEntryUtilization().mean() / 1000.0,
2125-
al.getWriteEntryUtilization().max() / 1000.0);
2126-
}
2127-
2128-
CLOG_INFO(Perf, "Tx Success Rate: {:f}%",
2129-
al.successRate() * 100);
2036+
al.execute();
21302037
}
21312038

21322039
return 0;

src/main/Config.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,19 +1742,18 @@ Config::processConfig(std::shared_ptr<cpptoml::table> t)
17421742
}},
17431743
{"APPLY_LOAD_NUM_LEDGERS",
17441744
[&]() { APPLY_LOAD_NUM_LEDGERS = readInt<uint32_t>(item); }},
1745-
{"APPLY_LOAD_MAX_SAC_TPS_TARGET_CLOSE_TIME_MS",
1745+
{"APPLY_LOAD_TARGET_CLOSE_TIME_MS",
17461746
[&]() {
1747-
APPLY_LOAD_MAX_SAC_TPS_TARGET_CLOSE_TIME_MS =
1747+
APPLY_LOAD_TARGET_CLOSE_TIME_MS =
17481748
readInt<uint32_t>(item, 1);
1749-
if (APPLY_LOAD_MAX_SAC_TPS_TARGET_CLOSE_TIME_MS %
1750-
ApplyLoad::MAX_SAC_TPS_TIME_STEP_MS !=
1749+
if (APPLY_LOAD_TARGET_CLOSE_TIME_MS %
1750+
ApplyLoad::TARGET_CLOSE_TIME_STEP_MS !=
17511751
0)
17521752
{
1753-
throw std::invalid_argument(
1754-
fmt::format(FMT_STRING("APPLY_LOAD_MAX_SAC_TPS_"
1755-
"TARGET_CLOSE_TIME_MS must "
1756-
"be a multiple of {}."),
1757-
ApplyLoad::MAX_SAC_TPS_TIME_STEP_MS));
1753+
throw std::invalid_argument(fmt::format(
1754+
FMT_STRING("APPLY_LOAD_TARGET_CLOSE_TIME_MS "
1755+
"must be a multiple of {}."),
1756+
ApplyLoad::TARGET_CLOSE_TIME_STEP_MS));
17581757
}
17591758
}},
17601759
{"APPLY_LOAD_MAX_SAC_TPS_MIN_TPS",

src/main/Config.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,16 @@ class Config : public std::enable_shared_from_this<Config>
386386

387387
uint32_t APPLY_LOAD_LEDGER_MAX_DEPENDENT_TX_CLUSTERS = 1;
388388

389+
// Number of ledgers to apply in apply-load.
390+
// Depending on the mode this represents either the total number of ledgers
391+
// to close for benchmarking, or the number of ledgers to apply per
392+
// iteration of binary search for modes that perform search.
389393
uint32_t APPLY_LOAD_NUM_LEDGERS = 100;
390394

395+
// Target ledger close time in milliseconds for modes that perform binary
396+
// search of TPS or limits.
397+
uint32_t APPLY_LOAD_TARGET_CLOSE_TIME_MS = 1000;
398+
391399
// Number of classic transactions to include in each ledger in ledger limit
392400
// based apply-load mode.
393401
uint32_t APPLY_LOAD_CLASSIC_TXS_PER_LEDGER = 0;
@@ -412,7 +420,6 @@ class Config : public std::enable_shared_from_this<Config>
412420
std::vector<uint32_t> APPLY_LOAD_EVENT_COUNT_DISTRIBUTION;
413421

414422
// MAX_SAC_TPS mode specific parameters
415-
uint32_t APPLY_LOAD_MAX_SAC_TPS_TARGET_CLOSE_TIME_MS = 1000;
416423
uint32_t APPLY_LOAD_MAX_SAC_TPS_MIN_TPS = 100;
417424
uint32_t APPLY_LOAD_MAX_SAC_TPS_MAX_TPS = 50000;
418425

0 commit comments

Comments
 (0)