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

Enable test_memory #1077

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
59 changes: 30 additions & 29 deletions Src/IronPython/Runtime/Types/PythonType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public partial class PythonType : IPythonMembersList, IDynamicMetaObjectProvider
private PythonTypeAttributes _attrs; // attributes of the type
private int _flags; // CPython-like flags on the type
private int _version = GetNextVersion(); // version of the type
private List<WeakReference> _subtypes; // all of the subtypes of the PythonType
private List<WeakReference<PythonType>> _subtypes; // all of the subtypes of the PythonType
private PythonContext _pythonContext; // the context the type was created from, or null for system types.
private bool? _objectNew, _objectInit; // true if the type doesn't override __new__ / __init__ from object.
internal Dictionary<CachedGetKey, FastGetBase> _cachedGets; // cached gets on user defined type instances
Expand Down Expand Up @@ -76,7 +76,6 @@ public partial class PythonType : IPythonMembersList, IDynamicMetaObjectProvider
[MultiRuntimeAware]
private static int MasterVersion = 1;
private static readonly CommonDictionaryStorage _pythonTypes = new CommonDictionaryStorage();
private static readonly WeakReference[] _emptyWeakRef = Array.Empty<WeakReference>();
private static readonly object _subtypesLock = new object();
internal static readonly Func<string, Exception, Exception> DefaultMakeException = (message, innerException) => new Exception(message, innerException);
internal static readonly Func<string, Exception> DefaultMakeExceptionNoInnerException = (message) => new Exception(message);
Expand Down Expand Up @@ -680,17 +679,15 @@ public static PythonDictionary __prepare__([ParamDictionary]IDictionary<object,

public PythonList __subclasses__(CodeContext/*!*/ context) {
PythonList ret = new PythonList();
IList<WeakReference> subtypes = SubTypes;
var subtypes = SubTypes;

if (subtypes != null) {
PythonContext pc = context.LanguageContext;

foreach (WeakReference wr in subtypes) {
if (wr.IsAlive) {
PythonType pt = (PythonType)wr.Target;

foreach (var wr in subtypes) {
if (wr.TryGetTarget(out PythonType pt)) {
if (pt.PythonContext == null || pt.PythonContext == pc) {
ret.AddNoLock(wr.Target);
ret.AddNoLock(pt);
}
}
}
Expand Down Expand Up @@ -1270,8 +1267,8 @@ public static PythonDictionary __prepare__([ParamDictionary]IDictionary<object,
private void ClearObjectNewInSubclasses(PythonType pt) {
lock (_subtypesLock) {
if (pt._subtypes != null) {
foreach (WeakReference wr in pt._subtypes) {
if (wr.Target is PythonType type) {
foreach (var wr in pt._subtypes) {
if (wr.TryGetTarget(out PythonType type)) {
type._objectNew = null;

ClearObjectNewInSubclasses(type);
Expand All @@ -1284,8 +1281,8 @@ public static PythonDictionary __prepare__([ParamDictionary]IDictionary<object,
private void ClearObjectInitInSubclasses(PythonType pt) {
lock (_subtypesLock) {
if (pt._subtypes != null) {
foreach (WeakReference wr in pt._subtypes) {
if (wr.Target is PythonType type) {
foreach (var wr in pt._subtypes) {
if (wr.TryGetTarget(out PythonType type)) {
type._objectInit = null;

ClearObjectInitInSubclasses(type);
Expand Down Expand Up @@ -2465,9 +2462,9 @@ public static PythonDictionary __prepare__([ParamDictionary]IDictionary<object,
#region Private implementation details

private void UpdateVersion() {
foreach (WeakReference wr in SubTypes) {
if (wr.IsAlive) {
((PythonType)wr.Target).UpdateVersion();
foreach (var wr in SubTypes) {
if (wr.TryGetTarget(out PythonType pt)) {
pt.UpdateVersion();
}
}

Expand Down Expand Up @@ -2497,31 +2494,35 @@ public static PythonDictionary __prepare__([ParamDictionary]IDictionary<object,
null);
}
}

/// <summary>
/// Internal helper function to add a subtype
/// </summary>
private void AddSubType(PythonType subtype) {
if (_subtypes == null) {
Interlocked.CompareExchange<List<WeakReference>>(ref _subtypes, new List<WeakReference>(), null);
Interlocked.CompareExchange(ref _subtypes, new List<WeakReference<PythonType>>(), null);
}

lock (_subtypesLock) {
_subtypes.Add(new WeakReference(subtype));
if (_subtypes.Count == _subtypes.Capacity) {
_subtypes.RemoveAll(x => !x.TryGetTarget(out _)); // remove dead entries
}
_subtypes.Add(new WeakReference<PythonType>(subtype));
}
}

private void RemoveSubType(PythonType subtype) {
int i = 0;
if (_subtypes != null) {
lock (_subtypesLock) {
while (i < _subtypes.Count) {
if (!_subtypes[i].IsAlive || _subtypes[i].Target == subtype) {
_subtypes.RemoveAt(i);
continue;
}
i++;
if (_subtypes is null) return;

lock (_subtypesLock) {
int i = 0;
while (i < _subtypes.Count) {
var wr = _subtypes[i];
if (!wr.TryGetTarget(out PythonType target) || target == subtype) {
_subtypes.RemoveAt(i);
continue;
}
i++;
}
}
}
Expand All @@ -2530,9 +2531,9 @@ public static PythonDictionary __prepare__([ParamDictionary]IDictionary<object,
/// Gets a list of weak references to all the subtypes of this class. May return null
/// if there are no subtypes of the class.
/// </summary>
private IList<WeakReference> SubTypes {
private IList<WeakReference<PythonType>> SubTypes {
get {
if (_subtypes == null) return _emptyWeakRef;
if (_subtypes == null) return Array.Empty<WeakReference<PythonType>>();

lock (_subtypesLock) {
return _subtypes.ToArray();
Expand Down
7 changes: 3 additions & 4 deletions Src/IronPythonTest/Cases/IronPythonCasesManifest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,9 @@ Ignore=true
Reason=Assertion error

[IronPython.test_memory]
#RunCondition=NOT $(IS_POSIX)
#Reason=Memory allocation on Mono may not match MS.NET
Ignore=true
Reason=Fails intermittently - https://github.com/IronLanguages/ironpython3/issues/508
IsolationLevel=PROCESS # to avoid having a long list of object subtypes
RunCondition=NOT $(IS_MONO)
Reason=Memory allocation on Mono may not match MS.NET

[IronPython.test_number]
Timeout=300000 # 5 minute timeout - slow on macOS
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ def setUp(self):
from Microsoft.Scripting.Generation import Snippets

self.skipMemoryCheck = Snippets.Shared.SaveSnippets or clr.GetCurrentRuntime().Configuration.DebugMode
self.expectedMem = 24000

# account for adaptive compilation
self.expectedMem = 24000
if is_cli64:
self.expectedMem = int(self.expectedMem*1.25)

Expand Down