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

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

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

      DotTrace系列:3. 時(shí)間度量之墻鐘時(shí)間和線(xiàn)程時(shí)間

      一:背景

      1. 講故事

      在用 dotTrace 對(duì)程序進(jìn)行性能評(píng)測(cè)的時(shí)候,有一個(gè)非常重要的概念需要使用者明白,那就是 時(shí)間度量 (Time measurement),主要分為兩種。

      • 墻鐘時(shí)間
      • 線(xiàn)程時(shí)間

      在 dotTrace 中有四種測(cè)量維度,其中 Real time 對(duì)應(yīng)著 墻鐘時(shí)間,截圖如下:

      二:時(shí)間度量分析

      1. 墻鐘時(shí)間

      墻鐘時(shí)間 顧名思義就是墻上的時(shí)鐘,只要給它上電它就能跑,無(wú)視這人世間發(fā)生的任何變化,屹立千年而不倒。

      用程序的話(huà)術(shù)就是它可以追蹤到線(xiàn)程的 上班時(shí)間下班時(shí)間,在 dottrace 中用 performance countercpu instruction 兩種方式,本質(zhì)上來(lái)說(shuō)前者是后者的包裝。

      如果有朋友比較懵的話(huà),可以用 C 調(diào)一下對(duì)應(yīng)的 Win32 api 就明白了,參考代碼如下:

      
      #include <windows.h>
      #include <stdio.h>
      #include <intrin.h>
      
      // 1. Real Time (Performance Counter)
      void measure_real_time_perf_counter() {
      
      	LARGE_INTEGER freq, start, end;
      	QueryPerformanceFrequency(&freq);
      	QueryPerformanceCounter(&start);
      	// 模擬工作負(fù)載(Sleep 不占用 CPU 時(shí)間)
      	Sleep(100);
      	QueryPerformanceCounter(&end);
      	double elapsed = (double)(end.QuadPart - start.QuadPart) / freq.QuadPart;
      	printf("RealTime (Performance Counter): %.2f ms\n", elapsed * 1000);
      }
      
      // 2. Real Time (CPU TSC)
      void measure_cpu_tsc() {
      	unsigned __int64 start = __rdtsc();
      	// 模擬工作負(fù)載(注意:Sleep 不會(huì)增加 TSC)
      	Sleep(100);  // 此處僅為演示,實(shí)際應(yīng)用應(yīng)使用 CPU 密集型操作
      	unsigned __int64 end = __rdtsc();
      	printf("RealTime (CPU TSC): %llu cycles\n", end - start);
      }
      
      int main() {
      	printf("----- Measuring Time with Win32 APIs -----\n");
      	measure_real_time_perf_counter();
      	measure_cpu_tsc();
      	return 0;
      }
      
      

      從卦中可以看到這兩種模式都可以追蹤到線(xiàn)程的 下班時(shí)間,接下來(lái)稍微解釋下。

      1. QueryPerformanceCounter,QueryPerformanceFrequency

      上面的 QueryPerformanceCounter 是Windows硬件定時(shí)器的計(jì)數(shù),而 QueryPerformanceFrequency 是這個(gè)定時(shí)器的時(shí)鐘頻率 (速度),所以時(shí)間值可以用小學(xué)的公式 T= S/V 算出來(lái)。

      1. __rdtsc

      tsc 是cpucore中的一個(gè)硬件寄存器,這個(gè)寄存器記錄了cpu上電之后的時(shí)鐘周期數(shù),要想算出時(shí)間需要知道cpu的時(shí)鐘頻率,截圖如下:

      有些朋友就說(shuō)了,你拿 差值/2.2GHZ 不就是時(shí)間嗎?這么算的話(huà)其實(shí)不準(zhǔn)的,因?yàn)?2.2GHZ 是基準(zhǔn)頻率,CPU在工作時(shí)會(huì)有上下浮動(dòng),比如寫(xiě)到這里的時(shí)候,當(dāng)前的CPU的頻率是4.93Ghz,這個(gè)就差的有點(diǎn)大了,截圖如下:

      所以比較合理的做法需要校準(zhǔn)下 時(shí)鐘頻率,我覺(jué)得 dottrace 內(nèi)部應(yīng)該是這么做的,畢竟這東西是閉源的,為了最簡(jiǎn)化,這里就用一個(gè)硬編碼,參考如下:

      
      // 2. Real Time (CPU TSC)
      void measure_cpu_tsc() {
      
      	double CPU_FREQUENCY_GHZ = 2.2;  // 例如 2.2 GHz
      
      	unsigned __int64 start = __rdtsc();
      
      	Sleep(100);  // 實(shí)際應(yīng)用應(yīng)替換為 CPU 密集型操作
      	unsigned __int64 end = __rdtsc();
      
      	// 計(jì)算時(shí)間(毫秒):
      	// 1. 計(jì)算時(shí)鐘周期差值
      	unsigned __int64 cycles = end - start;
      	// 2. 轉(zhuǎn)換為秒:cycles / (frequency in Hz)
      	double seconds = (double)cycles / (CPU_FREQUENCY_GHZ * 1e9);
      	// 3. 轉(zhuǎn)換為毫秒
      	double milliseconds = seconds * 1000.0;
      
      	printf("RealTime (CPU TSC): %.2f ms\n", milliseconds);
      }
      
      

      2. 線(xiàn)程時(shí)間

      線(xiàn)程時(shí)間 它追蹤的是 線(xiàn)程活動(dòng)的時(shí)間,即線(xiàn)程的上班時(shí)間,同樣 dottrace 也支持兩種,分別為 Thread cycle timeThread time ,本質(zhì)上來(lái)說(shuō)也是直接調(diào)用 Win32 Api 算出來(lái)的,參考代碼如下:

      
      
      #include <windows.h>
      #include <stdio.h>
      #include <intrin.h>
      
      
      // 1. Thread Time (User + Kernel Mode CPU Time)
      void measure_thread_time() {
      	FILETIME creation, exit, kernel_start, user_start, kernel_end, user_end;
      	HANDLE thread = GetCurrentThread();
      	GetThreadTimes(thread, &creation, &exit, &kernel_start, &user_start);
      	// 模擬 CPU 密集型工作
      	volatile int sum = 0;
      	for (int i = 0; i < 500000000; i++) sum += i;
      	GetThreadTimes(thread, &creation, &exit, &kernel_end, &user_end);
      
      	// 將 FILETIME(100ns 單位)轉(zhuǎn)換為微秒
      	ULARGE_INTEGER kernel_time, user_time;
      	kernel_time.LowPart = kernel_end.dwLowDateTime - kernel_start.dwLowDateTime;
      	kernel_time.HighPart = kernel_end.dwHighDateTime - kernel_start.dwHighDateTime;
      	user_time.LowPart = user_end.dwLowDateTime - user_start.dwLowDateTime;
      	user_time.HighPart = user_end.dwHighDateTime - user_start.dwHighDateTime;
      
      	printf("Thread Time: Kernel=%.2f ms, User=%.2f ms\n",
      		kernel_time.QuadPart / 10000.0,
      		user_time.QuadPart / 10000.0);
      }
      
      // 2. Thread Cycle Time
      void measure_thread_cycle_time() {
      	ULONG64 start, end;
      	HANDLE thread = GetCurrentThread();
      	QueryThreadCycleTime(thread, &start);
      	// 模擬 CPU 密集型工作
      	volatile int sum = 0;
      	for (int i = 0; i < 500000000; i++) sum += i;
      	QueryThreadCycleTime(thread, &end);
      	printf("Thread Cycle Time: %llu cycles\n", end - start);
      }
      
      int main() {
      	printf("----- Measuring Time with Win32 APIs -----\n");
      	measure_thread_time();
      	measure_thread_cycle_time();
      	return 0;
      }
      
      

      同樣的也來(lái)稍微解讀下。

      1. GetThreadTimes

      這個(gè)方法是直接獲取線(xiàn)程內(nèi)核數(shù)據(jù)結(jié)構(gòu) KThread 里的 KernelTime 和 UserTime 字段,我可以用 windbg 給大家演示下。

      
      lkd> !process 0 2 notepad.exe
      PROCESS ffffb98d5cc1a080
          SessionId: none  Cid: 6af4    Peb: ed94d6c000  ParentCid: 22a0
          DirBase: 3f045a000  ObjectTable: ffffe1039bf39040  HandleCount: 848.
          Image: Notepad.exe
      
              THREAD ffffb98d5f0a3080  Cid 6af4.60cc  Teb: 000000ed94d6d000 Win32Thread: ffffb98d69a53e20 WAIT: (WrUserRequest) UserMode Non-Alertable
                  ffffb98d6d64a9c0  QueueObject
      
              THREAD ffffb98d8766c080  Cid 6af4.3894  Teb: 000000ed94d6f000 Win32Thread: 0000000000000000 WAIT: (Unknown) UserMode Alertable
                  ffffb98d78286140  QueueObject
          ...
      
      lkd> dt nt!_KTHREAD ffffb98d5f0a3080 -y KernelTime UserTime
         +0x28c KernelTime : 4
         +0x2dc UserTime   : 2
      
      

      要注意的是上面的字段是 100納秒 為單位的,即 100納秒=0.1ms,所以上面分別為 0.4ms0.2ms。

      1. QueryThreadCycleTime

      在 _KTHREAD 中有一個(gè)字段 CycleTime,當(dāng)線(xiàn)程上班線(xiàn)程下班時(shí)都要打卡到 CycleTime 字段里,同樣也可以用windbg 驗(yàn)證。

      
      lkd> dt nt!_KTHREAD ffffb98d5f0a3080 -y CycleTime
         +0x048 CycleTime : 0x6db6621
      
      lkd> ? 0x6db6621
      Evaluate expression: 115041825 = 00000000`06db6621
      
      

      接下來(lái)就是如何將時(shí)鐘周期差值轉(zhuǎn)為 ms 呢?這需要知道CPU當(dāng)時(shí)的時(shí)鐘頻率,同樣我也簡(jiǎn)化一下,參考代碼如下:

      
      // 2. Thread Cycle Time
      void measure_thread_cycle_time() {
      	ULONG64 start, end;
      	HANDLE thread = GetCurrentThread();
      	QueryThreadCycleTime(thread, &start);
      
      	volatile int sum = 0;
      	for (int i = 0; i < 500000000; i++) sum += i;
      
      	QueryThreadCycleTime(thread, &end);
      
      	const double CPU_FREQUENCY_GHZ = 2.2;  // 假設(shè) CPU 主頻 2.2 GHz
      	double milliseconds = (double)(end - start) / (CPU_FREQUENCY_GHZ * 1e6);  // 直接計(jì)算毫秒
      
      	printf("Thread Cycle Time: %.2f ms\n", milliseconds);
      }
      
      

      哈哈,這兩個(gè)值偏差還是有點(diǎn)大哈。

      三:總結(jié)

      理解墻鐘時(shí)間和線(xiàn)程時(shí)間的底層原理,對(duì)我們后續(xù)的場(chǎng)景分析特別有用,比如前者適合分析為什么程序卡死?后者適合分析是哪些線(xiàn)程吃了那么多的CPU?

      作為JetBrains社區(qū)內(nèi)容合作者,如有購(gòu)買(mǎi)jetbrains的產(chǎn)品,可以用我的折扣碼 HUANGXINCHENG,有25%的內(nèi)部?jī)?yōu)惠哦。

      圖片名稱(chēng)
      posted @ 2025-06-23 10:17  一線(xiàn)碼農(nóng)  閱讀(507)  評(píng)論(2)    收藏  舉報(bào)
      主站蜘蛛池模板: 扒开双腿猛进入喷水高潮叫声| 日韩V欧美V中文在线| 国产亚洲精品VA片在线播放| 国产国产久热这里只有精品| 99福利一区二区视频| 久久久噜噜噜久久| 无遮挡又黄又刺激的视频| 亚洲精品无amm毛片| 国产精品无遮挡猛进猛出| 人妻无码不卡中文字幕系列| 亚洲av永久无码精品天堂久久| 三级国产在线观看| 色成人亚洲| 国产色婷婷亚洲99精品小说| 精品国产一区二区三区麻豆| 国产亚洲精品第一综合另类| 国产自产一区二区三区视频| 欧美和黑人xxxx猛交视频| 久久精品国产久精国产| 狠狠色丁香婷婷综合尤物| 日韩欧激情一区二区三区| 国产精品黑色丝袜在线观看| 欧美日韩精品一区二区三区高清视频| 极品无码国模国产在线观看| 亚洲欧美综合精品成人导航 | 韩国无码AV片午夜福利| 国产精品乱子乱xxxx| 国产精品亚洲一区二区z| 国产精品成人午夜福利| 狠狠色噜噜狠狠狠狠色综合久av | 欧美成人精品手机在线| 欧美黑人添添高潮a片www| 午夜成人无码免费看网站| 国产精品99区一区二区三| 2020国产欧洲精品网站| 亚洲精品成人久久av| 亚洲熟妇自偷自拍另亚洲| 久久久久久久无码高潮| 日韩一区二区三区女优丝袜| 亚洲国产精品自在拍在线播放蜜臀| 国产办公室秘书无码精品99|