<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      eaglet

      本博專(zhuān)注于基于微軟技術(shù)的搜索相關(guān)技術(shù)
        博客園  :: 首頁(yè)  :: 新隨筆  :: 聯(lián)系 :: 訂閱 訂閱  :: 管理

      關(guān)于 GetThreadTimes

          昨天我在一篇博文中 《對(duì)老趙寫(xiě)的簡(jiǎn)單性能計(jì)數(shù)器的修改》  提到用 GetThreadTimes 這個(gè)Win32 API 來(lái)獲取線程實(shí)際運(yùn)行時(shí)間。今天我又深入研究了一下,發(fā)現(xiàn)這個(gè)API 返回的時(shí)間并不準(zhǔn)確。

          首先我們先看一下 GetThreadTimes 的實(shí)現(xiàn)原理:

          在 kernel32.dll 內(nèi)部 GetThreadTimes 首先調(diào)用 NtQueryInformationThread 獲取線程TCB信息,然后從TCB 中獲取線程的內(nèi)核態(tài)計(jì)數(shù)和用戶態(tài)計(jì)數(shù)。然而這個(gè)計(jì)數(shù)值并不是實(shí)時(shí)增加的,操作系統(tǒng)只是在時(shí)間中斷(10/15ms一次,單處理器通常是10ms,多處理器15ms)發(fā)生時(shí)增加當(dāng)前線程的計(jì)數(shù)。這里就出現(xiàn)一個(gè)問(wèn)題,如果時(shí)間中斷發(fā)生時(shí),被統(tǒng)計(jì)線程恰好不在活動(dòng)狀態(tài),即不是當(dāng)前線程,那么這個(gè)線程就不會(huì)增加計(jì)數(shù)。所以只有線程長(zhǎng)時(shí)間連續(xù)占用CPU,或者每次都正好連續(xù)占用一個(gè)完整的時(shí)間片(10/15ms一次),才能確保這個(gè)線程的統(tǒng)計(jì)結(jié)果是準(zhǔn)確的。但實(shí)際情況是,線程不可能連續(xù)占用CPU(否則其他程序就別玩了,如果你一定要這樣我也沒(méi)辦法),也不可能每次都恰巧占用完整的時(shí)間片(線程工作過(guò)程中往往會(huì)需要Sleep,或者阻塞等待資源或者被高優(yōu)先級(jí)線程打斷)。所以顯而易見(jiàn),這個(gè)計(jì)數(shù)是不精確的。

          下面給出我寫(xiě)的一個(gè)示例代碼。

          這個(gè)代碼在我機(jī)器上運(yùn)行,如果將Thread.Sleep(1); 這行注釋掉,顯示耗時(shí)是140毫秒,但如果不注釋這行,顯示耗時(shí)是0毫秒。

          原因就是我們將140毫秒的時(shí)間強(qiáng)行分成了1000個(gè)很小的時(shí)間,每次線程只消耗大約0.14 毫秒的CPU時(shí)間,而在這1秒左右的時(shí)間(約 1000*1ms+140ms)

       時(shí)間里,共發(fā)生1140 / 15 = 74 次時(shí)間中斷(我的機(jī)器是雙核的),每次中斷時(shí),主線程正好在運(yùn)行的概率不高,如果這74次中斷中沒(méi)有一次擊中當(dāng)前線程,

       則當(dāng)前線程的計(jì)數(shù)增長(zhǎng)始終為0。

         

             
              [DllImport(
      "kernel32.dll", SetLastError = true)]
              
      static extern bool GetThreadTimes(IntPtr hThread, out long lpCreationTime,
                 
      out long lpExitTime, out long lpKernelTime, out long lpUserTime);

              [DllImport(
      "kernel32.dll")]
              
      static extern IntPtr GetCurrentThread();

              
      private static long GetCurrentThreadTimes()
              
      {
                  
      long l;
                  
      long kernelTime, userTimer;
                  GetThreadTimes(GetCurrentThread(), 
      out l, out l, out kernelTime, out 
                     userTimer);
                  
      return kernelTime + userTimer;
              }


              
      static void TestGetThreadTimes()
              
      {
                  
      long lst = GetCurrentThreadTimes();
                  
      string a = "";

                  
      for (int i = 0; i < 10000; i++)
                  
      {
                      a 
      += "a";

                      
      if (i % 10 == 0)
                      
      {
                          Thread.Sleep(
      1); //休眠1毫秒
                      }

                  }


                  Console.Write((GetCurrentThreadTimes() 
      - lst) / (10 * 1000));
                  Console.WriteLine(
      "ms");
              }

       

      參考文章:

      http://blog.kalmbachnet.de/?postid=28

      這是一個(gè)德國(guó)人寫(xiě)的博客,我看了好幾遍,對(duì)他寫(xiě)的德式英語(yǔ)還是不太明白,(本人英文水平不高也是事實(shí)),所以我理解的不對(duì)的地方還望大家指正。不過(guò)結(jié)論肯定是正確的,就是通過(guò)GetThreadTimes 得到的線程占用時(shí)間是不準(zhǔn)確的,在某種條件下甚至是很不準(zhǔn)確的。

      另外我發(fā)現(xiàn)調(diào)用GetThreadTimes獲取其它線程的計(jì)數(shù)基本得不到,我還沒(méi)有搞明白是什么原因。

       

      進(jìn)一步分析:

      這篇文章發(fā)出后,老蔡回帖認(rèn)為我的理解有偏差,他認(rèn)為只有線程經(jīng)歷了完整的時(shí)間片才會(huì)被計(jì)數(shù),我為此做了進(jìn)一步分析,

      看如下代碼

       

       

       

       

              static void TestGetThreadTimes()
              
      {
                  QueryPerfCounter q 
      = new QueryPerfCounter();

                  
      long lst = GetCurrentThreadTimes();
                  
      string a = "";
                  
      const int BreakTimes = 10000;
                  
      const int Iteration = 100000;

                  
      double[] timeList = new double[BreakTimes];

                  
      int times = 0;

                  
      for (int i = 0; i < Iteration; i++)
                  
      {
                      a 
      += "a";
                      
      if (i % (Iteration / BreakTimes) == 0)
                      
      {
                          
      if (i > 0)
                          
      {
                              q.Stop();
                              timeList[times
      ++= q.Duration(1);
                          }

                          Thread.Sleep(
      1);
                          q.Start();
                      }

                  }


                  q.Stop();
                  timeList[times
      ++= q.Duration(1);

                  Console.Write(
      "GetThreadTimes:");
                  Console.Write((GetCurrentThreadTimes() 
      - lst) / (10 * 1000));
                  Console.WriteLine(
      "ms");

                  
      double max = 0;
                  
      double sum = 0;
                  
      foreach (double time in timeList)
                  
      {
                      
      if (max < time)
                      
      {
                          max 
      = time;
                      }


                      sum 
      += time;
                  }



                  Console.WriteLine(
      string.Format("Avg time {0} ms", (sum / BreakTimes) / 1000000));
                  Console.WriteLine(
      string.Format("max time {0} ms", (max) / 1000000));
                  Console.WriteLine(
      string.Format("Total time {0} ms", sum / 1000000));

              }

       

       

      QueryPerfCounter 類(lèi)見(jiàn) dotnet下時(shí)間精度測(cè)量  感謝 xiaotie

      運(yùn)行結(jié)果:

      GetThreadTimes:11218ms
      Avg time 1.58978048886101 ms
      max time 5.64513087557217 ms
      Total time 15897.8048886101 ms

      也就是說(shuō) 通過(guò)GetThreadTimes 我們測(cè)量到了 11218ms CPU用時(shí)。實(shí)際用時(shí)大概是 15897 ms

      但Sleep(1) 之間間隔的時(shí)間平均是 1.59 ms 最大間隔時(shí)間是 5.6 ms 。可見(jiàn)沒(méi)有一次的間隔時(shí)間達(dá)到了一個(gè)完整時(shí)間片(15ms)

      如果只有跑滿一個(gè)完整時(shí)間片才會(huì)計(jì)數(shù),那么通過(guò) GetThreadTimes 得到的結(jié)果應(yīng)該是0ms。但實(shí)際并非如此。

      所以跑滿一個(gè)完整時(shí)間片才計(jì)數(shù)的說(shuō)法在這里很難解釋這種現(xiàn)象。這個(gè)現(xiàn)象我在寫(xiě)這篇文章前已經(jīng)發(fā)現(xiàn)了。

      我們?cè)儆脫糁懈怕实姆椒▉?lái)驗(yàn)證。

      每次時(shí)鐘中斷擊中的概率大概是

      15897 / (10000 + 15897) = 0.61

      那么按照這個(gè)概率計(jì)算,GetThreadTimes 可以統(tǒng)計(jì)到的時(shí)間是15897 * 0.61 = 9697.17 ms

      這個(gè)數(shù)值和實(shí)際數(shù)值基本上是吻合的。所以綜上所述,我傾向于認(rèn)同那個(gè)德國(guó)專(zhuān)家的說(shuō)法。

       

      備注

      下面是 Jochen Kalmbach  寫(xiě)的C++代碼,我沒(méi)有調(diào)試過(guò),不過(guò)他的代碼是用其他線程獲取計(jì)數(shù)的,不知道是不是對(duì).Net的托管線程這樣不行,反正我在.Net下試是不行的。

       

       

        #include <windows.h>
        #include 
      <stdio.h>

        DWORD loopCounter 
      = 0;
        DWORD loopCounterMax 
      = 1000;
        DWORD internalCounter 
      = 0xFFF00000;

        DWORD __stdcall CalcThread(LPVOID)
        
      {
          
      while(loopCounter <= loopCounterMax)
          
      {
            DWORD cnt 
      = internalCounter;
            
      while(cnt != 0) cnt++;
            Sleep(
      1);
            loopCounter
      ++;
          }
       return 0;
        }


        DWORD WINAPI IdleThread(LPVOID)
        
      {
          
      while(loopCounter <= loopCounterMax)
          
      {
            Sleep(
      0);  // just do something
          }
       return 0;
        }


        
      int _tmain(int argc, _TCHAR* argv[])
        
      {
          
      // be sure we only use 1 processor!
          SetProcessAffinityMask(GetCurrentProcess(), 1);

          LARGE_INTEGER liStart, liEnd, liFreq;

          
      // test, how much time the inc is using
          QueryPerformanceCounter(&liStart);
          DWORD cnt 
      = internalCounter;
          
      while(cnt != 0) cnt++;
          QueryPerformanceCounter(
      &liEnd);
          QueryPerformanceFrequency(
      &liFreq);
          
      double ms = ((double) (liEnd.QuadPart-liStart.QuadPart) * 1000/
        (
      double)liFreq.QuadPart;
          printf(
      "Inc duration: %.3f msnn", ms);
          
      // test-end

          DWORD id;
          HANDLE hThread[ 
      2 ];
          QueryPerformanceCounter(
      &liStart);

          hThread[ 
      0 ] = CreateThread(NULL, 0, CalcThread, 00&id);
          hThread[ 
      1 ] = CreateThread(NULL, 0, IdleThread, 00&id);

          WaitForMultipleObjects(
      2, hThread, TRUE, INFINITE);

          QueryPerformanceCounter(
      &liEnd);
          QueryPerformanceFrequency(
      &liFreq);

          ms 
      = ((double) (liEnd.QuadPart-liStart.QuadPart) * 1000/ (double)
        liFreq.QuadPart;
          printf(
      "Duration: %.3f msnn", ms);

          FILETIME ftCreate, ftExit, ftKernel, ftUser;
          
      for(DWORD i=0; i<2; i++)
          
      {
            GetThreadTimes(hThread[i], 
      &ftCreate, &ftExit, &ftKernel, &ftUser);

            printf(
      "Reported time for thread %dn", i+1);

            SYSTEMTIME st;
            FileTimeToSystemTime(
      &ftKernel, &st);
            printf(
      "Kernel: %2.2d:%2.2d.%3.3dn", st.wMinute, st.wSecond,
        st.wMilliseconds);

            FileTimeToSystemTime(
      &ftUser, &st);
            printf(
      "User: %2.2d:%2.2d.%3.3dnn", st.wMinute, st.wSecond,
        st.wMilliseconds);
          }

        
      return 0;
        }

            

      主站蜘蛛池模板: 亚洲欧美人成网站在线观看看| 亚洲AV无码秘?蜜桃蘑菇| 日本免费一区二区三区久久| 国产成人毛片无码视频软件| 久久精品娱乐亚洲领先| 国产av麻豆mag剧集| 啊轻点灬大JI巴太粗太长了在线| 欧美午夜成人片在线观看| 亚洲区成人综合一区二区| 横峰县| 久久久久噜噜噜亚洲熟女综合| 丁香五月婷激情综合第九色| 最近中文字幕国产精品| 亚洲精品日韩在线观看| 国产毛片基地| 亚洲精品国产老熟女久久| 国产精品疯狂输出jk草莓视频| 久久99精品久久久大学生| 亚洲国产永久精品成人麻豆| 躁躁躁日日躁| 日韩av不卡一区二区在线| 亚洲一区二区精品另类| 中国CHINA体内裑精亚洲日本| 国产亚洲精品久久综合阿香| 国产片av在线观看国语| 亚洲精品一区二区妖精| 鲁大师在线视频播放免费观看 | V一区无码内射国产| 天天爽夜夜爱| 无码专区一va亚洲v专区在线| 国产av一区二区不卡| 国产精品自拍视频免费看| 中文字幕精品人妻av在线| 无码专区 人妻系列 在线| 十八禁日本一区二区三区| 色综合久久蜜芽国产精品| 国产成人永久免费av在线| 中国CHINA体内裑精亚洲日本| 午夜福利国产精品视频| 日本中文字幕不卡在线一区二区| 5555国产在线观看|