-
Notifications
You must be signed in to change notification settings - Fork 1k
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
ReferenceCounterV2
#3526
base: master
Are you sure you want to change the base?
ReferenceCounterV2
#3526
Changes from 22 commits
22c2107
51ce4ba
a4b936b
01445c2
bc2e52e
93c42fc
cab91ca
71cc724
e158c5f
37c1c00
c0efc7c
6352c5b
8276180
21e5434
066cc8b
9347754
57f122e
75ccbae
e2a10e5
0a85aad
e38f73e
a79dd96
4986c54
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Copyright (C) 2015-2024 The Neo Project. | ||
// | ||
// Benchmarks.ReferenceCounter.cs file belongs to the neo project and is free | ||
// software distributed under the MIT software license, see the | ||
// accompanying file LICENSE in the main directory of the | ||
// repository or http://www.opensource.org/licenses/mit-license.php | ||
// for more details. | ||
// | ||
// Redistribution and use in source and binary forms with or without | ||
// modifications are permitted. | ||
|
||
using BenchmarkDotNet.Attributes; | ||
using Neo.Test; | ||
using Neo.Test.Extensions; | ||
using Neo.Test.Types; | ||
using System.Text; | ||
|
||
namespace Neo.VM.Benchmark | ||
{ | ||
public class Benchmarks_ReferenceCounter : VMJsonTestBase | ||
{ | ||
[Benchmark] | ||
public void V2() | ||
{ | ||
Run<ReferenceCounterV2>(); | ||
} | ||
|
||
[Benchmark] | ||
public void V1() | ||
{ | ||
Run<ReferenceCounter>(); | ||
} | ||
|
||
private void Run<T>() where T : IReferenceCounter, new() | ||
{ | ||
var path = Path.GetFullPath("../../../../../../../../../tests/Neo.VM.Tests/Tests"); | ||
|
||
foreach (var file in Directory.GetFiles(path, "*.json", SearchOption.AllDirectories)) | ||
{ | ||
var realFile = Path.GetFullPath(file); | ||
var json = File.ReadAllText(realFile, Encoding.UTF8); | ||
var ut = json.DeserializeJson<VMUT>(); | ||
|
||
try | ||
{ | ||
ExecuteTest<T>(ut); | ||
} | ||
catch (Exception ex) | ||
{ | ||
throw new AggregateException("Error in file: " + realFile, ex); | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
// Copyright (C) 2015-2024 The Neo Project. | ||
// | ||
// ReferenceCounterV2.cs file belongs to the neo project and is free | ||
// software distributed under the MIT software license, see the | ||
// accompanying file LICENSE in the main directory of the | ||
// repository or http://www.opensource.org/licenses/mit-license.php | ||
// for more details. | ||
// | ||
// Redistribution and use in source and binary forms with or without | ||
// modifications are permitted. | ||
|
||
using Neo.VM.Types; | ||
using System; | ||
using System.Collections.Generic; | ||
|
||
namespace Neo.VM | ||
{ | ||
/// <summary> | ||
/// Used for reference counting of objects in the VM. | ||
/// </summary> | ||
public sealed class ReferenceCounterV2 : IReferenceCounter | ||
{ | ||
private readonly List<StackItem> _stack = []; | ||
|
||
/// <summary> | ||
/// Gets the count of references. | ||
/// </summary> | ||
public int Count => _stack.Count; | ||
|
||
/// <summary> | ||
/// Adds item to Reference Counter | ||
/// </summary> | ||
/// <param name="item">The item to add.</param> | ||
/// <param name="count">Number of similar entries</param> | ||
public void AddStackReference(StackItem item, int count = 1) | ||
{ | ||
for (var x = 0; x < count; x++) | ||
{ | ||
if (item is CompoundType compound && ReferenceEqualsIndexOf(item) == -1) | ||
{ | ||
// Add sub items only if it was not present | ||
|
||
foreach (var subItem in compound.SubItems) | ||
{ | ||
AddStackReference(subItem); | ||
} | ||
} | ||
|
||
_stack.Add(item); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Removes item from Reference Counter | ||
/// </summary> | ||
/// <param name="item">The item to remove.</param> | ||
public void RemoveStackReference(StackItem item) | ||
{ | ||
var indexOf = ReferenceEqualsIndexOf(item); | ||
|
||
if (indexOf == -1) | ||
{ | ||
throw new InvalidOperationException("Reference was not added before"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This version is not compatible with circular references, but at the same it works like a protection |
||
} | ||
|
||
_stack.RemoveAt(indexOf); | ||
|
||
if (item is CompoundType compound && ReferenceEqualsIndexOf(item, indexOf) == -1) | ||
{ | ||
// Remove all the childrens only if the compound is not present | ||
|
||
foreach (var subItem in compound.SubItems) | ||
{ | ||
RemoveStackReference(subItem); | ||
} | ||
} | ||
} | ||
|
||
private int ReferenceEqualsIndexOf(StackItem item, int index = 0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's complexity is O(n), may not fast in some cases. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this version is slower than I expected, I tried with different ways, and still slower than expected |
||
{ | ||
// Note: List use Equals, and Struct don't allow to use it, so we iterate over the list | ||
|
||
for (; index < _stack.Count; index++) | ||
{ | ||
if (ReferenceEquals(_stack[index], item)) | ||
{ | ||
return index; | ||
} | ||
} | ||
|
||
return -1; | ||
} | ||
|
||
public void AddReference(StackItem item, CompoundType parent) | ||
{ | ||
if (ReferenceEqualsIndexOf(parent) != -1) | ||
{ | ||
// Add only if the parent is present | ||
|
||
AddStackReference(item); | ||
} | ||
} | ||
|
||
public void RemoveReference(StackItem item, CompoundType parent) | ||
{ | ||
if (ReferenceEqualsIndexOf(parent) != -1) | ||
{ | ||
// Remove only if the parent is present | ||
|
||
RemoveStackReference(item); | ||
} | ||
} | ||
|
||
public void AddZeroReferred(StackItem item) | ||
{ | ||
// This version don't use this method | ||
} | ||
|
||
/// <summary> | ||
/// Checks and processes items that have zero references. | ||
/// </summary> | ||
/// <returns>The current reference count.</returns> | ||
public int CheckZeroReferred() | ||
{ | ||
return Count; | ||
} | ||
} | ||
} |
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.
this actually is not necessary, currently we process his when we create the compound type. For instance, new array will pass the rc and add all its subitems.
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 know it, but it's hard to explain, there are cases where the items are removed without exists.
maybe is not this case that i remember, but when the stack was clean, I received "item not found" error