DDeepin Developerfeat: Init commit
bd5e64d7创建于 2022年9月22日历史提交
/* MemLat.cpp -- Memory Latency

2011-05-12 : Igor Pavlov : Public domain */



// #define _WIN32_WINNT 0x0500



#include <stdio.h>



#ifdef _MSC_VER

// "was declared deprecated" disabling

#pragma warning(disable : 4996 )

// #define LARGE_PAGES

#endif



#include "../Benchmark.h"

#include "../MyVersion.h"



#include "Walk.h"



#ifdef ITS_WINDOWS

#ifdef LARGE_PAGES

#include "..\..\..\Windows\Security.h"

#include "..\..\..\Windows\MemoryLock.h"

#endif

#endif



// #define _TEST_64



#ifdef _TEST_64

typedef UInt64 TestType;

const int kNumMoveBits = 3;

#else

typedef UInt32 TestType;

const int kNumMoveBits = 2;

#endif



const int kNumTestsMax = 22;



const int kBasePowerMax = 33;

const size_t kBufferSize3 = ((size_t)1 << (kBasePowerMax - kNumMoveBits));



#ifndef NUM_DIRECT_TESTS

    #define NUM_DIRECT_TESTS 10

#endif



#ifndef NUM_PAR_TESTS

    #define NUM_PAR_TESTS 12

#endif



static unsigned GetHex(const char *s)

{

  UInt32 value;

  if (1 != sscanf(s, "%x", &value))

    throw "incorrect value";

  return value;

}



#ifndef MY_CPU_AMD64

#define SUPPORT_DIRECT

#endif



#ifdef UNDER_CE

#define USE_GUI

#endif



#ifdef USE_GUI

HWND g_Hwnd;

BOOL g_bAbort;



#define MY_PROGRESS(id, nnn) \

  { MSG msg; wchar_t s2[64]; _itow(nnn, s2, 10); \

    SetWindowTextW(GetDlgItem(g_Hwnd, id), s2); \

    while (!g_bAbort && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) \

      if (!IsDialogMessage(g_Hwnd, &msg)) \

      { TranslateMessage(&msg); DispatchMessage(&msg); } \

      if (g_bAbort) return 1; }

#else

#define MY_PROGRESS(id, nnn)

#endif



int main2(CPrinter &f, int numArgs, const char *args[])

