From owner-freebsd-acpi@FreeBSD.ORG Sun Dec 23 16:30:54 2007 Return-Path: Delivered-To: freebsd-acpi@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2AA2C16A417 for ; Sun, 23 Dec 2007 16:30:54 +0000 (UTC) (envelope-from andrey.kosachenko@gmail.com) Received: from fk-out-0910.google.com (fk-out-0910.google.com [209.85.128.187]) by mx1.freebsd.org (Postfix) with ESMTP id 9D51B13C4CE for ; Sun, 23 Dec 2007 16:30:53 +0000 (UTC) (envelope-from andrey.kosachenko@gmail.com) Received: by fk-out-0910.google.com with SMTP id b27so1829543fka.11 for ; Sun, 23 Dec 2007 08:30:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:message-id:date:user-agent:mime-version:to:subject:content-type:from; bh=8eorWfvOVjoK7Qg37Lk4CsSZIP1NmuqA38jWQkqZCeE=; b=Gdj3n97CRE9zNs9lcP96tOZjLD3TMnkJjfDnf9Zz1SowfB8GZOPHQH+BzqEtbwsBq5xd1vXFa1muy0+QgMrXJCLCbHrpS2HzjxYWDW6A3poAAYduzhMiPgLsfBUEpom/QNpxxrRPiBWQQ6+BfTFTS5XY+bWonV3HIb3jeeyrAIk= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:user-agent:mime-version:to:subject:content-type:from; b=HjGbPpTL6DPe5yK33Lppd5Dgq/dSxMlcvfBItF5fO9X1NcLexj1kkYrxZgx7SKNuXNfE8tcV8pl2Roq5bsgiwosuIl0j+v9XIf6h2p+2qPEh8u0BlUWQonzbXQzVQujK/c5BHEXaaDJKJL+FUDy51xQz7bQPtMwnPcaBk0Ui8wU= Received: by 10.78.204.20 with SMTP id b20mr4441170hug.33.1198425775462; Sun, 23 Dec 2007 08:02:55 -0800 (PST) Received: from beastie.lan ( [195.60.174.21]) by mx.google.com with ESMTPS id g17sm3040055nfd.10.2007.12.23.08.02.52 (version=SSLv3 cipher=RC4-MD5); Sun, 23 Dec 2007 08:02:54 -0800 (PST) Message-ID: <476E8674.5000303@gmail.com> Date: Sun, 23 Dec 2007 18:01:56 +0200 User-Agent: Thunderbird 2.0.0.9 (X11/20071129) MIME-Version: 1.0 To: freebsd-acpi@FreeBSD.org Content-Type: multipart/mixed; boundary="------------050801090600030805090806" From: Andrey Cc: Subject: powerd doesn't decrease CPU frequency in some cases X-BeenThere: freebsd-acpi@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: ACPI and power management development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 23 Dec 2007 16:30:54 -0000 This is a multi-part message in MIME format. --------------050801090600030805090806 Content-Type: text/plain; charset=windows-1251; format=flowed Content-Transfer-Encoding: 7bit Good time of the day. I've noticed that powerd isn't able to decrease CPU frequency on my laptop (HP Compaq 6710b) as soon as frequency gets highest level. I've pottered a bit in the sources and it seems found the root of the issue. So those who are interested in the subject let consider it. For instance my system reports the following frequency levels: [silent@beastie][/home/silent]sysctl dev.cpu.0.freq_levels dev.cpu.0.freq_levels: 2001/35000 2000/35000 1750/30625 1600/25000 1400/21875 1200/16000 1050/14000 900/12000 800/14000 700/12250 600/10500 500/8750 400/7000 300/5250 If I try to adjust current frequency to 2000 MHz then I'll get: [silent@beastie][/home/silent]sudo sysctl dev.cpu.0.freq=2000 dev.cpu.0.freq: 300 -> 2001 Let check: [silent@beastie][/home/silent]sysctl dev.cpu.0.freq dev.cpu.0.freq: 2001 Thus, as you can see, I have level "2000" which system reports me but actually I can't to adjust those one exactly because it silently becomes "2001" Well... If I'm not mistaken powerd calculates the current "CPU idle mark" and if it is more then adopted value (by default 90%) then it shifts CPU frequency value 1 step down. In my case powerd sticks at "2001". It is obvious because when powerd decreases CPU frequency from the highest frequency level we'll get the following scenario: +-----------------------+ | dev.cpu.0.freq=2001 +--<-+ +-----------+-----------+ | | | Y | +-----------+-----------+ | | "CPU idle" > 90% | | +-----------+-----------+ | | | Y ^ +-----------+-----------+ ^ | powerd shifts freq. | ^ | 1 step down: | | | "2001" -> "2000" | | +-----------+-----------+ | | | Y | +-----------+-----------+ | | actually we have here | | | dev.cpu.0.freq == 2001+-->-+ +-----------------------+ According to the things mentioned above I've came to conclusion that in my case it is not a good idea to rely on frequency levels reported by the system. (Also I saw many sysctl mibs (dev.cpu.0.freq) of many other people. And there were "strange" frequency levels like "2000" and "2001". Of course I can't state that their systems' behaviors fit my case. But still...) So the simple way out I see is to teach powerd recognize "fake" frequency levels. Here I suggest a very simple workaround (and may be quite ugly... sorry I'm not sure if it is my cup of tee) which allows me to overcome the issue. And I hope it can be useful for smb. else. Also I'd like to hear opinions of others. May be there exists another and simpler way to overcome an issue or even I've missed something or not aware of something. Thank you. -- Sincerely, Andrey Kosachenko --------------050801090600030805090806 Content-Type: text/plain; name="powerd.c.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="powerd.c.diff" --- /usr/src/usr.sbin/powerd/powerd.c 2007-06-13 22:05:11.000000000 +0300 +++ /home/silent/Data/powerd/powerd.c 2007-12-23 16:52:50.000000000 +0200 @@ -79,6 +79,8 @@ static int read_usage_times(long *idle, long *total); static int read_freqs(int *numfreqs, int **freqs, int **power); +static int reduct_freqs(int *numfreqs, int **freqs, int **power); +static int get_freq(void); static int set_freq(int freq); static void acline_init(void); static void acline_read(void); @@ -189,6 +191,68 @@ return (0); } + +static int +reduct_freqs(int *numfreqs, int **freqs, int **power) +{ + int i = 0; + int k = 0; + int curfreq = 0; + int mem_frequency = get_freq(); + for (i = 0; i < *numfreqs; i++) { + if (vflag) { + printf("Checking frequency %5d - ", (*freqs)[i]); + } + + if (set_freq((*freqs)[i]) == 0) { + curfreq = get_freq(); + if (curfreq > 0 && curfreq == (*freqs)[i]) { + if (vflag) { + printf("[ OK ]\n"); + } + } + else { + if (vflag) { + printf("[FAIL] -> excluding frequency from levels list\n"); + } + + --(*numfreqs); + for (k = i; k < (*numfreqs); k++) { + (*freqs)[k] = (*freqs)[k + 1]; + (*power)[k] = (*power)[k + 1]; + } + + (*freqs)[(*numfreqs)] = 0; + (*power)[(*numfreqs)] = 0; + } + } + } + + if (mem_frequency > 0) { + set_freq(mem_frequency); + } + + return (0); +} + + +static int +get_freq(void) +{ + int curfreq = 0; + size_t len; + + len = sizeof(curfreq); + if (sysctl(freq_mib, 4, &curfreq, &len, NULL, 0) != 0) { + if (vflag) + warn("error reading current CPU frequency"); + return 0; + } + + return (curfreq); +} + + static int set_freq(int freq) { @@ -452,7 +516,11 @@ err(1, "read_usage_times"); if (read_freqs(&numfreqs, &freqs, &mwatts)) err(1, "error reading supported CPU frequencies"); - + + if (reduct_freqs(&numfreqs, &freqs, &mwatts) != 0) { + warn("cannot exclude lame frequencies from list"); + } + /* Run in the background unless in verbose mode. */ if (!vflag) { pid_t otherpid; --------------050801090600030805090806--