Skip to content

Commit 0f58a0d

Browse files
authored
Optimize PackedFieldDescriptor to avoid Bit operations; DO_MAX_1000_COLUMNS definition (#200)
* Optimize `PackedFieldDescriptor` to avoid Bit operations * Group fields * AggressiveInlining * `DO_MAX_1000_COLUMNS` conditional compilation * bugfix * Add fieldCount > 1000 check * Error message * Error message * Correct tests for DO_MAX_1000_COLUMNS * Exclude test
1 parent 73ca08e commit 0f58a0d

10 files changed

+143
-70
lines changed

Directory.Build.props

+1
Original file line numberDiff line numberDiff line change
@@ -143,5 +143,6 @@
143143

144144
<DefineConstants Condition="'$(DO_SAFE_COLLECTION_WRAPPER)'=='true'">$(DefineConstants);DO_SAFE_COLLECTION_WRAPPER</DefineConstants>
145145
<DefineConstants Condition="'$(DO_CONFIGURE_AWAIT_FALSE)'=='true'">$(DefineConstants);DO_CONFIGURE_AWAIT_FALSE</DefineConstants>
146+
<DefineConstants Condition="'$(DO_MAX_1000_COLUMNS)'!='false'">$(DefineConstants);DO_MAX_1000_COLUMNS</DefineConstants>
146147
</PropertyGroup>
147148
</Project>

Orm/Xtensive.Orm.Tests/Storage/CommandProcessing/BatchingCommandProcessorParametersManagement.cs

+2
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,9 @@ public void InsertTest07()
729729
}
730730
}
731731

