love! LOVEHINA - love2hina.net


カテゴリー

アーカイブ
2010/02/28 意外に遅くない!? CriticalSection

作成者: カテゴリー: 未分類

VC++ CriticalSectionの速度をみると、ループ速度が14倍遅くなる!?
というのを見かけたので、これから実装してみる処理を見立ててサンプリングしてみることにしました。

やりたいことは単純で、1つのメッセージキューがあり、そのキューは複数のスレッドがアクセスします。
ロックして行う作業はメッセージを入れるか、取り出すかの単純なものです。

というわけで、以下のようなコードを書いてみました。

#include <stdio.h>
#include <tchar.h>
#include <list>
#include <iostream>
#include <windows.h>

std::list<int>    listValues;

CRITICAL_SECTION  lock;

__int64           intCounterFreq;

void push(void)
{
  listValues.push_back(0);
}

int pop(void)
{
  const int value = listValues.front();
  listValues.pop_front();
  return value;
}

void nolock(void)
{
  __int64  intStartCounter;
  __int64  intEndCounter;

  ::QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&intStartCounter));
  std::cout << "start no locking mode at " << intStartCounter << "." << std::endl;

  for (int i = 0; i < 100000; i++)
  {
    push();
    pop();
  }

  ::QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&intEndCounter));
  std::cout << "end no locking mode at " << intEndCounter << " offset " << (intEndCounter - intStartCounter) << "." << std::endl;
}

void sectionLock(void)
{
  __int64  intStartCounter;
  __int64  intEndCounter;

  ::QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&intStartCounter));
  std::cout << "start section locking mode at " << intStartCounter << "." << std::endl;

  for (int i = 0; i < 100000; i++)
  {
    ::EnterCriticalSection(&lock);
    push();
    ::LeaveCriticalSection(&lock);

    ::EnterCriticalSection(&lock);
    pop();
    ::LeaveCriticalSection(&lock);
  }

  ::QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&intEndCounter));
  std::cout << "end section locking mode at " << intEndCounter << " offset " << (intEndCounter - intStartCounter) << "." << std::endl;
}

int _tmain(int argc, _TCHAR * argv[])
{

  ::InitializeCriticalSection(&lock);

  ::SetThreadAffinityMask(::GetCurrentThread(), 0x1);
  ::QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER *>(&intCounterFreq));

  // test functions
  nolock();
  sectionLock();

  ::DeleteCriticalSection(&lock);
  return 0;
}

これを以下の環境で測定!

Model : HP Mini 2140
OS : Windows 7 Enterprise 32bit
CPU : Atom N270 1.6GHz
MEM : 2GB

環境は…Visual Studio 2010 RC(笑
コンパイラの最適化は有りで、Visual C++のデフォルト最適化のままです。
というのも、実際には最適化なしでソフトウェアをリリースするなんてことはありえませんし…。

結果は…
ロックなしが65873サンプル、ロック有りが91059サンプル(38%増加)
これを6回測定し、平均が21%遅くなるというものでした。

…と実際に処理を交えてみると、気になるほど極端には遅くならないようにみえます。
ロック処理中に何をするのか、にもよってきますので、
排他制御を適用される際には、疑似ロジックを用意して測定してみた方がよろしいようです。