-
Notifications
You must be signed in to change notification settings - Fork 73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[PH -> main] Performance Harness MVP [PH] #350
Conversation
Added unit tests for the tps_tester
…a_structures Capture data and create usable data structures storing data in performance_test_basic.py
…nfigurable_logging Performance harness cluster configurable logging
Refactored the trx_generator main code
…ons from performance_test_basic. Fix a bug in the test regarding cease block
Added tps_performance_monitor
…package Update to test harness python package
…scripts Refactor and Separate Python Script for Performance Harness
…row_chains [PH] Performance harness remove unnecessary throw chains
appArgs.add(flag="--produce-time-offset-us", type=int, help="Offset of non last block producing time in microseconds. Valid range 0 .. -block_time_interval.", default=0) | ||
appArgs.add(flag="--cpu-effort-percent", type=int, help="Percentage of cpu block production time used to produce block. Whole number percentages, e.g. 80 for 80%%", default=100) | ||
appArgs.add(flag="--last-block-cpu-effort-percent", type=int, help="Percentage of cpu block production time used to produce last block. Whole number percentages, e.g. 80 for 80%%", default=100) | ||
appArgs.add(flag="--http-max-response-time-ms", type=int, help="Maximum time for processing a request, -1 for unlimited", default=990000) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any alternative to replicating many of nodeos configuration options in a second location like this? (newer PRs have even more than the ~10 in this PR). Seems like a sneaky maintenance overhead, and especially prone to breakage for options not used by default.
A simple naive way to do this is to have a way to "forward" arguments to nodeos without the python code caring, For example instead of
perf.py --target-tps --test-duration-sec 60 --genesis ~/genesis.json --signature-cpu-billable-pct 50 --chain-state-db-size-mb 40
it becomes
perf.py --target-tps --test-duration-sec 60 -- --genesis ~/genesis.json --signature-cpu-billable-pct 50 --chain-state-db-size-mb 40
that is, everything after --
is simply forwarded along to nodeos.
Unfortunately that won't work here due to the defaults for these options in this performance test not being the same as the defaults of nodeos.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any alternative to replicating many of nodeos configuration options in a second location like this? (newer PRs have even more than the ~10 in this PR). Seems like a sneaky maintenance overhead, and especially prone to breakage for options not used by default.
Some thoughts here:
There are several alternatives that are being discussed down at the Regression Test Framework (TestHarness
) level, where TestHelper.py
, Node.py
and Cluster.py
boostrap the blockchain test environment. The Performance Harness MVP was not intending to implement those during this effort, but will look to take advantage of them and integrate with them when they occur.
Currently in Cluster.py
there is a catch-all argument extraNodeosArgs
that functions similarly to your suggestion to pass on any command line provided extra arguments, not explicitly supported by a command line argument, directly to nodeos
. However, in the Performance Harness there is a desire to have finer grain manipulation of configurations between specific nodes to measure specific configurations. We are trying to identify which arguments have performance impacts, and provide support directly for those. We are also providing defaults for most config options to either mirror those in nodeos
itself or those that have been tuned for performance due to empirical analysis.
As far as maintainability is concerned, there is a basic test being run in CI/CD, which should catch if any config items change at the nodeos
level that need to bubble up into the regression test and performance frameworks, since all config parameters used by the performance test (even those defaulted) are being passed to nodeos, and would cause a test failure if no longer matching nodeos
options.
An effort was just completed to group configuration options such that they would not have to be reproduced at each level of script in the Performance Harness. The use of ArgumentParser
parents
and groups
will help bubble component arguments up/down for reuse as well as provide groups for easier understanding of when to use each. That work is currently sitting in a PR for Stage 2 development here: #518.
Care was taken to make it easy to expand the supported set of nodeos
configuration options. Adding a new command line option to nodeos
is as simple as adding the argument in the ArgumentParser
and in the plugin args object (PerformanceBasicTest.ClusterConfig.ExtraNodeosArgs.*PluginArgs
).
[PH] main merge
The payload object can be extremely long when printing out during verbose logging. Rarely is the entire response needed for debugging. However, the code is often useful when something goes wrong. Reverse the order of code and payload so that, when trunctating printed responsed, the return code is always available. Truncate the response to 1024 characters.
[PH] Update response order and truncate when printing.
[PH] test tweaking
[PH] Test tweaking - Decrease perf expectations for lower performing vms in CI/CD
The current runners really aren't designed for running a reliable (consistent) performance test. I was already concerned with this change extending test time some some minute and half, but it seems like you're going to have to keep dialing down the test until it's reliable too. And even then it may have side effects on other tests (which have been somewhat sensitive already). I'm not sure at what point we move performance testing to proper consistent performance runners. |
We are currently only running one test, the |
Since it's just a smoke test, why not run it at something very low like 10 trx/sec or such? Getting it to pass on the CI runners should not be the goal: this is bucketed in as a unit test -- it must run and pass for users. If someone compiles Leap on a slow Raspberry Pi the expectation is that the unit tests pass. If we feel this smoke test needs to be 1000+ trx/sec then we likely need a new bucket of tests ( |
That's a good point. I agree. I'll lower the test performance expectations so it shouldn't ever have a problem passing. I do want to keep it requiring 2 transaction generators, but I can have them both churning out small amounts of trxs. I'll push up changes for this. @spoonincode -> Addressed here: be7640e |
removing block due to ongoing reviews
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I approve this MVP PR after discussions with Kevin, Peter and the team on a larger call due to the fact that it is standalone code, will not affect EOS Mainnet, and has been successfully tested by Kevin multiple times. This code tests a Leap node on a standalone box that cannot affect any other systems.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving based on Kevin's successful tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved based on today's discussion.
Performance Harness
The Performance Harness is configured and run through the main
performance_test.py
script. The script's main goal is to measure current peak performance metrics through iteratively tuning and running basic performance tests. The current basic test works to determine the maximum throughput of Token Transfers the system can sustain. It does this by conducting a binary search of possible Token Transfers Per Second (TPS) configurations, testing each configuration in a short duration test and scoring its result. The search algorithm iteratively configures and runsperformance_test_basic.py
tests and analyzes the output to determine a success metric used to continue the search. When the search completes, a max TPS throughput value is reported (along with other performance metrics from that run). The script then proceeds to conduct an additional search with longer duration test runs within a narrowed TPS configuration range to determine the sustainable max TPS. Finally it produces a report on the entire performance run, summarizing each individual test scenario, results, and full report details on the tests when maximum TPS was achieved (Performance Test Report)The
performance_test_basic.py
support script performs a single basic performance test that targets a configurable TPS target and, if successful, reports statistics on performance metrics measured during the test. It configures and launches a blockchain test environment, creates wallets and accounts for testing, and configures and launches transaction generators for creating specific transaction load in the ecosystem. Finally it analyzes the performance of the system under the configuration through log analysis and chain queries and produces a Performance Test Basic Report.The
launch_generators.py
support script provides a means to easily calculate and spawn the number of transaction generator instances to generate a given target TPS, distributing generation load between the instances in a fair manner such that the aggregate load meets the requested test load.The
log_reader.py
support script is used primarily to analyzenodeos
log files to glean information about generated blocks and transactions within those blocks after a test has concluded. This information is used to produce the performance test report. In similar fashion,read_log_data.py
allows for recreating a report from the configuration and log files without needing to rerun the test.Prerequisites
Please refer to Leap: Build and Install from Source for a full list of prerequisites.
New dependency - python NumPy, a package for scientific computing with Python.
If running on Ubuntu 18.04 an additional dependency will need to be installed to support modern python dataclasses:
python3 -m pip install dataclasses
Steps
--del-perf-logs
. Additionally, final reports will be collected by default. To omit final reports, use--del-report
and/or--del-test-report
.Navigate to performance test logs directory
cd ./build/performance_test/
Log Directory Structure is hierarchical with each run of the
performance_test.py
reporting into a timestamped directory where it includes the full performance report as well as a directory containing output from each test type run (here,performance_test_basic.py
) and each individual test run outputs into a timestamped directory that may contain block data logs and transaction generator logs as well as the test's basic report. An example directory structure follows:Expand Example Directory Structure
Configuring Performance Harness Tests
Performance Test
The Performance Harness main script
performance_test.py
can be configured using the following command line arguments:Expand Argument List
-p P
producing nodes count (default: 1)-n N
total nodes (default: 0)-d D
delay between nodes startup (default: 1)--nodes-file NODES_FILE
File containing nodes info in JSON format. (default: None)
-s {mesh}
topology (default: mesh)--dump-error-details
Upon error printetc/eosio/node_*/config.ini
andvar/lib/node_*/stderr.log
to stdout (default: False)-v
verbose logging (default: False)--leave-running
Leave cluster running after test finishes (default: False)--clean-run
Kill all nodeos and keosd instances (default: False)--max-tps-to-test MAX_TPS_TO_TEST
The max target transfers realistic as ceiling of test range (default: 50000)
--test-iteration-duration-sec TEST_ITERATION_DURATION_SEC
The duration of transfer trx generation for each iteration of the test during the initial search (seconds) (default: 30)
--test-iteration-min-step TEST_ITERATION_MIN_STEP
The step size determining granularity of tps result during initial search (default: 500)
--final-iterations-duration-sec FINAL_ITERATIONS_DURATION_SEC
The duration of transfer trx generation for each final longer run iteration of the test during
the final search (seconds) (default: 90)
--tps-limit-per-generator TPS_LIMIT_PER_GENERATOR
Maximum amount of transactions per second a single generator can have. (default: 4000)
--genesis GENESIS
Path to genesis.json (default: tests/performance_tests/genesis.json)--num-blocks-to-prune NUM_BLOCKS_TO_PRUNE
The number of potentially non-empty blocks, in addition to leading and trailing size 0 blocks,
to prune from the beginning and end of the range of blocks of interest for evaluation.
(default: 2)
--signature-cpu-billable-pct SIGNATURE_CPU_BILLABLE_PCT
Percentage of actual signature recovery cpu to bill. Whole number percentages, e.g. 50 for 50% (default: 0)
--chain-state-db-size-mb CHAIN_STATE_DB_SIZE_MB
Maximum size (in MiB) of the chain state database (default: 10240)
--disable-subjective-billing DISABLE_SUBJECTIVE_BILLING
Disable subjective CPU billing for API/P2P transactions (default: True)
--last-block-time-offset-us LAST_BLOCK_TIME_OFFSET_US
Offset of last block producing time in microseconds. Valid range 0 .. -block_time_interval. (default: 0)
--produce-time-offset-us PRODUCE_TIME_OFFSET_US
Offset of non last block producing time in microseconds. Valid range 0 .. -block_time_interval. (default: 0)
--cpu-effort-percent CPU_EFFORT_PERCENT
Percentage of cpu block production time used to produce block. Whole number percentages, e.g. 80 for 80% (default: 100)
--last-block-cpu-effort-percent LAST_BLOCK_CPU_EFFORT_PERCENT
Percentage of cpu block production time used to produce last block. Whole number percentages, e.g. 80 for 80% (default: 100)
--http-max-response-time-ms HTTP_MAX_RESPONSE_TIME_MS
Maximum time for processing a request, -1 for unlimited (default: 990000)
--del-perf-logs
Whether to delete performance test specific logs. (default: False)--del-report
Whether to delete overarching performance run report. (default: False)--del-test-report
Whether to save json reports from each test scenario. (default: False)--quiet
Whether to quiet printing intermediate results and reports to stdout (default: False)--prods-enable-trace-api
Determines whether producer nodes should have eosio::trace_api_plugin enabled (default: False)
Support Scripts
The following scripts are typically used by the Performance Harness main script
performance_test.py
to perform specific tasks as delegated and configured by the main script. However, there may be applications in certain use cases where running a single one-off test or transaction generator is desired. In those situations, the following argument details might be useful to understanding how to run these utilities in stand-alone mode. The argument breakdown may also be useful in understanding how the Performance Harness main script's arguments are being passed through to configure lower-level entities.Performance Test Basic
performance_test_basic.py
can be configured using the following command line arguments:Expand Argument List
-p P
producing nodes count (default: 1)-n N
total nodes (default: 0)-d D
delay between nodes startup (default: 1)--nodes-file NODES_FILE
File containing nodes info in JSON format. (default: None)
-s {mesh}
topology (default: mesh)--dump-error-details
Upon error printetc/eosio/node_*/config.ini
andvar/lib/node_*/stderr.log
to stdout (default: False)-v
verbose logging (default: False)--leave-running
Leave cluster running after test finishes (default: False)--clean-run
Kill all nodeos and keosd instances (default: False)--target-tps TARGET_TPS
The target transfers per second to send during test (default: 8000)
--tps-limit-per-generator TPS_LIMIT_PER_GENERATOR
Maximum amount of transactions per second a single generator can have. (default: 4000)
--test-duration-sec TEST_DURATION_SEC
The duration of transfer trx generation for the test in seconds (default: 30)
--genesis GENESIS
Path to genesis.json (default: tests/performance_tests/genesis.json)--num-blocks-to-prune NUM_BLOCKS_TO_PRUNE
The number of potentially non-empty blocks, in addition to leading and trailing size 0 blocks, to prune from the beginning and end
of the range of blocks of interest for evaluation. (default: 2)
--signature-cpu-billable-pct SIGNATURE_CPU_BILLABLE_PCT
Percentage of actual signature recovery cpu to bill. Whole number percentages, e.g. 50 for 50% (default: 0)
--chain-state-db-size-mb CHAIN_STATE_DB_SIZE_MB
Maximum size (in MiB) of the chain state database (default: 10240)
--disable-subjective-billing DISABLE_SUBJECTIVE_BILLING
Disable subjective CPU billing for API/P2P transactions (default: True)
--last-block-time-offset-us LAST_BLOCK_TIME_OFFSET_US
Offset of last block producing time in microseconds. Valid range 0 .. -block_time_interval. (default: 0)
--produce-time-offset-us PRODUCE_TIME_OFFSET_US
Offset of non last block producing time in microseconds. Valid range 0 .. -block_time_interval. (default: 0)
--cpu-effort-percent CPU_EFFORT_PERCENT
Percentage of cpu block production time used to produce block. Whole number percentages, e.g. 80 for 80% (default: 100)
--last-block-cpu-effort-percent LAST_BLOCK_CPU_EFFORT_PERCENT
Percentage of cpu block production time used to produce last block. Whole number percentages, e.g. 80 for 80% (default: 100)
--http-max-response-time-ms HTTP_MAX_RESPONSE_TIME_MS
Maximum time for processing a request, -1 for unlimited (default: 990000)
--del-perf-logs
Whether to delete performance test specific logs. (default: False)--del-report
Whether to delete overarching performance run report. (default: False)--quiet
Whether to quiet printing intermediate results and reports to stdout (default: False)--prods-enable-trace-api
Determines whether producer nodes should have eosio::trace_api_plugin enabled (default: False)
Launch Transaction Generators
launch_transaction_generators.py
can be configured using the following command line arguments:Expand Argument List
chain_id
set the chain idlast_irreversible_block_id
Current last-irreversible-block-id (LIB ID) to use for transactions.handler_account
Account name of the handler account for the transfer actionsaccounts
Comma separated list of account namespriv_keys
Comma separated list of private keys.trx_gen_duration
Transaction generation duration (seconds). Defaults to 60 seconds.target_tps
Target transactions per second to generate/send.tps_limit_per_generator
Maximum amount of transactions per second a single generator can have.log_dir
set the logs directoryTransaction Generator
The Transaction Generator is a program built to create and send transactions at a specified rate in order to generate load on a blockchain. It is comprised of 3 main components: Transaction Generator, Transaction Provider, and Performance Monitor.
The
trx_generator.[hpp, cpp]
is currently specialized to be atransfer_trx_generator
primarily focused on generating token transfer transactions. The transactions are then provided to the network by thetrx_provider.[hpp, cpp]
which is currently aimed at the P2P network protocol in thep2p_trx_provider
. The third component, thetps_performance_monitor
, allows the Transaction Generator to monitor its own performance and take action to notify and exit if it is unable to keep up with the requested transaction generation rate.The Transaction Generator logs each transaction's id and sent timestamp at the moment the Transaction Provider sends the transaction. Logs are written to the configured log directory and will follow the naming convention
trx_data_output_10744.txt
where10744
is the transaction generator instance's process ID.Configuration Options
./build/tests/trx_generator/trx_generator
can be configured using the following command line arguments:Expand Argument List
--chain-id arg
set the chain id--handler-account arg
Account name of the handler account forthe transfer actions
--accounts arg
comma-separated list of accounts thatwill be used for transfers. Minimum
required accounts: 2.
--priv-keys arg
comma-separated list of private keys insame order of accounts list that will
be used to sign transactions. Minimum
required: 2.
--trx-expiration arg
(=3600) transaction expiration time in seconds.Defaults to 3,600. Maximum allowed:
3,600
--trx-gen-duration arg
(=60) Transaction generation duration(seconds). Defaults to 60 seconds.
--target-tps arg
(=1) Target transactions per second togenerate/send. Defaults to 1
transaction per second.
--last-irreversible-block-id arg
Current last-irreversible-block-id (LIBID) to use for transactions.
--monitor-spinup-time-us arg
(=1000000)Number of microseconds to wait before
monitoring TPS. Defaults to 1000000
(1s).
--monitor-max-lag-percent arg
(=5) Max percentage off from expectedtransactions sent before being in
violation. Defaults to 5.
--monitor-max-lag-duration-us arg
(=1000000)Max microseconds that transaction
generation can be in violation before
quitting. Defaults to 1000000 (1s).
--log-dir arg
set the logs directoryResult Reports
Performance Test Report
The Performance Harness generates a report to summarize results of test scenarios as well as overarching results of the performance harness run. By default the report described below will be written to the top level timestamped directory for the performance run with the file name
report.json
. To omit final report, use--del-report
.Command used to run test and generate report:
Report Breakdown
The report begins by delivering the max TPS results of the performance run.
InitialMaxTpsAchieved
- the max TPS throughput achieved during initial, short duration test scenarios to narrow search windowLongRunningMaxTpsAchieved
- the max TPS throughput achieved during final, longer duration test scenarios to zero in on sustainable max TPSNext, a summary of the search scenario conducted and respective results is included. Each summary includes information on the current state of the overarching search as well as basic results of the individual test that are used to determine whether the basic test was considered successful. The list of summary results are included in
InitialSearchResults
andLongRunningSearchResults
. The number of entries in each list will vary depending on the TPS range tested (--max-tps-to-test
) and the configured--test-iteration-min-step
.Expand Search Scenario Summary Example
Finally, the full detail test report for each of the determined max TPS throughput (
InitialMaxTpsAchieved
andLongRunningMaxTpsAchieved
) runs is included after each scenario summary list in the full report. Note: In the example full report below, these have been truncated as they are single performance test basic run reports as detailed in the following section Performance Test Basic Report. Herein these truncated reports appear as:Expand Truncated Report Example
Expand for full sample Performance Test Report
Performance Test Basic Report
The Performance Test Basic generates, by default, a report that details results of the test, statistics around metrics of interest, as well as diagnostic information about the test run. If
performance_test.py
is run with--del-test-report
, orperformance_test_basic.py
is run with--del-report
, the report described below will not be written. Otherwise the report will be written to the timestamped directory within theperformance_test_basic
log directory for the test run with the file namedata.json
.Expand for full sample report
Supported nodeos versions
The Performance Harness currently supports scraping/analyzing nodeos v 2.0.14 log format up to the current format (v3+).