732+
#if !DO_MAX_1000_COLUMNS
732733
[Test]
734+
#endif
733735
public void InsertTest08()
734736
{
735737
using (var session = Domain.OpenSession())

Orm/Xtensive.Orm.Tests/Storage/CommandProcessing/ParametersManagementModel.cs

+9-1
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,15 @@ public void OnDefinitionsBuilt(BuildingContext context, DomainModelDef model)
162162
var originalCount = context.Domain.Handlers.ProviderInfo.MaxQueryParameterCount;
163163
var maxcount = originalCount;
164164

165+
#if DO_MAX_1000_COLUMNS
166+
if (maxcount > 989) {
167+
maxcount = 989;
168+
}
169+
#else
165170
if (maxcount > 1024) {
166171
maxcount = 1000;
167172
}
168-
173+
#endif
169174
var validFieldCount = maxcount - 1;
170175
var invalidFieldCount = validFieldCount + 10;
171176
var t = model.Types[typeof(ALotOfFieldsEntityValid)];
@@ -220,6 +225,9 @@ public void OnDefinitionsBuilt(BuildingContext context, DomainModelDef model)
220225
indexToWrite = 0;
221226
currentFieldCount = 0;
222227
var fieldsCount = 2100;
228+
#if DO_MAX_1000_COLUMNS
229+
fieldsCount = 990;
230+
#endif
223231
foreach (var fieldName in GetFieldNames(fieldsCount)) {
224232
_ = types[indexToWrite].DefineField(fieldName, typeof(int));
225233
currentFieldCount++;

Orm/Xtensive.Orm/Tuples/Packed/PackedFieldAccessor.cs

+14-14
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,12 @@ public override object GetUntypedValue(PackedTuple tuple, PackedFieldDescriptor
146146
{
147147
var state = tuple.GetFieldState(descriptor);
148148
fieldState = state;
149-
return state == TupleFieldState.Available ? tuple.Objects[descriptor.GetObjectIndex()] : null;
149+
return state == TupleFieldState.Available ? tuple.Objects[descriptor.Index] : null;
150150
}
151151

152152
public override void SetUntypedValue(PackedTuple tuple, PackedFieldDescriptor descriptor, object value)
153153
{
154-
tuple.Objects[descriptor.GetObjectIndex()] = value;
154+
tuple.Objects[descriptor.Index] = value;
155155
tuple.SetFieldState(descriptor, value != null ? TupleFieldState.Available : (TupleFieldState.Available | TupleFieldState.Null));
156156
}
157157

@@ -161,18 +161,18 @@ public override void SetValue(PackedTuple tuple, PackedFieldDescriptor descripto
161161
public override void CopyValue(PackedTuple source, PackedFieldDescriptor sourceDescriptor,
162162
PackedTuple target, PackedFieldDescriptor targetDescriptor)
163163
{
164-
target.Objects[targetDescriptor.GetObjectIndex()] = source.Objects[sourceDescriptor.GetObjectIndex()];
164+
target.Objects[targetDescriptor.Index] = source.Objects[sourceDescriptor.Index];
165165
}
166166

167167
public override bool ValueEquals(PackedTuple left, PackedFieldDescriptor leftDescriptor,
168168
PackedTuple right, PackedFieldDescriptor rightDescriptor)
169169
{
170-
return Equals(left.Objects[leftDescriptor.GetObjectIndex()], right.Objects[rightDescriptor.GetObjectIndex()]);
170+
return Equals(left.Objects[leftDescriptor.Index], right.Objects[rightDescriptor.Index]);
171171
}
172172

173173
public override int GetValueHashCode(PackedTuple tuple, PackedFieldDescriptor descriptor)
174174
{
175-
return tuple.Objects[descriptor.GetObjectIndex()]?.GetHashCode() ?? 0;
175+
return tuple.Objects[descriptor.Index]?.GetHashCode() ?? 0;
176176
}
177177

178178
public ObjectFieldAccessor()
@@ -265,14 +265,14 @@ private void SetNullableValue(PackedTuple tuple, PackedFieldDescriptor descripto
265265
protected virtual void Store(PackedTuple tuple, PackedFieldDescriptor d, T value)
266266
{
267267
var encoded = Encode(value);
268-
ref var block = ref tuple.Values[d.GetValueIndex()];
269-
var valueBitOffset = d.GetValueBitOffset();
268+
ref var block = ref tuple.Values[d.Index];
269+
var valueBitOffset = d.ValueBitOffset;
270270
var mask = ValueBitMask << valueBitOffset;
271271
block = (block & ~mask) | ((encoded << valueBitOffset) & mask);
272272
}
273273

274274
protected virtual T Load(PackedTuple tuple, PackedFieldDescriptor d) =>
275-
Decode((tuple.Values[d.GetValueIndex()] >> d.GetValueBitOffset()) & ValueBitMask);
275+
Decode((tuple.Values[d.Index] >> d.ValueBitOffset) & ValueBitMask);
276276

277277
protected ValueFieldAccessor(int bits, byte index)
278278
: base(bits, index)
@@ -569,15 +569,15 @@ internal sealed class GuidFieldAccessor : ValueFieldAccessor<Guid>
569569
protected override Guid Load(PackedTuple tuple, PackedFieldDescriptor d)
570570
{
571571
unsafe {
572-
fixed (long* valuePtr = &tuple.Values[d.GetValueIndex()])
572+
fixed (long* valuePtr = &tuple.Values[d.Index])
573573
return *(Guid*) valuePtr;
574574
}
575575
}
576576

577577
protected override void Store(PackedTuple tuple, PackedFieldDescriptor d, Guid value)
578578
{
579579
unsafe {
580-
fixed (long* valuePtr = &tuple.Values[d.GetValueIndex()])
580+
fixed (long* valuePtr = &tuple.Values[d.Index])
581581
*(Guid*) valuePtr = value;
582582
}
583583
}
@@ -601,15 +601,15 @@ internal sealed class DecimalFieldAccessor : ValueFieldAccessor<decimal>
601601
protected override decimal Load(PackedTuple tuple, PackedFieldDescriptor d)
602602
{
603603
unsafe {
604-
fixed (long* valuePtr = &tuple.Values[d.GetValueIndex()])
604+
fixed (long* valuePtr = &tuple.Values[d.Index])
605605
return *(decimal*) valuePtr;
606606
}
607607
}
608608

609609
protected override void Store(PackedTuple tuple, PackedFieldDescriptor d, decimal value)
610610
{
611611
unsafe {
612-
fixed (long* valuePtr = &tuple.Values[d.GetValueIndex()])
612+
fixed (long* valuePtr = &tuple.Values[d.Index])
613613
*(decimal*) valuePtr = value;
614614
}
615615
}
@@ -628,15 +628,15 @@ internal sealed class DateTimeOffsetFieldAccessor : ValueFieldAccessor<DateTimeO
628628
protected override DateTimeOffset Load(PackedTuple tuple, PackedFieldDescriptor d)
629629
{
630630
unsafe {
631-
fixed (long* valuePtr = &tuple.Values[d.GetValueIndex()])
631+
fixed (long* valuePtr = &tuple.Values[d.Index])
632632
return *(DateTimeOffset*) valuePtr;
633633
}
634634
}
635635

636636
protected override void Store(PackedTuple tuple, PackedFieldDescriptor d, DateTimeOffset value)
637637
{
638638
unsafe {
639-
fixed (long* valuePtr = &tuple.Values[d.GetValueIndex()])
639+
fixed (long* valuePtr = &tuple.Values[d.Index])
640640
*(DateTimeOffset*) valuePtr = value;
641641
}
642642
}

Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptiorExtensions.cs

-20
This file was deleted.

Orm/Xtensive.Orm/Tuples/Packed/PackedFieldDescriptor.cs

+85-4
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,97 @@
55
// Created: 2012.12.29
66

77
using System;
8+
using System.Runtime.CompilerServices;
89

910
namespace Xtensive.Tuples.Packed
1011
{
1112
[Serializable]
1213
internal struct PackedFieldDescriptor
1314
{
14-
internal int DataPosition;
15-
internal ushort StatePosition;
15+
#if DO_MAX_1000_COLUMNS
16+
private int bitFields;
1617

17-
[NonSerialized]
18+
internal int Index
19+
{
20+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
21+
get => bitFields & 0x7FF;
22+
23+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
24+
set => bitFields = bitFields & ~0x7FF | value;
25+
}
26+
27+
internal int StateIndex
28+
{
29+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
30+
get => (bitFields >> 11) & 0x1F;
31+
32+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
33+
set => bitFields = bitFields & ~(0x1F << 11) | (value << 11);
34+
}
35+
36+
internal int ValueBitOffset
37+
{
38+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
39+
get => (bitFields >> 16) & 0x3F;
40+
41+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
42+
set => bitFields = bitFields & ~0x3F0000 | (value << 16);
43+
}
44+
45+
internal int StateBitOffset
46+
{
47+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
48+
get => (bitFields >> 21) & 0x3E; // Even always
49+
50+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
51+
set => bitFields = bitFields & ~(0x3E << 21) | (value << 21);
52+
}
53+
54+
internal int AccessorIndex
55+
{
56+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
57+
get => (bitFields >> 27) & 0x1F;
58+
59+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
60+
set => bitFields = bitFields & ~(0x1F << 27) | (value << 27);
61+
}
62+
#else
63+
internal ushort Index;
64+
internal ushort StateIndex;
65+
internal byte ValueBitOffset;
66+
internal byte StateBitOffset;
1867
internal byte AccessorIndex;
68+
69+
#endif // DO_MAX_1000_COLUMNS
70+
71+
internal int DataPosition
72+
{
73+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
74+
set {
75+
Index = (ushort) (value >> 6);
76+
ValueBitOffset = (byte) (value & 0x3F);
77+
}
78+
}
79+
80+
internal int StatePosition
81+
{
82+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
83+
set {
84+
StateIndex = (ushort) (value >> 6);
85+
StateBitOffset = (byte) (value & 0x3F);
86+
}
87+
}
88+
89+
internal PackedFieldAccessor Accessor
90+
{
91+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
92+
get => PackedFieldAccessor.All[AccessorIndex];
93+
}
94+
95+
internal bool IsObjectField
96+
{
97+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
98+
get => Accessor.Rank < 0;
99+
}
19100
}
20-
}
101+
}

Orm/Xtensive.Orm/Tuples/Packed/PackedTuple.cs

+13-16
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public override bool Equals(Tuple other)
5555
return false;
5656
}
5757
if (thisState == TupleFieldState.Available &&
58-
!descriptor.GetAccessor().ValueEquals(this, descriptor, packedOther, descriptor)) {
58+
!descriptor.Accessor.ValueEquals(this, descriptor, packedOther, descriptor)) {
5959
return false;
6060
}
6161
}
@@ -72,7 +72,7 @@ public override int GetHashCode()
7272
ref readonly var descriptor = ref fieldDescriptors[i];
7373
var state = GetFieldState(descriptor);
7474
var fieldHash = state == TupleFieldState.Available
75-
? descriptor.GetAccessor().GetValueHashCode(this, descriptor)
75+
? descriptor.Accessor.GetValueHashCode(this, descriptor)
7676
: 0;
7777
result = HashCodeMultiplier * result ^ fieldHash;
7878
}
@@ -94,27 +94,27 @@ protected internal override void SetFieldState(int fieldIndex, TupleFieldState f
9494
public override object GetValue(int fieldIndex, out TupleFieldState fieldState)
9595
{
9696
ref readonly var descriptor = ref PackedDescriptor.FieldDescriptors[fieldIndex];
97-
return descriptor.GetAccessor().GetUntypedValue(this, descriptor, out fieldState);
97+
return descriptor.Accessor.GetUntypedValue(this, descriptor, out fieldState);
9898
}
9999

100100
public override T GetValue<T>(int fieldIndex, out TupleFieldState fieldState)
101101
{
102102
var isNullable = null == default(T); // Is nullable value type or class
103103
ref readonly var descriptor = ref PackedDescriptor.FieldDescriptors[fieldIndex];
104-
return descriptor.GetAccessor().GetValue<T>(this, descriptor, isNullable, out fieldState);
104+
return descriptor.Accessor.GetValue<T>(this, descriptor, isNullable, out fieldState);
105105
}
106106

107107
public override void SetValue(int fieldIndex, object fieldValue)
108108
{
109109
ref readonly var descriptor = ref PackedDescriptor.FieldDescriptors[fieldIndex];
110-
descriptor.GetAccessor().SetUntypedValue(this, descriptor, fieldValue);
110+
descriptor.Accessor.SetUntypedValue(this, descriptor, fieldValue);
111111
}
112112

113113
public override void SetValue<T>(int fieldIndex, T fieldValue)
114114
{
115115
var isNullable = null==default(T); // Is nullable value type or class
116116
ref readonly var descriptor = ref PackedDescriptor.FieldDescriptors[fieldIndex];
117-
descriptor.GetAccessor().SetValue(this, descriptor, isNullable, fieldValue);
117+
descriptor.Accessor.SetValue(this, descriptor, isNullable, fieldValue);
118118
}
119119

120120
public override void SetValueFromDataReader(in MapperReader mr)
@@ -124,27 +124,24 @@ public override void SetValueFromDataReader(in MapperReader mr)
124124
}
125125
else {
126126
ref readonly var descriptor = ref PackedDescriptor.FieldDescriptors[mr.FieldIndex];
127-
descriptor.GetAccessor().SetValue(this, descriptor, mr);
127+
descriptor.Accessor.SetValue(this, descriptor, mr);
128128
}
129129
}
130130

