Skip to content
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

Introduce global optimiser settings. #5959

Merged
merged 7 commits into from
Mar 4, 2019
Merged

Introduce global optimiser settings. #5959

merged 7 commits into from
Mar 4, 2019

Conversation

chriseth
Copy link
Contributor

@chriseth chriseth commented Feb 7, 2019

Replaces PR #2600
References issue #1658

Apart from exporting the settings via the metadata, this should be a pure refactoring.

Still todo:

  • enable the yul optimiser based on the settings
  • parse the settings from standard-json-io
  • parse the settings from the commandline (do we really want 100% control from the CLI?)

@chriseth
Copy link
Contributor Author

chriseth commented Feb 7, 2019

If we agree on the metadata strings, we can already merge it like this.

@chriseth chriseth force-pushed the optimiser2 branch 2 times, most recently from d5e72d0 to 1a34e66 Compare February 7, 2019 19:51
@codecov
Copy link

codecov bot commented Feb 7, 2019

Codecov Report

Merging #5959 into develop will increase coverage by <.01%.
The diff coverage is 87.82%.

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #5959      +/-   ##
===========================================
+ Coverage    87.91%   87.92%   +<.01%     
===========================================
  Files          374      375       +1     
  Lines        35771    35973     +202     
  Branches      4220     4245      +25     
===========================================
+ Hits         31447    31628     +181     
- Misses        2901     2910       +9     
- Partials      1423     1435      +12
Flag Coverage Δ
#all 87.92% <87.82%> (ø) ⬆️
#syntax 27.17% <3.35%> (-0.14%) ⬇️

@chriseth
Copy link
Contributor Author

chriseth commented Feb 7, 2019

Compilation error for emscripten:

/root/project/libsolidity/interface/CompilerStack.cpp:934:64: error: result of comparison of constant 18446744073709551615 with expression of type 'const size_t' (aka 'const unsigned long') is always true [-Werror,-Wtautological-constant-out-of-range-compare]
        solAssert(m_optimiserSettings.expectedExecutionsPerDeployment < std::numeric_limits<Json::LargestUInt>::max(), "");
                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/root/project/liblangutil/Exceptions.h:45:21: note: expanded from macro 'solAssert'

I believe we already had something like that in the past. Anyone remembers how we solved it?

@ekpyron
Copy link
Member

ekpyron commented Feb 11, 2019

@chriseth The emscripten compile error is due to the emscripten build having 32-bit size_t - so to avoid the assertion from being trivial due to type constraints, we need to cast, but we have to be careful not to defeat the purpose of the assertion by doing so (due to potentially truncating during the cast...)...
The following would probably do it, but is not particularly nice:

solAssert(u256(m_optimiserSettings.expectedExecutionsPerDeployment) < u256(std::numeric_limits<Json::LargestUInt>::max()), "")

C++17 would be nice here, then we could do

if constexpr (sizeof(m_optimiserSettings.expectedExecutionsPerDeployment) >= sizeof(Json::LargestUInt))
    solAssert(m_optimiserSettings.expectedExecutionsPerDeployment < std::numeric_limits<Json::LargestUInt>::max(), "");

Maybe there's a nicer solution, but that's the problem in any case.

EDIT:
Maybe the following is best:

static_assert(sizeof(m_optimiserSettings.expectedExecutionsPerDeployment) <= sizeof(JSon::LargestUint));
solAssert(static_cast<JSon::LargestUint>(m_optimiserSettings.expectedExecutionsPerDeployment) < std::numeric_limits<Json::LargestUInt>::max(), "")

@chriseth chriseth force-pushed the optimiser2 branch 3 times, most recently from 322a657 to e2eb48a Compare February 11, 2019 16:06
@chriseth chriseth changed the title Introduce global optimiser settings. [WIP] Introduce global optimiser settings. Feb 11, 2019
@axic
Copy link
Member

axic commented Feb 19, 2019

