gettimeofday和clock_gettime是不是系統調用?

在《Linux多線程服務端編程》一書5.1節中提到過,在x86-64的Linux上,gettimeofday不是系統調用,不會陷入內核。其實這種說法有點小問題,因爲gettimeofday確實是個系統調用,但是linux的vdso(virtual dynamic shared object)機制幫我們做到了在調用這些系統調用時不陷入內核,從而提高了性能。

vdso機制說白了就是在用戶空間幫我們實現了一些特定的系統調用,用戶進程啓動時這些代碼會被自動映射到進程地址空間的用戶空間中。這樣的話,當我們利用vdso調用到這些系統調用時,就不會陷入內核了。如何調用到這些代碼呢?直接調用這些系統調用對應的libc包裝函數就可以,因爲這些libc包裝函數默認會使用vdso。如果你執意通過syscall函數/syscall指令/int 0x80來調用這些系統調用,vdso是無法生效的,還是會陷入內核。

當然vdso也不保證一定不會陷入內核,有些情況下是會fallback的,以clock_gettime爲例,下面是linux 4.16版本中該系統調用在vdso中的實現:

notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
{
	switch (clock) {
	case CLOCK_REALTIME:
		if (do_realtime(ts) == VCLOCK_NONE)
			goto fallback;
		break;
	case CLOCK_MONOTONIC:
		if (do_monotonic(ts) == VCLOCK_NONE)
			goto fallback;
		break;
	case CLOCK_REALTIME_COARSE:
		do_realtime_coarse(ts);
		break;
	case CLOCK_MONOTONIC_COARSE:
		do_monotonic_coarse(ts);
		break;
	default:
		goto fallback;
	}

	return 0;
fallback:
	return vdso_fallback_gettime(clock, ts);
}

其中do_realtimedo_monotonic如果返回值爲VCLOCK_NONE的話,就會調用vdso_fallback_gettime,而這個函數是會陷入內核的。另外,clock_gettimeclock參數可不止上面代碼中switch裏面的4個case,如果我們傳入的是CLOCK_BOOTTIME/CLOCK_PROCESS_CPUTIME_ID/CLOCK_THREAD_CPUTIME_ID的話,就會走到default分支,還是會調用vdso_fallback_gettime陷入內核。

綜上所訴,gettimeofdayclock_gettime實際上都是系統調用,但是調用得當的話,可以避免陷入內核,從而提高性能。是否陷入了內核,可以利用strace來判斷。

(爲什麼我會寫這篇文章呢?因爲我之前一直顧慮clock_gettime是個系統調用,雖然精度比gettimeofday高,但性能差不敢多用。爲什麼我會覺得clock_gettime性能差呢?因爲之前用strace排查公司代碼性能問題的時候總是能看到一大堆一大堆的clock_gettime,總耗時加起來佔所有系統調用總耗時比例不低。那看了今天的文章,clock_gettime不是在vdso中有實現麼,爲什麼性能差?那是因爲既然在strace中有輸出,就說明這些clock_gettime還是陷入了內核。爲什麼陷入了內核中呢?那是因爲英偉達顯卡驅動辣!雞!,是的,這些clock_gettime就是英偉達顯卡驅動通過syscall函數調用的。)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章