バインドされた統計

説明

統計バインド(7.7の新機能)は、オブジェクトで統計を追跡するための標準の方法です。これらの統計は、バインドされた統計、または単に統計と呼ばれます。

オブジェクトに統計を追加する

SimpleDataTypeを継承する任意のオブジェクトに統計を追加できます。これにはすべてのFlexSimObjects、FixedResources、TaskExecutorsが含まれます。統計を追加するには、次の手順に従います。

  1. オブジェクトの定義にTreeNode*メンバーを追加します。
    class MyObject : public FlexSimObject
    	{
    	public:
    		TreeNode* someStat = nullptr;
    		void bindStatistics() override;
    		...
  2. bindStatistics()メソッドをオーバーライドします。
    void MyObject::bindStatistics()
    	{
    		FlexSimObject::bindStatistics(); // bind the parent class statistics
    		bindStatistic(someStat, flags);
    		...
    flags引数はビットマスクで、タイプと、統計が時間加重かどうかを指定します。統計には3つのタイプがあります。
    • STAT_TYPE_LEVEL - デフォルトのタイプ。統計が増減し、現在の値はキュー内のコンテンツなど、何かの値のレベルを反映していることを意味します。
    • STAT_TYPE_INCREMENTAL - この種類の統計は、入力や出力など、常に増加するものです。
    • STAT_TYPE_STREAM - この種類の統計は、フローアイテムのプロセッサでの滞在時間など、値のセットを表します。
    各統計は、3つのうちいずれか1つのタイプです。オプションとして、typeフラグをSTAT_TIME_WEIGHTEDフラグとビット単位でorすることもできますが、これは通常はSTAT_TYPE_LEVEL統計でのみ行われます。
  3. 統計を更新するには、3つのマクロのいずれかを使用します。
    • UPDATE_SDT_STAT(statNode, newValue) - 統計を新しい値に設定します。
    • UPDATE_SDT_STAT_DELTA(statNode, delta) - 統計を古い値に設定し、デルタを加算します。
    • UPDATE_SDT_STAT_INCREMENTAL(statNode) - 統計を1だけ増やします。
    void MyObject::doStuff()
    	{
    		// ... object logic
    		UPDATE_SDT_STAT(someStat, value);
  4. オブジェクトがリセットされるとき、オブジェクトのすべての統計をアクティブにし、リセットします。
    enumerateStatistics(destNode, true);
    	StatisticBinding& binding = *(destNode->objectAs(StatisticBinding));
    					
    	for (StatisticBindingEntry& entry : binding) {
    		binding.select(entry.statName.getBuffer());
    		TrackedVariable* tv = sdt->assertStatistic(&binding)->objectAs(TrackedVariable);
    		tv->reset();
    		if ((entry.flags & STAT_TYPE_MASK) != STAT_TYPE_STREAM)
    			tv->set(0);
    	}
    この手法は、特に親クラスのメソッドで適切に動作し、呼び出し元の子クラスの統計をすべてリセットします。ストリーム以外の統計は0に設定されることに注意してください。これは、レベルおよび増加統計の初期値は0であるためです。リセット時ロジックでオブジェクトにアイテムが追加される場合、アイテムの追加時にリセットロジックとは別に、これらの統計を更新する必要があります。ストリーム統計(滞在時間など)の場合、その値についてデータが収集されていないため、通常は初期値がありません。

各統計はTrackedVariableオブジェクトにより表されます。assertStatistic()関数を使用すると、TrackedVariableを持つツリーノードが返されます。それによって、各統計の現在、平均、最大、最小の値を取得できます。ただし、増加統計については平均、最大、最小の値は意味を持ちません。

統計の列挙

オブジェクトで利用可能な統計を照会できます。前のセクションのステップ4が、その例です。この場合、オブジェクト自身の統計がすべて列挙されます。ただし、enumerateStatistics()メソッドも統計データをツリーノードのテーブルとして返すことができます。この動作を行うには、2番目のパラメータをfalseに設定します。

各統計には名前とフラグが存在します。フラグはビットマスクで、統計のタイプと、その統計が中継されるかどうかの情報が含まれています。

for (StatisticBindingEntry& statBindingEntry : listStatBinding) {
		if (statBindingEntry.flags & STAT_RELAYED) { /* check if a statistic is relayed */ }
		int numRequirements = sdt->getNumStatRequirementsFromFlags(statBindingEntry.flags);
		// numRequirements will be 0, 1, 2, or 3
		int statType = (statBindingEntry.flags & STAT_TYPE_MASK)
		// statType will be equal to 
		//     0 or STAT_TYPE_LEVEL (both are equivalent)
		//     STAT_TYPE_INCREMENTAL
		//     STAT_TYPE_STREAM

中継された統計

オブジェクトが管理するサブオブジェクトに、独自の統計が含まれることがあります。統計の中継により、サブオブジェクトの統計を、それを所有するオブジェクトで利用できます。たとえば、ListがPartitionsを管理し、Partitionsに統計が存在すると考えます。ListがPartitionsの統計を中継するため、これらの統計にListオブジェクトからアクセスできます。

オブジェクトが統計をサブオブジェクトに中継する場合、bindRelayedClassStatistics<>()関数(bindStatistics()メソッド内)を使用する必要があります。

たとえば、PartitionクラスのbindStatistics()メソッドを次に示します。

void List::Partition::bindStatistics()
	{
		SimpleDataType::bindStatistics();
		bindStatistic(content, STAT_TIME_WEIGHTED);
		bindStatistic(input, STAT_TYPE_INCREMENTAL);
		bindStatistic(output, STAT_TYPE_INCREMENTAL);
		bindStatistic(staytime, STAT_TYPE_STREAM);

		bindStatistic(backOrderContent, STAT_TIME_WEIGHTED);
		bindStatistic(backOrderInput, STAT_TYPE_INCREMENTAL);
		bindStatistic(backOrderOutput, STAT_TYPE_INCREMENTAL);
		bindStatistic(backOrderStaytime, STAT_TYPE_STREAM);
	}

ListはPartitionsを管理するので、これらの統計も中継します。

void List::bindStatistics()
	{
		ObjectDataType::bindStatistics();

		bindStatistic(input, STAT_TYPE_INCREMENTAL);
		bindStatistic(output, STAT_TYPE_INCREMENTAL);
		bindStatistic(content, STAT_TIME_WEIGHTED);
		bindStatistic(staytime, STAT_TYPE_STREAM);

		bindStatistic(backOrderInput, STAT_TYPE_INCREMENTAL);
		bindStatistic(backOrderOutput, STAT_TYPE_INCREMENTAL);
		bindStatistic(backOrderContent, STAT_TIME_WEIGHTED);
		bindStatistic(backOrderStaytime, STAT_TYPE_STREAM);

		bindRelayedClassStatistics<Partition>("Partition", STAT_1_REQUIREMENT, &List::partitionResolver, &List::getPartitionPossibilities);
	}

bindRelayedClassStatistics<>()関数はテンプレート関数です。テンプレートのパラメータは、統計の中継元となるクラスです。前の例では、Partitionクラスがテンプレートのパラメータになります。

bindRelayedClassStatistics<>()関数には4つの引数があります。

  1. プレフィックス - 統計名に付加される文字列。Listの統計を列挙するとき、Partitionのすべての統計が含まれますが、統計の名前にプレフィックスとして「Partition」が付けられ、「PartitionContent」のような名前になります。
  2. 要件の数。統計が中継されるため、これは統計の取得の要件が1、2、3個のどれかに応じてSTAT_1_REQUIREMENT、STAT_2_REQUIREMENTS、STAT_3_REQUIREMENTSのいずれかにする必要があります。
  3. 要件リゾルバ。これは、次の形式の関数です。
    TreeNode* resolver1(const Variant& p1)
    	TreeNode* resolver2(const Variant& p1, const Variant& p2)
    	TreeNode* resolver3(const Variant& p1, const Variant& p2, const Variant& p3)
    使用される関数は、要件の数が1、2、3個のどれかによって異なります。いずれの場合も、関数は与えられた要件をマップし、目的のオブジェクトを持つツリーノードを返します。たとえば、List::partitionResolverはパーティションIDを取得し、そのパーティションを含むツリーノードを返します。
  4. 可能性列挙子。これは、次の形式の関数です。
    int enumerator(TreeNode* destNode, const Variant& p1, const Variant& p2) {}
    この関数は与えられた要件を使用して、最後の要件として使用可能なノードをすべて列挙します。p1がnullバリアントなら、この関数はリゾルバのp1の可能な値のそれぞれについて、サブノードを追加します。p1がnullではなく、p2がnullなら、この関数はリゾルバのp2の可能な値のそれぞれについて、サブノードを追加します。それぞれの可能性について、要件の可能な値をポイントするdestNodeにサブノードを追加します。

    また、この関数はdestNodeの名前を、要件の名前に設定します。

    最後に、この関数は3つの値のいずれかを返します。
    • STAT_ENUM_REQS_INVALID - この値は、可能性が与えられないことを示します。
    • STAT_ENUM_REQS_STATIC - この値は、列挙された可能性がモデルの実行中に変化しないことを示します。
    • STAT_ENUM_REQS_DYNAMIC - この値は、可能性が動的であるため列挙されないことを示します。