{

  f.Print("MemLat " MY_VERSION_COPYRIGHT_DATE "\n");

  if (numArgs < 2 || numArgs > 100)

  {

    f.Print(

      "use: MemLat.exe Size[K|M] [n] [l] [b] [c] [p[N]]\n"

      "  Size[K|M] - upper memory limit\n"

      "  n - show results in ns\n"

      "  l - use large pages\n"

      #ifdef SUPPORT_DIRECT

      "  a - unAligned read\n"

      #endif

      "  b - check Bandwidth using sum operator\n"

      "  c - check Latency and Bandwidth using sequential Chain\n"

      #ifdef SUPPORT_DIRECT

      "  d - Direct pointers\n"

      #endif

      "  p - check different page sizes\n"

      "  p[N] - check page performance for pageSize = 2^N\n"

      "  r - check different page sizes with NOP-40 mode\n"

      "  x[N] - align test array on 2^N range\n"

      "  z[N] - the number of random interations = 2^N\n"

      "  w    - write mode\n"

      );

    return 1;

  }

  const char *arg = args[1];

  int len = (int)strlen(arg);

  if (len < 1)

    return 2;

  size_t bufferSizeMax = atoi(arg);

  if (arg[len-1] == 'K' || arg[len-1] == 'k')

    bufferSizeMax <<= 10;

  else

    bufferSizeMax <<= 20;

  bufferSizeMax >>= kNumMoveBits;



  #ifdef _WIN32

  #ifdef LARGE_PAGES

  NWindows::NSecurity::AddLockMemoryPrivilege();

  NWindows::NSecurity::EnableLockMemoryPrivilege();

  #endif

  #endif



  bool nsMode = false;

  bool largePages = false;

  bool noCache = false;



  bool bwMode = false;

  bool seqMode = false;

  #ifdef SUPPORT_DIRECT

  bool alignMode = false;

  bool directMode = false;

  #endif



  bool writeMode = false;

  bool pageMode = false;

  int pageBits = 2;



  int zBits =

    #ifdef UNDER_CE

    16;

    #else

    21;

    #endif



  int seqStep = 0;



  int xBits =

  #ifdef ITS_WINDOWS

  #ifdef UNDER_CE

  20;

  #else

  24;

  #endif

  #else

  12;

  #endif



  int affinity = 0;



  bool nopMode = false;

  

  for (int ii = 2; ii < numArgs; ii++)

  {

    const char *str = args[ii];

    switch(str[0])

    {

      case 'p':

      {

        str++;

        int len = (int)strlen(str);

        if (len < 1)

          pageMode = true;

        else

        {

          pageBits = atoi(str);

          if (pageBits > 30 || pageBits < 2)

            return 1;

        }

        break;

      }

      case 'r':

      {

        pageMode = true;

        nopMode = true;

        break;

      }



      case 'b': bwMode = true; break;

      case 'c':

      {

        seqMode = true;

        str++;

        int len = (int)strlen(str);

        if (len >= 1)

        {

          if (str[len - 1] == 'h')

            seqStep = GetHex(str);

          else

          {

            return 1;

            // seqStep = atoi(str);

          }

          if (seqStep < 4 || seqStep > (1 << 30))

            return 1;

          seqStep >>= kNumMoveBits;

        }

        break;

      }

      #ifdef SUPPORT_DIRECT

      case 'a': alignMode = true; break;

      case 'd': directMode = true; break;

      #endif



      case 'n': nsMode = true; break;

      case 'l': largePages = true; break;

      case 'u': noCache = true; break;

      case 'w': writeMode = true; break;

      case 't':

      {

        str++;

        int len = (int)strlen(str);

        if (len < 1)

          return 1;

        else

        {

          affinity = atoi(str);

          if (affinity > 31 || affinity < 0)

            return 1;

        }

        break;

      }

      case 'x':

      {

        str++;

        int len = (int)strlen(str);

        if (len < 1)

          return 1;

        else

        {

          xBits = atoi(str);

          if (xBits > 30 || xBits < 3)

            return 1;

        }

        break;

      }

      case 'z':

      {

        str++;

        int len = (int)strlen(str);

        if (len < 1)

          return 1;

        else

        {

          zBits = atoi(str);

          if (zBits > 30 || zBits < 3)

            return 1;

        }

        break;

      }

      default: return 1;

    }

  }

  MY_SET_AFFINITY_NUMBER(affinity);



  bool latMode = !(seqMode || bwMode);



  size_t kAlignSize = (size_t)1 << xBits;

  size_t allocSize = ((size_t)bufferSizeMax * sizeof(TestType) + kAlignSize + kAlignSize - 1) & ~((size_t)kAlignSize - 1);

  TestType *randAddressesBase = (TestType *)

  #ifdef _WIN32

  ::VirtualAlloc(0, allocSize,

      MEM_COMMIT

      #ifndef UNDER_CE

      | (largePages ? MEM_LARGE_PAGES : 0)

      #endif

	    , PAGE_READWRITE | (noCache ? PAGE_NOCACHE : 0));

  #else

  malloc(allocSize);

  #endif



  if (randAddressesBase == 0)

  {

    f.Print( "Not enough memory\n");

    return 1;

  }



  TestType *randAddresses = randAddressesBase;

  

  while((((size_t)randAddresses) & (kAlignSize - 1)) != 0)

    randAddresses++;

 

  CRandomGenerator rg;



  const int kNumSubItemsBits = 2;

  const int kNumSubItems = 1 << kNumSubItemsBits;

  const int kNumMaxItems = (kBasePowerMax + 1) * kNumSubItems;

  const unsigned kNumTestCycles = 4;

  int kStartPower = 12;



  int numTests = kNumTestsMax;

  

  if (bwMode)

    numTests = 9;

  else if (seqMode)

    numTests = (seqStep == 0) ? 13 : 1;

  #ifdef SUPPORT_DIRECT

  else if (alignMode)

    numTests = 13;

  #endif

  else

  {

    if (pageMode)

      numTests = 21;

    else

    {

      if (writeMode)

      {

        numTests = 6;

        #ifdef SUPPORT_DIRECT

        numTests = directMode ? 3 : 2;

        #endif

      }

      else

      {

        numTests =

          #ifdef SUPPORT_DIRECT

          directMode ? NUM_DIRECT_TESTS :

          #endif

          NUM_PAR_TESTS;

      }

    }

  }



  if (numTests > kNumTestsMax)

    numTests = kNumTestsMax;





  unsigned sizes[kNumMaxItems];

  double ticksResults[kNumTestsMax][kNumMaxItems];

  TestType sum = 0;



  {

    for (int k = 0; k <

      #ifdef UNDER_CE

      20000000

      #else

      600000000

      #endif

      ; k++)

      sum += (k >> 3);

  }



  UInt64 startCount = GetTimeCount();

  UInt64 startCount2 = GetTimeCount2();



  {

    for (int k = 0; k <

      #ifdef UNDER_CE

      10000000

      #else

      100000000

      #endif

      ; k++)

      sum += (k >> 3);

  }







  int sizeIndexMax = 0;

  for (int testIndex = 0; testIndex < numTests; testIndex++)

  {

    MY_PROGRESS(102, testIndex);



    int numThreads = 1;

    if (!seqMode && !bwMode

        #ifdef SUPPORT_DIRECT

        && !alignMode

        #endif

      )

    {

      if (!pageMode)

        numThreads = testIndex + 1;

    }

    int sizeIndex = 0;

    // printf("\ntestIndex=%d\n", testIndex);

    for (int k = kStartPower; k < 64; k++)

    {

      MY_PROGRESS(103, (1 << k) >> 10);

      // printf("k=%d\n", k);

      int t;

      for (t = 0; t < kNumSubItems; t++, sizeIndex++)

      {

        unsigned a[kNumTestsMax];

        ticksResults[testIndex][sizeIndex] = 0;

        // printf("t=%d\n", t);

        unsigned bufferSize = ((unsigned)1 << (k - kNumMoveBits)) +

            (t << (k - kNumMoveBits - kNumSubItemsBits));

        if (bufferSize > kBufferSize3 || bufferSize > bufferSizeMax)

          break;

        sizes[sizeIndex] = bufferSize;

        

        UInt32 numCycles;



        unsigned i;

        const UInt32 kEmpty = 0xFFFFFFFF;

        for (i = 0; i < bufferSize; i++)

          randAddresses[i] = kEmpty;



        // printf("numCycles=%d\n", numCycles);



        #ifdef SUPPORT_DIRECT

        if (alignMode)

        {

          UInt32 step = 1 << testIndex;

          if (step > bufferSize)

            continue;

          numCycles = bufferSize / step;

          UInt32 stepInBytes = step << kNumMoveBits;

          char *pAlignStart = (char *)(randAddresses) + (stepInBytes - (1 << kNumMoveBits)) / 2;

          a[0] = (UInt32)pAlignStart;

          char *p = pAlignStart;

          for (i = 0; i + step <= bufferSize; i += step, p += stepInBytes)

            *(UInt32 *)p = (UInt32)(p + stepInBytes);

          *(UInt32 *)(p - stepInBytes) = (UInt32)pAlignStart;

        }

        else

        #endif



        if (bwMode || seqMode)

        {

          UInt32 step = (testIndex == 0) ? 1 : (1 << (testIndex - 1));

          if (seqStep != 0)

            step = seqStep;

          if (step > bufferSize)

            continue;

          numCycles = bufferSize / step;

          if (bwMode)

          {

            if (numCycles < 4)

              continue;

          }

          if (seqMode)

          {

            if (testIndex == 0 && seqStep == 0)

            {

              for (i = 0; i < bufferSize; i++)

                randAddresses[i] = 1;

              randAddresses[i - 1] = 0 - (i - 1);

            }

            else

            {

              for (i = 0; i < bufferSize; i += step)

                randAddresses[i] = i + step;

              randAddresses[i - step] = 0;

            }

          }

        }

        else

        {

          int curPageBits = pageBits;

          if (pageMode)

            curPageBits = pageBits + testIndex;

          int kPageIntsBits = curPageBits - 2;

          numCycles = bufferSize >> kPageIntsBits;

          numCycles /= numThreads;

          

          // printf(" kNumCycles = %5d", numCycles);

          if (numCycles > (1 << 10))

          {

            const UInt32 kDiv = 8;

            numCycles = numCycles / kDiv * (kDiv - 1);

            const UInt32 kNumCyclesMax = (1 << zBits);

            if (numCycles > kNumCyclesMax)

              numCycles = kNumCyclesMax;

          }

          if (numCycles < 1)

            continue;

          

          for (int s = 0; s < numThreads; s++)

          {

            UInt32 prev = 0xFFFFFFFF;

            for (i = 0; i < numCycles; i++)

            {

              for (;;)

              {

                UInt32 pageIndex = rg.GetRnd32(bufferSize >> kPageIntsBits);

                unsigned randValueBase = pageIndex << kPageIntsBits;

                unsigned randValue = randValueBase + rg.GetRnd32(1 << kPageIntsBits);

                

                // unsigned randValue = (aaa + 1)  % bufferSize;

                // printf("randValue=%d\n", randValue);

                

                if (randAddresses[randValueBase] == kEmpty)

                {

                  UInt32 val = randValue;

                  #ifdef SUPPORT_DIRECT

                  if (directMode)

                    val = (UInt32)(randAddresses + randValue);

                  #endif



                  if (i == 0)

                    a[s] = val;

                  else

                    randAddresses[prev] = val;

                  randAddresses[randValueBase] = 0;

                  prev = randValue;

                  // printf(" i = %d r=%d\n", i, randValue);

                  break;

                }

              }

            }

            randAddresses[prev] = a[s];

          }

        }



        double minValue = 1 << 30;



        UInt32 mult2 = (k <= 16) ? 2047000 : 127000;

        mult2 = (UInt32)((UInt64)mult2 / GetFreq2()) + 1;

        unsigned numSpecCycles = (unsigned)(((UInt64)1 << 12) * mult2 / numCycles) + 1;



        // printf("numSpecCycles = %5d\n", numSpecCycles);

        for (i = 0; i < kNumTestCycles; i++)

        {

          UInt32 res = 0;

          UInt64 startTime = GetTimeCount();

          if (latMode)

          {

            UInt32 numCycles2 = numCycles * numSpecCycles;

            // printf("  numCycles2 = %5d \n", numCycles2);



            #ifdef SUPPORT_DIRECT

            if (alignMode ||

                (pageMode || testIndex == 0) && directMode)

              if (writeMode)

                res = Walk1wd(numCycles2, (void **)a[0]);

              else

                res = Walk1d(numCycles2, (void **)a[0]);

            else

            #endif

            if (pageMode || testIndex == 0)

                if (nopMode)

                  res = Walk1Nop(randAddresses, numCycles2, a[0]);

                else if (writeMode)

                  res = Walk1w(randAddresses, numCycles2, a[0]);

                else

                  res = Walk1(randAddresses, numCycles2, a[0]);

            else

              #ifdef SUPPORT_DIRECT

              if (directMode)

                if (writeMode)

              switch (testIndex)

              {

                case 1: res = Walk2wd(numCycles2, (void **)a[0], (void **)a[1]); break;

                case 2: res = Walk3wd(numCycles2, (void **)a[0], (void **)a[1], (void **)a[2]); break;

                default: f.Print( "\nInternal error\n"); return 1;

              }

              else

              switch (testIndex)

              {

                case 1: res = Walk2d(numCycles2, (void **)a[0], (void **)a[1]); break;

                case 2: res = Walk3d(numCycles2, (void **)a[0], (void **)a[1], (void **)a[2]); break;

                case 3: res = Walk4d(numCycles2, (void **)a[0], (void **)a[1], (void **)a[2], (void **)a[3]); break;

                case 4: res = Walk5d(numCycles2, (void **)a[0], (void **)a[1], (void **)a[2], (void **)a[3], (void **)a[4]); break;

                case 5: res = Walk6d(numCycles2, (void **)a[0], (void **)a[1], (void **)a[2], (void **)a[3], (void **)a[4], (void **)a[5]); break;

                #if NUM_DIRECT_TESTS > 6

                case 6: res = Walk7d(numCycles2, (void **)a[0], (void **)a[1], (void **)a[2], (void **)a[3], (void **)a[4], (void **)a[5], (void **)a[6]); break;

                #if NUM_DIRECT_TESTS > 7

                case 7: res = Walk8d(numCycles2, (void **)a[0], (void **)a[1], (void **)a[2], (void **)a[3], (void **)a[4], (void **)a[5], (void **)a[6], (void **)a[7]); break;

                #if NUM_DIRECT_TESTS > 8

                case 8: res = Walk9d(numCycles2, (void **)a[0], (void **)a[1], (void **)a[2], (void **)a[3], (void **)a[4], (void **)a[5], (void **)a[6], (void **)a[7], (void **)a[8]); break;

                #if NUM_DIRECT_TESTS > 9

                case 9: res = Walk10d(numCycles2, (void **)a[0], (void **)a[1], (void **)a[2], (void **)a[3], (void **)a[4], (void **)a[5], (void **)a[6], (void **)a[7], (void **)a[8], (void **)a[9]); break;

                #endif

                #endif

                #endif

                #endif

                default: f.Print("\nInternal error\n"); return 1;

              }

              else

              #endif



            if (writeMode)

            {

              switch (testIndex)

              {

                case 1: res = Walk2w(randAddresses, numCycles2, a[0], a[1]); break;

                #ifdef _WIN64

                case 2: res = Walk3w(randAddresses, numCycles2, a[0], a[1], a[2]); break;

                case 3: res = Walk4w(randAddresses, numCycles2, a[0], a[1], a[2], a[3]); break;

                case 4: res = Walk5w(randAddresses, numCycles2, a[0], a[1], a[2], a[3], a[4]); break;

                case 5: res = Walk6w(randAddresses, numCycles2, a[0], a[1], a[2], a[3], a[4], a[5]); break;

                #endif

                default: f.Print("\nInternal error\n"); return 1;

              }

            }

            else

            switch (testIndex)

            {

              case 1: res = Walk2(randAddresses, numCycles2, a[0], a[1]); break;

              case 2: res = Walk3(randAddresses, numCycles2, a[0], a[1], a[2]); break;

              case 3: res = Walk4(randAddresses, numCycles2, a[0], a[1], a[2], a[3]); break;

              case 4: res = Walk5(randAddresses, numCycles2, a[0], a[1], a[2], a[3], a[4]); break;

              #if NUM_PAR_TESTS > 5

              case 5: res = Walk6(randAddresses, numCycles2, a[0], a[1], a[2], a[3], a[4], a[5]); break;

              #if NUM_PAR_TESTS > 6

              case 6: res = Walk7(randAddresses, numCycles2, a[0], a[1], a[2], a[3], a[4], a[5], a[6]); break;

              #if NUM_PAR_TESTS > 7

              case 7: res = Walk8(randAddresses, numCycles2, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]); break;

              #if NUM_PAR_TESTS > 8

              case 8: res = Walk9(randAddresses, numCycles2, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); break;

              #if NUM_PAR_TESTS > 9

              case 9: res = Walk10(randAddresses, numCycles2, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]); break;

              #if NUM_PAR_TESTS > 10

              case 10: res = Walk11(randAddresses, numCycles2, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10]); break;

              #if NUM_PAR_TESTS > 11

              case 11: res = Walk12(randAddresses, numCycles2, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11]); break;

              #endif

              #endif

              #endif

              #endif

              #endif

              #endif

              #endif

              default: f.Print("\nInternal error\n"); return 1;

            }

          }

          else

          {

            if (seqMode)

            {

              if (testIndex == 0 && seqStep == 0)

                res = Walk1Add(randAddresses, numCycles * numSpecCycles, 0);

              else

                res = Walk1(randAddresses, numCycles * numSpecCycles, 0);

            }

            else

              for (unsigned spec = 0; spec < numSpecCycles; spec++)

                if (testIndex == 0)

                  if (writeMode)

                    WalkWrite(randAddresses, numCycles);

                  else

                    res += WalkSum(randAddresses, numCycles);

                else

                  if (writeMode)

                    WalkWrite2(randAddresses, numCycles << (testIndex - 1), 1 << (testIndex - 1));

                  else

                    res += WalkSum2(randAddresses, numCycles << (testIndex - 1), 1 << (testIndex - 1));

          }

          double ticks = double(Int64(GetTimeCount() - startTime)) / numCycles / numSpecCycles / numThreads;

          // printf("\nTimer=%d\n", GetTimeCount() - startTime);

          sum += res;

          if (ticks < minValue)

            minValue = ticks;

          if (minValue == 0)

            minValue = 0.000000000000000001;

        }

        ticksResults[testIndex][sizeIndex] = minValue;

      }

      if (t != kNumSubItems)

        break;

    }

    sizeIndexMax = sizeIndex;

  }

  UInt64 countTotal = GetTimeCount() - startCount;

  UInt64 countTotal2 = GetTimeCount2() - startCount2;



  if (countTotal2 == 0)

    countTotal2 = 1;

  double freq = double((Int64)countTotal) * (Int64)GetFreq2() / (Int64)countTotal2;

  if (freq == 0)

    freq = 1;



  char temp[128];

  {

    f.Print("    Size");

    #ifdef SUPPORT_DIRECT

    if (alignMode)

    {

      for (int testIndex = 0; testIndex < numTests; testIndex++)

      {

        sprintf(temp, " %6d", testIndex == 0 ? 0 : (2 << testIndex));

        f.Print(temp);

      }

    }

    else

    #endif

    if (seqMode || bwMode)

    {

      f.Print((seqMode && seqStep == 0) ? "    Add" : " Linear");

      for (int testIndex = 1; testIndex < numTests; testIndex++)

      {

        sprintf(temp, " %6d", (2 << testIndex));

        f.Print(temp);

      }

    }

    else

      for (int testIndex = 0; testIndex < numTests; testIndex++)

      {

        sprintf(temp, " %6d", pageMode ? (pageBits + testIndex) : (testIndex + 1));

        f.Print(temp);

      }

    f.Print("\n\n");

  }



  for (int i = 0; i < sizeIndexMax; i++)

  {

    int size = (sizes[i] >> (10 - kNumMoveBits));

    if (size < (4 << 10))

      sprintf(temp, "%6d-K", size);

    else

      sprintf(temp, "%6d-M", size >> 10);

    f.Print(temp);



    for (int testIndex = 0; testIndex < numTests; testIndex++)

    {

      double value = ticksResults[testIndex][i];

      if (nsMode)

        value = double(value) * 1000000000 / freq;

      sprintf(temp, " %6.2f", value);

      f.Print(temp);

    }

    f.NewLine();

  }



  f.NewLine();

  if (sizeIndexMax > 0)

  {

    for (int iii = 0; iii < 3; iii++)

    {

      const int kMovs = 5 + iii;

      f.Print("BW-");

      if (latMode)

      {

        sprintf(temp, "%3d B", 1 << kMovs);

        f.Print(temp);

      }

      else

        f.Print("     ");





      for (int testIndex = 0; testIndex < numTests; testIndex++)

      {

        double memoryBandwidth = (freq / ticksResults[testIndex][sizeIndexMax - 1]) * (1 << kNumMoveBits);

        if (latMode)

          memoryBandwidth *= (1 << (kMovs - 2));

        else if (testIndex > 0)

          memoryBandwidth *= (1 << (testIndex - 1));

        sprintf(temp, " %6d", (UInt32)(memoryBandwidth / 1000000));

        f.Print(temp);

      }

      f.NewLine();

      if (!latMode)

        break;

    }

    f.NewLine();

  }



  if (sizeIndexMax > 0)

  {

    if (latMode)

    {

      int latencyIndex = 0;

      double cacheLatency = ticksResults[latencyIndex][0] / freq;

      sprintf(temp, "Cache latency    = %10.2f ns     = %10.2f cycles\n",

        cacheLatency * (1e9), ticksResults[latencyIndex][0]);

      f.Print(temp);

      double memoryLatency = ticksResults[latencyIndex][sizeIndexMax - 1] / freq;

      sprintf(temp, "Memory latency   = %10.2f ns     = %10.2f cycles\n",

        memoryLatency * (1e9), ticksResults[latencyIndex][sizeIndexMax - 1]);

      f.Print(temp);

    }

    {

      if (nsMode)

        f.Print("ns ");

      if (largePages)

        f.Print("LargePages ");



      if (bwMode)

        f.Print("BW-Sum");

      else if (seqMode)

        f.Print("Seq Step");

      else if (pageMode)

        f.Print("PageMode");

      else

      {

        sprintf(temp, "PageSize=%d \n", 1 << pageBits);

        f.Print(temp);

      }

      f.NewLine();

    }

  }



  f.NewLine();

  sprintf(temp, "Timer frequency  = %10.0f Hz\n", (double)(Int64)GetFreq2());

  f.Print(temp);

  sprintf(temp, "CPU frequency    = %10.2f MHz\n", freq / 1000000);

  f.Print(temp);



  #ifdef _WIN32

  VirtualFree(randAddressesBase, 0, MEM_RELEASE);

  #else

  free(randAddressesBase);

  #endif

  return (int)(sum >> 3);

}



