diff --git a/pkg/cgroup/cgroup_cpu.go b/pkg/cgroup/cgroup_cpu.go index 9d63a1b9093..df1c104f77f 100644 --- a/pkg/cgroup/cgroup_cpu.go +++ b/pkg/cgroup/cgroup_cpu.go @@ -21,6 +21,8 @@ import ( "github.com/pingcap/errors" ) +var errNoCPUControllerDetected = errors.New("no cpu controller detected") + // Helper function for getCgroupCPU. Root is always "/", except in tests. func getCgroupCPUHelper(root string) (CPUUsage, error) { path, err := detectControlPath(filepath.Join(root, procPathCGroup), "cpu,cpuacct") @@ -30,7 +32,7 @@ func getCgroupCPUHelper(root string) (CPUUsage, error) { // No CPU controller detected if path == "" { - return CPUUsage{}, errors.New("no cpu controller detected") + return CPUUsage{}, errNoCPUControllerDetected } mount, ver, err := getCgroupDetails(filepath.Join(root, procPathMountInfo), path, "cpu,cpuacct") diff --git a/pkg/cgroup/cgroup_cpu_test.go b/pkg/cgroup/cgroup_cpu_test.go index fad947632de..c0dbdfcd2b9 100644 --- a/pkg/cgroup/cgroup_cpu_test.go +++ b/pkg/cgroup/cgroup_cpu_test.go @@ -12,18 +12,57 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build linux && enable_flaky_tests +//go:build linux package cgroup import ( + "fmt" + "regexp" "runtime" + "strconv" "sync" + "syscall" "testing" "github.com/stretchr/testify/require" ) +func checkKernelVersionNewerThan(t *testing.T, major, minor int) bool { + u := syscall.Utsname{} + err := syscall.Uname(&u) + require.NoError(t, err) + releaseBs := make([]byte, 0, len(u.Release)) + for _, v := range u.Release { + if v == 0 { + break + } + releaseBs = append(releaseBs, byte(v)) + } + releaseStr := string(releaseBs) + t.Log("kernel release string:", releaseStr) + versionInfoRE := regexp.MustCompile(`[0-9]+\.[0-9]+\.[0-9]+`) + kernelVerion := versionInfoRE.FindAllString(releaseStr, 1) + require.Equal(t, 1, len(kernelVerion), fmt.Sprintf("release str is %s", releaseStr)) + kernelVersionPartRE := regexp.MustCompile(`[0-9]+`) + kernelVersionParts := kernelVersionPartRE.FindAllString(kernelVerion[0], -1) + require.Equal(t, 3, len(kernelVersionParts), fmt.Sprintf("kernel verion str is %s", kernelVerion[0])) + t.Logf("parsed kernel version parts: major %s, minor %s, patch %s", + kernelVersionParts[0], kernelVersionParts[1], kernelVersionParts[2]) + mustConvInt := func(s string) int { + i, err := strconv.Atoi(s) + require.NoError(t, err, s) + return i + } + versionNewerThanFlag := false + if mustConvInt(kernelVersionParts[0]) > major { + versionNewerThanFlag = true + } else if mustConvInt(kernelVersionParts[0]) == major && mustConvInt(kernelVersionParts[1]) > minor { + versionNewerThanFlag = true + } + return versionNewerThanFlag +} + func TestGetCgroupCPU(t *testing.T) { exit := make(chan struct{}) var wg sync.WaitGroup @@ -42,9 +81,18 @@ func TestGetCgroupCPU(t *testing.T) { }() } cpu, err := GetCgroupCPU() - require.NoError(t, err) - require.NotZero(t, cpu.Period) - require.Less(t, int64(1), cpu.Period) + if err == errNoCPUControllerDetected { + // for more information, please refer https://github.com/pingcap/tidb/pull/41347 + if checkKernelVersionNewerThan(t, 4, 7) { + require.NoError(t, err, "linux version > v4.7 and err still happens") + } else { + t.Logf("the error '%s' is ignored because the kernel is too old", err) + } + } else { + require.NoError(t, err) + require.NotZero(t, cpu.Period) + require.Less(t, int64(1), cpu.Period) + } close(exit) wg.Wait() }