/*
 * Random_Call1.cpp
 *
 *  Created on: 2013/09/23
 *      Author: まっちゃん
 */

// 826 名前：デフォルトの名無しさん[sage] 投稿日：2013/09/23(月) 20:13:03.86
// 結局メモリからコール先をロードする際にはレジスタでコールテーブルからオフセット値を
// 読み込んで初めてコール先が決定するので、コール先がアトランダムに変わる場合
// 全くと言って良いほど分岐予測が当たらない

// これはCの関数ポインタ配列でも同じだと思う
// 誰かベンチマーク取ってみてよ
// 同じ関数ばかり関数ポインタで呼ぶのと、乱数で呼び先をランダムに変えた場合

#include <iostream>
#include <chrono>
#include <cstdlib>
#include <ctime>

class Duration {
  std::chrono::high_resolution_clock::time_point beg, duration;
public:
  Duration() {
    beg = std::chrono::high_resolution_clock::now();
  }
  ~Duration() {
    duration = std::chrono::high_resolution_clock::now();
    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(duration - beg).count() << "ms" << std::endl;
  }
};

const int N = 10000000;

int rnd[N];

void func1()
{
  return;
}

void func2()
{
  return;
}

void func3()
{
  return;
}

void func4()
{
  return;
}

int main()
{
  void (*func[])() = { func1, func2, func3, func4 }; // Avoid std::function costs

  {
    std::cout << "The same function call" << std::endl;
    Duration d;

    for (int i = 0; i < N; i++)
      func[0]();
  }

  {
    std::srand(std::time(0));
    for (int i = 0; i < N; i++)
      rnd[i] = std::rand() % 4; // Avoid std::rand() costs
    std::cout << "Random function call" << std::endl;
    Duration d;

    for (int i = 0; i < N; i++)
      func[rnd[i]]();
  }
}

