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

Some VM optimizations #2128

Merged
merged 7 commits into from
Aug 13, 2021
Merged

Some VM optimizations #2128

merged 7 commits into from
Aug 13, 2021

Conversation

fyrchik
Copy link
Contributor

@fyrchik fyrchik commented Aug 12, 2021

  1. Simplify BigInteger and Bool items.
  2. Remove map from refcounter.
  3. Don't copy the parameter.

It is always copied.

Signed-off-by: Evgeniy Stratonikov <[email protected]>
Remove one indirection step.
``
name       old time/op    new time/op    delta
MakeInt-8    79.7ns ± 8%    56.2ns ± 8%  -29.44%  (p=0.000 n=10 10)

name       old alloc/op   new alloc/op   delta
MakeInt-8     48.0B ± 0%     40.0B ± 0%  -16.67%  (p=0.000 n=10 10)

name       old allocs/op  new allocs/op  delta
MakeInt-8      3.00 ± 0%      2.00 ± 0%  -33.33%  (p=0.000 n=10 10)
```

Signed-off-by: Evgeniy Stratonikov <[email protected]>
@roman-khimov roman-khimov added this to the v0.97.2 milestone Aug 12, 2021
Copy link
Member

@roman-khimov roman-khimov left a comment

Choose a reason for hiding this comment

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

Can we also simplify ByteArray, Buffer and Pointer items?

pkg/vm/ref_counter.go Outdated Show resolved Hide resolved
@@ -171,8 171,7 @@ func (c *Context) Next() (opcode.Opcode, []byte, error) {
if err != nil {
return instr, nil, err
}
parameter := make([]byte, numtoread)
copy(parameter, c.prog[c.nextip:c.nextip numtoread])
parameter := c.prog[c.nextip : c.nextip numtoread]
Copy link
Member

Choose a reason for hiding this comment

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

This reminds me of golang/go#27975, but until we have it we need to trace what exactly is happening to this parameter.

We have it being used in compiler/test code, but it's not dangerous there.

ParseSignatureContract and ParseMultiSigContract return it, but all current users are safe, they only read these values.

PrintOps also reads things.

And then we have v.execute with a hell a lot of options. It's used for GetPrice, but it doesn't care. It's used to push integers onto the stack, but that inevitably leads to bigint.FromBytes, so not a problem. It's used for PUSHDATA, but we'll get to it later. Then PUSHA, ISTYPE, CONVERT, slot-related opcodes, NEW*, JMP*, CALL*, and *TRY* all read their parameters from it and it's all fine.

The most problematic case is PUSHDATA, because that's where a ByteArray item is created containing reference to this data. By design ByteArray is an immutable type (kinda like string), unlike Buffer, but we still need to check it.

We can use it in MEMCPY, but only as a source that we copy data from. CAT can take it, but it also copies data from both of its parameters. SUBSTR, LEFT and RIGHT copy too. PICKITEM reads one byte and SIZE takes a len(). It can also be used in exception-handling code, but it's converted to string there immediately.

We have conversions though. Conversions to ByteArray don't copy data, but it's ByteArray, so it should be safe, Buffer does slice.Copy and Integer and Bool return new respective values. Equals doesn't change anything.

So, we're safe?

Copy link
Member

Choose a reason for hiding this comment

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

Anyway, I think it's worth mentioning in Next documentation that this parameter points to script data and user is responsible for copying it if needed.

Signed-off-by: Evgeniy Stratonikov <[email protected]>
`Next` doesn't longer copy parameter.

Signed-off-by: Evgeniy Stratonikov <[email protected]>
@fyrchik
Copy link
Contributor Author

fyrchik commented Aug 13, 2021

@roman-khimov updated for ByteArray and Buffer items. I am clueless about how we may simplify the Pointer though.

@codecov
Copy link

codecov bot commented Aug 13, 2021

Codecov Report

Merging #2128 (6879f76) into master (5aff82a) will increase coverage by 0.37%.
The diff coverage is 98.27%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2128       /-   ##
==========================================
  Coverage   84.07%   84.44%    0.37%     
==========================================
  Files         290      291        1     
  Lines       27356    27966      610     
==========================================
  Hits        22999    23616      617     
  Misses       3085     3069      -16     
- Partials     1272     1281        9     
Impacted Files Coverage Δ
pkg/vm/stackitem/item.go 92.00% <97.14%> ( 0.49%) ⬆️
pkg/compiler/codegen.go 93.26% <100.00%> (-0.03%) ⬇️
pkg/smartcontract/convertor.go 91.66% <100.00%> (ø)
pkg/vm/context.go 86.99% <100.00%> (-0.11%) ⬇️
pkg/vm/ref_counter.go 100.00% <100.00%> (ø)
pkg/vm/stackitem/json.go 96.22% <100.00%> (ø)
pkg/vm/stackitem/reference.go 100.00% <100.00%> (ø)
pkg/vm/stackitem/serialization.go 95.62% <100.00%> (ø)
pkg/vm/vm.go 94.49% <100.00%> (-0.01%) ⬇️
pkg/core/storage/leveldb_store.go 86.04% <0.00%> (-7.51%) ⬇️
... and 13 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5aff82a...6879f76. Read the comment docs.

@roman-khimov
Copy link
Member

I am clueless about how we may simplify the Pointer though.

Meh, I wanted to tell about Interop, that can be just an alias to interface{}.

@fyrchik
Copy link
Contributor Author

fyrchik commented Aug 13, 2021

@roman-khimov Go disallows declaring methods on aliases to interfaces.

pkg/vm/ref_counter.go Outdated Show resolved Hide resolved
pkg/vm/ref_counter.go Outdated Show resolved Hide resolved
return &ByteArray{
value: b,
}
return (*ByteArray)(&b)
}

// Value implements Item interface.
func (i *ByteArray) Value() interface{} {
Copy link
Member

Choose a reason for hiding this comment

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

Can pointer be avoided here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It certainly can, though I am not sure this will speed-up things: while there is 1 less indirection step, we will copy 2.5 as much data for every method.

Copy link
Member

Choose a reason for hiding this comment

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

OK, let it be the way it is for now and we can always get back to it later.

Copy link
Member

Choose a reason for hiding this comment

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

I'd expect it to be somewhat faster, but it just needs some testing.

```
name              old time/op  new time/op  delta
RefCounter_Add-8  44.8ns ± 4%  11.7ns ± 3%  -73.94%  (p=0.000 n=10 10)
```

Signed-off-by: Evgeniy Stratonikov <[email protected]>
@roman-khimov roman-khimov merged commit 5b12dd2 into master Aug 13, 2021
@roman-khimov roman-khimov deleted the vm-update-int branch August 13, 2021 13:16
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