131131
public void SetFieldState(PackedFieldDescriptor d, TupleFieldState fieldState)
132132
{
133133
var bits = (long) fieldState;
134-
ref var block = ref Values[d.GetStateIndex()];
135-
var stateBitOffset = d.GetStateBitOffset();
134+
ref var block = ref Values[d.StateIndex];
135+
var stateBitOffset = d.StateBitOffset;
136136
block = (block & ~(3L << stateBitOffset)) | (bits << stateBitOffset);
137137

138-
if (fieldState != TupleFieldState.Available && d.IsObjectField()) {
139-
Objects[d.GetObjectIndex()] = null;
138+
if (fieldState != TupleFieldState.Available && d.IsObjectField) {
139+
Objects[d.Index] = null;
140140
}
141141
}
142142

143-
public TupleFieldState GetFieldState(PackedFieldDescriptor d)
144-
{
145-
int stateIndex = d.GetStateIndex(), stateBitOffset = d.GetStateBitOffset();
146-
return (TupleFieldState) ((Values[stateIndex] >> stateBitOffset) & 3);
147-
}
143+
public TupleFieldState GetFieldState(PackedFieldDescriptor d) =>
144+
(TupleFieldState) ((Values[d.StateIndex] >> d.StateBitOffset) & 3);
148145

149146
public PackedTuple(in TupleDescriptor descriptor)
150147
{

0 commit comments

Comments
 (0)