আমি একটি পারফরম্যান্স সমালোচনামূলক বাইনারি সিদ্ধান্ত গাছ পেয়েছি, এবং আমি এই প্রশ্নটি কোডের একক লাইনে ফোকাস করতে চাই। বাইনারি ট্রি আইট্রেটারের কোডটি এর বিপরীতে কার্য সম্পাদন বিশ্লেষণের ফলাফল সহ নীচে রয়েছে।
public ScTreeNode GetNodeForState(int rootIndex, float[] inputs)
{
0.2% ScTreeNode node = RootNodes[rootIndex].TreeNode;
24.6% while (node.BranchData != null)
{
0.2% BranchNodeData b = node.BranchData;
0.5% node = b.Child2;
12.8% if (inputs[b.SplitInputIndex] <= b.SplitValue)
0.8% node = b.Child1;
}
0.4% return node;
}
ব্রাঞ্চডেটা একটি ক্ষেত্র, সম্পত্তি নয়। এর ঝুঁকি যাতে অন্তর্ভুক্ত না হয় সে জন্য আমি এটি করেছি।
ব্রাঞ্চনোডেটা ক্লাসটি নিম্নরূপ:
public sealed class BranchNodeData
{
/// <summary>
/// The index of the data item in the input array on which we need to split
/// </summary>
internal int SplitInputIndex = 0;
/// <summary>
/// The value that we should split on
/// </summary>
internal float SplitValue = 0;
/// <summary>
/// The nodes children
/// </summary>
internal ScTreeNode Child1;
internal ScTreeNode Child2;
}
যেমন আপনি দেখতে পাচ্ছেন, সেই সময় লুপ / নাল চেকটি পারফরম্যান্সে একটি বিশাল হিট। গাছটি বিশাল, তাই আমি একটি পাতা সন্ধান করার জন্য কিছু সময় নেওয়ার আশা করব, তবে আমি সেই এক লাইনে ব্যয়বহুল পরিমাণ ব্যয় করতে চাই।
আমি চেষ্টা করেছিলাম:
- নল চেকটি কিছুক্ষণ থেকে আলাদা করা - এটি হ'ল নল চেক।
- বস্তুটিতে একটি বুলিয়ান ক্ষেত্র যুক্ত করা এবং এর বিপরীতে পরীক্ষা করা, এতে কোনও তফাত হয়নি। কী তুলনা করা হচ্ছে তা বিবেচ্য নয়, এটি তুলনা এটিই।
এটি কি শাখার পূর্বাভাসের বিষয়? যদি তা হয় তবে আমি এটি সম্পর্কে কী করতে পারি? কিছু হলে?
আমি সিআইএল বোঝার ভান করব না তবে আমি এটি কারও জন্য পোস্ট করব যাতে তারা এ থেকে কিছু তথ্য নষ্ট করার চেষ্টা করতে পারে।
.method public hidebysig
instance class OptimalTreeSearch.ScTreeNode GetNodeForState (
int32 rootIndex,
float32[] inputs
) cil managed
{
// Method begins at RVA 0x2dc8
// Code size 67 (0x43)
.maxstack 2
.locals init (
[0] class OptimalTreeSearch.ScTreeNode node,
[1] class OptimalTreeSearch.BranchNodeData b
)
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Collections.Generic.List`1<class OptimalTreeSearch.ScRootNode> OptimalTreeSearch.ScSearchTree::RootNodes
IL_0006: ldarg.1
IL_0007: callvirt instance !0 class [mscorlib]System.Collections.Generic.List`1<class OptimalTreeSearch.ScRootNode>::get_Item(int32)
IL_000c: ldfld class OptimalTreeSearch.ScTreeNode OptimalTreeSearch.ScRootNode::TreeNode
IL_0011: stloc.0
IL_0012: br.s IL_0039
// loop start (head: IL_0039)
IL_0014: ldloc.0
IL_0015: ldfld class OptimalTreeSearch.BranchNodeData OptimalTreeSearch.ScTreeNode::BranchData
IL_001a: stloc.1
IL_001b: ldloc.1
IL_001c: ldfld class OptimalTreeSearch.ScTreeNode OptimalTreeSearch.BranchNodeData::Child2
IL_0021: stloc.0
IL_0022: ldarg.2
IL_0023: ldloc.1
IL_0024: ldfld int32 OptimalTreeSearch.BranchNodeData::SplitInputIndex
IL_0029: ldelem.r4
IL_002a: ldloc.1
IL_002b: ldfld float32 OptimalTreeSearch.BranchNodeData::SplitValue
IL_0030: bgt.un.s IL_0039
IL_0032: ldloc.1
IL_0033: ldfld class OptimalTreeSearch.ScTreeNode OptimalTreeSearch.BranchNodeData::Child1
IL_0038: stloc.0
IL_0039: ldloc.0
IL_003a: ldfld class OptimalTreeSearch.BranchNodeData OptimalTreeSearch.ScTreeNode::BranchData
IL_003f: brtrue.s IL_0014
// end loop
IL_0041: ldloc.0
IL_0042: ret
} // end of method ScSearchTree::GetNodeForState
সম্পাদনা: আমি একটি শাখার পূর্বাভাস পরীক্ষা করার সিদ্ধান্ত নিয়েছি, কিছুক্ষণের মধ্যে যদি আমি একটি অভিন্ন যোগ করেছি, তাই আমাদের রয়েছে
while (node.BranchData != null)
এবং
if (node.BranchData != null)
যে ভিতরে। আমি তারপরে পারফরম্যান্স বিশ্লেষণ চালিয়েছিলাম এবং প্রথম তুলনাটি কার্যকর করতে এটি ছয় গুণ বেশি সময় নিয়েছিল কারণ এটি সর্বদা সত্য প্রত্যাবর্তনকারী দ্বিতীয় তুলনাটি কার্যকর করতে হয়েছিল। সুতরাং দেখে মনে হচ্ছে এটি সত্যিই একটি শাখার পূর্বাভাসের বিষয় - এবং আমি অনুমান করছি যে এটি সম্পর্কে আমি কিছুই করতে পারি না !?
অন্য সম্পাদনা
উপরের ফলাফলটিও ঘটতে পারে যদি নোড.ব্রেঞ্চডাটা কিছুক্ষণ চেক করার জন্য র্যাম থেকে লোড করতে হয় - তবে এটি যদি বিবৃতিতে ক্যাশে হয়।
এটি একটি অনুরূপ বিষয়ে আমার তৃতীয় প্রশ্ন। এবার আমি কোডের একক লাইনে ফোকাস করছি। এই বিষয়ে আমার অন্যান্য প্রশ্নগুলি হ'ল:
while(true) { /* current body */ if(node.BranchData == null) return node; }
। এটি কিছু পরিবর্তন করে?
while(true) { BranchNodeData b = node.BranchData; if(ReferenceEquals(b, null)) return node; node = b.Child2; if (inputs[b.SplitInputIndex] <= b.SplitValue) node = b.Child1; }
এটি node. BranchData
কেবল একবারে পুনরুদ্ধার হবে ।
BranchNode
সম্পত্তি বাস্তবায়ন দেখান । প্রতিস্থাপন করার চেষ্টা করুনnode.BranchData != null
ReferenceEquals(node.BranchData, null)
। এটা কি কোনো পার্থক্য তৈরি করে?