static const size_t kTempSize = 20000;



#ifdef USE_GUI



static int g_TestNumber = 0;



static int OneTest(CPrinter &f, const char *s, const wchar_t *fileName2)

{

  f.Init();

  

  {

    wchar_t s2[64];

    for (int t = 0; t < 100; t++)

    {

      s2[t] = s[t];

      if (s[t] == 0)

        break;

    }

    SetWindowTextW(GetDlgItem(g_Hwnd, 110), s2);

    MY_PROGRESS(101, g_TestNumber++);

  }



  char args[10][32];

  int param = 1;

  int pos = 0;

  for (;;)

  {

	char c = *s++;

	if (pos >= 32 || param >= 10)

      return 1;

	if (c == ' ')

	{

	  args[param][pos++] = 0;

	  pos = 0;

	  param++;

	}

	else

	{

	  args[param][pos++] = c;

      if (c == 0)

	    break;

	}

  }



  const char *argsPtr[10];

  param++;

  argsPtr[0] = "memLat.exe";

  for (int i = 1; i < param; i++)

	argsPtr[i] = args[i];

  main2(f, param, argsPtr);

  

  wchar_t fileName[300];

  GetModuleFileNameW(0, fileName, 300);

  wchar_t *p = wcsrchr(fileName, L'\\');

  if (p == 0)

    return 0;

  p++;

  wcscpy(p, fileName2);

  FILE *inputHandle = _wfopen(fileName, L"w+");

  if (inputHandle == 0)

  {

    MessageBoxW(0, L"Can't open text file", L"Error", 0);

    return 1;

  }

  fprintf(inputHandle, "%s", f.buf);

  fclose(inputHandle);



  return 0;

}