I suggest the following:

  1. If any fine-grained setting is provided in standard json, then the enabled option cannot be present.
  2. If the fine-grained settings equal to that of the default enabled: false or enabled: true, then the metadata only contains the enabled field, but not the fine-grained settings. Otherwise only the fine-grained settings are stored.

In 0.6.0 we may revisit dropping enabled.

@axic
Copy link
Member

axic commented Feb 19, 2019

From off-line discussion: it seems that introducing a new sub-level for optimiser "details" is a better approach.

Example:

    // Optional: Optimizer settings. The fields "enabled" and "runs" are deprecated
    // and are only given for backwards-compatibility.
    optimizer: {
      enabled: true,
      runs: 200,
      details: {
          // peephole defaults to "true"
          peephole: true,
          // jumpdestRemover defaults to "true"
          jumpdestRemover: true,
          orderLiterals: false,
          deduplicate: false,
          cse: false,
          constantOptimizer: false,
          yul: true
          yulDetails: {}
      },
    },

Subtleties:

  • if the enabled field is set to false, optimisations are entirely disabled and the metadata will not contain the details object.
  • if the enabled field is set to true, optimisations are enabled with a default preset. The details object can be present and can modify these settings. If the details section changes any of the settings from the default present, the entire object is included in the metadata.

The runs parameter is still preferred to be renamed to expectedExecutionsPerDeployment, but that seems to be a breaking change. Also don't forget that as of late, this field is used outside of the optimiser to determine the optimal layout of the "ABI dispatcher code", therefore it is suggested to be moved outside of the optimizer object. This should be done in a separate change together with renaming the field.

@chriseth
Copy link
Contributor Author

If "details" is not a member, optimizer will be in "default disabled" mode, which mean peephole and jumpdest remover are still on.

@chriseth
Copy link
Contributor Author

@axic should we also add a "stackAllocation" option to the optimizer? This would then activate the _allowStackOpt switch of CodeTransform.

@chriseth
Copy link
Contributor Author

Hm, that could just be the yul optimizer option.

@chriseth chriseth changed the title [WIP] Introduce global optimiser settings. Introduce global optimiser settings. Feb 21, 2019
@chriseth
Copy link
Contributor Author

Updated.

axic
axic previously approved these changes Mar 1, 2019
@axic
Copy link
Member

axic commented Mar 1, 2019

All of the gas tests are broken and every single one becomes more expensive. Any idea why? This PR shouldn't change behaviour of the optimiser.

@@ -153,7 +153,7 @@ bytes compileFirstExpression(
parametersSize--
);

ExpressionCompiler(context).compile(*extractor.expression());
ExpressionCompiler(context, dev::test::Options::get().optimize).compile(*extractor.expression());
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason for these tests to change was that we did not take the global test parameter into account before. I think this is a good test, because it shows the effect of order literals optimization.

Copy link
Member

Choose a reason for hiding this comment

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

But all the deployment sizes increased.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, the non-optimized expectations are unchanged.

Compiler compiler(dev::test::Options::get().evmVersion());
Compiler compiler(
dev::test::Options::get().evmVersion(),
dev::test::Options::get().optimize ? OptimiserSettings::enabled() : OptimiserSettings::minimal()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same here, optimizer setting was ignored before.

@chriseth
Copy link
Contributor Author

chriseth commented Mar 1, 2019

I also don't understand why the commandline tests changed - will have to investigate. It might be that "stack allocation" was activated before when the optimizer was activated, now it can only be activated manually.

@chriseth
Copy link
Contributor Author

chriseth commented Mar 4, 2019

Ok, the problem in the commandline tests was actually related to the invalid reference noted above.

Copy link
Member

@axic axic left a comment

Choose a reason for hiding this comment

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

On the assumption that apart from the const& change this is identical to last week.

@chriseth
Copy link
Contributor Author

chriseth commented Mar 4, 2019

Yep, removed the reference and also removed the test expectation changes the reference caused.

@chriseth chriseth merged commit 2e0ea16 into develop Mar 4, 2019
@axic axic deleted the optimiser2 branch March 4, 2019 11:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants