// Copyright 2016 The Periph Authors. All rights reserved. // Use of this source code is governed under the Apache License, Version 2.0 // that can be found in the LICENSE file. package cpu import ( "io" "io/ioutil" "os" "strconv" "strings" "sync" "time" "periph.io/x/host/v3/fs" ) // MaxSpeed returns the processor maximum speed in Hz. // // Returns 0 if it couldn't be calculated. func MaxSpeed() int64 { if isLinux { return getMaxSpeedLinux() } return 0 } // Nanospin spins for a short amount of time doing a busy loop. // // This function should be called with durations of 10µs or less. func Nanospin(d time.Duration) { // TODO(maruel): Use runtime.LockOSThread()? if isLinux { nanospinLinux(d) } else { nanospinTime(d) } } // var ( mu sync.Mutex maxSpeed int64 = -1 openFile = openFileOrig ) func openFileOrig(path string, flag int) (io.ReadCloser, error) { f, err := fs.Open(path, flag) if err != nil { return nil, err } return f, nil } func getMaxSpeedLinux() int64 { mu.Lock() defer mu.Unlock() if maxSpeed == -1 { maxSpeed = 0 if f, err := openFile("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", os.O_RDONLY); err == nil { defer f.Close() if b, err := ioutil.ReadAll(f); err == nil { s := strings.TrimSpace(string(b)) if i, err := strconv.ParseInt(s, 10, 64); err == nil { // Weirdly, the speed is listed as khz. :( maxSpeed = i * 1000 } } } } return maxSpeed } func nanospinTime(d time.Duration) { // TODO(maruel): That's not optimal; it's actually pretty bad. // time.Sleep() sleeps for really too long, calling it repeatedly with // minimal value will give the caller a wake rate of 5KHz or so, depending on // the host. This makes it useless for bitbanging protocol implementations. for start := time.Now(); time.Since(start) < d; { } }