static INT_PTR CALLBACK MyDlgProc(HWND /* hwnd */, UINT message, WPARAM wParam, LPARAM /* lParam */)

{

  switch(message)

  {

    case WM_COMMAND:

      switch(LOWORD(wParam))

      {

        case IDCANCEL:

          SetWindowTextW(GetDlgItem(g_Hwnd, 101), L"Stopping...");

          g_bAbort = TRUE;

          break;

      }

      break;

    default:

      return FALSE;

  }

  return TRUE;

}



int WINAPI WinMain(HINSTANCE,

    HINSTANCE,

    #ifdef UNDER_CE

    LPWSTR

    #else

    LPSTR

    #endif

    ,

    int)

{

  g_bAbort = FALSE;

  g_Hwnd = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(100), NULL, MyDlgProc);

  if (g_Hwnd == 0)

  {

    MessageBoxW(0, L"Error", L"Error", 0);

    return 1;

  }



  CPrinter f(kTempSize);



  OneTest(f, "2m n c", L"c.txt");

  OneTest(f, "2m n b", L"b.txt");

  OneTest(f, "2m n b w", L"bw.txt");



  OneTest(f, "16m n p d", L"pd.txt");

  OneTest(f, "16m n p2 d", L"p2d.txt");

  OneTest(f, "16m n p5 d", L"p5d.txt");

  OneTest(f, "16m n p6 d", L"p6d.txt");

  OneTest(f, "16m n p7 d", L"p7d.txt");

  OneTest(f, "16m n p12 d", L"p12d.txt");

  OneTest(f, "16m n p2", L"p2.txt");



  // OneTest("16m n p d u", L"pdu.txt");

  // OneTest("16m n p2 d u", L"p2du.txt");

  // OneTest("16m n p4 d u", L"p4du.txt");

  // OneTest("16m n p5 d u", L"p5du.txt");

  // OneTest("1m n c u", L"cu.txt");

  // OneTest("1m n b u", L"bu.txt");

  // OneTest("1m n b w u", L"bwu.txt");



  return 0;

}

#else

int

#ifdef _MSC_VER

_cdecl

#endif

main(int numargs, const char *args[])

{

  CPrinter f(kTempSize);

  int code = main2(f, numargs, args);

  fputs(f.buf, stdout);

  return code;

}

#endif