From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1030690AbbJ3KFj (ORCPT ); Fri, 30 Oct 2015 06:05:39 -0400 Received: from mail-bn1bon0054.outbound.protection.outlook.com ([157.56.111.54]:38304 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1030450AbbJ3KFf convert rfc822-to-8bit (ORCPT ); Fri, 30 Oct 2015 06:05:35 -0400 Authentication-Results: spf=none (sender IP is 165.204.84.222) smtp.mailfrom=amd.com; alien8.de; dkim=none (message not signed) header.d=none;alien8.de; dmarc=permerror action=none header.from=amd.com; X-WSS-ID: 0NX12P2-08-ANT-02 X-M-MSG: From: Huang Rui To: Borislav Petkov , Guenter Roeck , "Peter Zijlstra" , Jean Delvare , "Andy Lutomirski" , Andreas Herrmann , Thomas Gleixner , "Ingo Molnar" , "Rafael J. Wysocki" , "Len Brown" , John Stultz , =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Weisbecker?= CC: , , , Andreas Herrmann , Aravind Gopalakrishnan , Borislav Petkov , Fengguang Wu , Aaron Lu , SPG_Linux_Kernel , Huang Rui Subject: [PATCH v3 08/10] hwmon: (fam15h_power) Introduce a cpu accumulated power reporting algorithm Date: Fri, 30 Oct 2015 17:57:02 +0800 Message-ID: <1446199024-1896-9-git-send-email-ray.huang@amd.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1446199024-1896-1-git-send-email-ray.huang@amd.com> References: <1446199024-1896-1-git-send-email-ray.huang@amd.com> MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8BIT X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:165.204.84.222;CTRY:US;IPV:NLI;EFV:NLI;SFV:NSPM;SFS:(10009020)(6009001)(2980300002)(428002)(189002)(199003)(23676002)(5001920100001)(77096005)(106466001)(92566002)(229853001)(50226001)(97736004)(5001770100001)(2950100001)(189998001)(105586002)(5008740100001)(36756003)(5820100001)(87936001)(5007970100001)(50986999)(33646002)(53416004)(50466002)(76176999)(5003600100002)(86362001)(101416001)(47776003)(19580395003)(19580405001)(921003)(1121003);DIR:OUT;SFP:1101;SCL:1;SRVR:DM3PR12MB0858;H:atltwp02.amd.com;FPR:;SPF:None;PTR:InfoDomainNonexistent;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: 1;DM3PR12MB0858;2:SZzlLSPYqXn3hTll5WucjFfPH8Rc4rDt4XeiZ6xJ9ya5EXMN0aUn+wnrRTNUyZmPGDLiphmlIRq87nhN0yS/H4c+LwaFKdJZbqhotWjzjObjGj9pTbtwKZZkwFvPU6aNgi/VKe01MYt/hSOkrtkgZSl7oGCVijrZ/7JsKAeOsRI=;3:nkKSe93Onvson4/c/d6BW6upPG6U5htr7s7Ba3RZhgkf3UF9Gjerb50zUBKeXt0qWl0fywe3tXo55BSENaBf/ButlyF6cfuSQYKZqphPEf1bIXFqdeqDyd71b7AI0UE3SFkkgYZBnus4wVd+RismAnVneS1oELqV1JRCEMNoBIJIYf7nivAGHXFFzS78RYGgMT9kxP8Xnmx6hZSExvitdUq/KPMBQzYysWTAFBODiZT7B3oc4+oICrvolhRT2ihh;25:NbzrkwQ2R8V5hl4eI9TM35UbiSwzGffQ/q6aw4CFa0fJgdc/OWDV8rnc3uR/iHIo4GzhDNMvT+hfblr5O4jA49SwrUkkoDKbLnCQNSaW9Mb41whdqbGU/v7SQh0GQvbzZR0cY3dKW/cqQsFmwj4EbCMP9KrLbnnSghrERzn2YszuMacD0sdcbIsp2GUeh6ZOE4O3/TuLwN4sDupIVrIiYByJcItt1a9S5Ee4njdztCNsx/rCNs+w4Oatk4YmSWqlfX6KmZRKpgROXkAWx08b1w== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:DM3PR12MB0858; X-Microsoft-Exchange-Diagnostics: 1;DM3PR12MB0858;20:yvRTVucVWv1ueA/0RhuXtAmtcw+AYNWwviSINjTADpn/aFM4OWSRmf/IUjMhz5yFVYOeB1sQEQ8ZpDXoNms56+zIYukju9mPPPoDlvDF6cuJIx9YoSJ4FkuAtiR1BEWYfLhQn/cOydAW3J2gTLAX+9iGVh2zXKlPq8cnxJDhBTosYDUmMWPPLvwIsklzZmmbKTzRXC2yjvkqT6X7ytot5eGMIE+w92hzKYQLyR7twjLYqERCMTwQpC2xUjK0d4Exgvc0cy5C3wETYvbTNoPll63b6QAlWWyBIJOQuzFkycTgxIYvizyKyCd8/3jQhO8JR9gpO/XN06kA+09h81NBFZBj4vWWWeEVRhN1GpoMzP5hPQjQCZ3kOGnr3xsZJ1YEgeiLZmeW016+KRMHjVdR5bpEfdi2kYifdKZTzFWErMq/y5NXtpWGj47yfSN+eE+/VU2iurin3HL6UJeGl7suwzjF3aSMeDEtlPJZzm1HSZbAZ/ZEKNXzQ7budGdEGpAj;4:qtcQHUak5otF4wEaBQGOHPPm6W3XgWnzsirItQkmI0M2yR1896uP6B6DI7G+l387jAjKk6UyG7JIB3PoLNDna4vuslb+9fHGcbGv2Ogg9OSQdL3Aa40tqR6Ja1CwimgZOUUbniAypFEkvye/UjC3y96bAqvH6473Cn88iysWTuci9+DLegbQ15AYrzUwdhl4zcCxZHZX7/sQ2LfsNzhuw/DJAbl+TBzxMCTjTKnhsoHkjYV17btyLsA4Xd7JWsI9witVzFKXpeWezM5sIYNJbRfVicjg9HGMXQVgkqnOD5dz2yTIVYSU+WhC6z9TrpchQThEGd0XQLti17cpSgp+yBKh90rE5sSM+ltfoeJZR8dfGJxI6ZoNAYDMuVCSRGgbGgysYfXVB3i44VVAjgYfmw== X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(767451399110); X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(2401047)(520078)(5005006)(8121501046)(3002001)(10201501046)(102215026);SRVR:DM3PR12MB0858;BCL:0;PCL:0;RULEID:;SRVR:DM3PR12MB0858; X-Forefront-PRVS: 07459438AA X-Microsoft-Exchange-Diagnostics: =?utf-8?B?MTtETTNQUjEyTUIwODU4OzIzOkVZVUhScUdtVGF0SjVYbHJDblQ1dHdHQXM0?= =?utf-8?B?K3FqZTlqSXBuM1FKN2VCcG9DYWZSdVAzcFVCQVhRMlZkbDZuOXdnU0F2YTJ6?= =?utf-8?B?U1ZlVXNxd2o1MVIzSk9WVFVPc2hyRXJQVFdLK1Z6QTZpNndpRi93aEtDazI5?= =?utf-8?B?ck53eWRMNEErUnZZSDdsQ3ppSm4rV2Nwby9OWHhDVVFkUjZQR1RqNkFRKys2?= =?utf-8?B?NnpUZzk0dTd1MUVvNENqN2U3d0ErUVJ3d3R2OFFMNk5PaUtoK3NjSXZWcjdt?= =?utf-8?B?VnJyR3FNNVgrNzE2MHAzOTl5cGx6RytZR2U5R2JhNzJwTk1EQThGNHI1aC9O?= =?utf-8?B?M0dYVkxwUm03aDlvTU55SmhocWZrb2lJNjB4NXZLRW1uT2xpT2FVOEdoVEV2?= =?utf-8?B?WjU3eFpFRUx4YWl2T0FJR1RzaHp0OXlwWWNBeXlvTE5nN25weEl5UE1mNXZ0?= =?utf-8?B?bFNXZUpHNzlQN0xEMGRWUElxYktZU1dVRWozZGlPamlZRnYxNFdyeE84ZGlR?= =?utf-8?B?dDBuZHQ0MWtZZlljUmJRTFN3V1c3NFUwMlJtZjlrSW5hUFpOeVhqNXZHNHZa?= =?utf-8?B?ZXlOTDFRaktQV0p4dGdEM0FZTFJHaEU2dnpta0k3T0ZtcVI1SXhDSzhvVXFq?= =?utf-8?B?ZGtGdm9MdnkyV2NuaWYzanBVdUtRZjFqc1dXMEh0VWs5RjJFVEI1UDVuM0sv?= =?utf-8?B?RSthY09PSWpuWXA3NnM4RmVEOFJZdmFiYm1IdXNzT2dwMUR3QWE4RVBsWnd5?= =?utf-8?B?Qzd4aUlKWElpV1BjN3lTeGE2ODd5YUVySnVTQjZxWCsrb0I1dEIxT1NkN09x?= =?utf-8?B?ckl4Q0FvZ2I4cVd5UFJvSjVQc25DUFcyQmZVbm9HWEtHS0Nrc0RJUUpRcWtI?= =?utf-8?B?NGltUjJSUTJYNis4cERtZlF3T2Qvd3JIWHpwei9PMGthRCtJaUVEcUpMSmRq?= =?utf-8?B?ZVJIYmtJNitDVVRqa05neFE5ODI4RWpCVS9QYm1KUll3Njk3TlI2Y0hVcTQ5?= =?utf-8?B?NUNzRFUxZUU2N1hINHI2MGxNclVrckZjUEhkeFgvNEZNeWhnSnl5L3JaM1l4?= =?utf-8?B?V3huaTd0VHdwcVh6STFWRWFrZElrajdOOFprUzhjcWRicnVwZTNtaGsvZ2Ni?= =?utf-8?B?RlZ5THdwdmd5V2hkMWJhamhoN3Byd0JNOWdCYjUxVkw0RnIzVWhONXBGSkha?= =?utf-8?B?WGNRcHMySnhOQTRjNmdHMHZ5NmFvd09LNG5nZzRZRFBBaytxNkVpU3E4dmtj?= =?utf-8?B?bkV1Nm9XeVU3ckd1N2NSS241WjVCVjE1dUNjOHZXcjlWS1U5d3VhdGo4MlNT?= =?utf-8?B?dFExN0Zoa1ptM1E9PQ==?= X-Microsoft-Exchange-Diagnostics: 1;DM3PR12MB0858;5:9VvdTx6IyLsgjzjcGCPVhodjv+YNWE3Vn5X3IJPNh8DusgLcJ1sdhn4X9KFFtWT8etzQzotBSCKD2Q3CnGpkHs/D4/vst35K6GfShuoxGNXL5YJ7uylQF6Gjf2FXvriAFte8tF+fhQKxfwGSfMXNnQ==;24:UMB19exsjs3UagcfP9IfVldTh1K3Ee39efc6gMjBFqKF5/yMoQN/P6ORQMhDCvMx/0Kifw0KlXKeJvCjQ2dsoaBL1j5VtDEx172ZRrO1HPg=;20:OyIkw7jskSNKK9Yt4R0aqsZJlSlsh2KdV7ASb76ZZnx6fskhG9fD7S2Lis+kEbwekiIc5CrePbm2dNBLd6MNQk4uPiIMaFNIWJQBECkxKpoXX2Ums/lMCqb4TMKgtecPhJArd5XjPOX+2J5+/g6DU92uLxUSGa1VCMmqpAJhEcARZZPxXsWlr3PU587sKhLPBODlkGO2l6yzqxpzxkjMks0xsAM/XFjKL5vk52IH93i9EfVltCkdRfrcXJOqTCb0 SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Oct 2015 10:05:31.1628 (UTC) X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.222];Helo=[atltwp02.amd.com] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM3PR12MB0858 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch introduces an algorithm that computes the average power by reading a delta value of “core power accumulator” register during measurement interval, and then dividing delta value by the length of the time interval. User is able to use power1_average entry to measure the processor power consumption and power1_average_interval entry to set the interval. A simple example: ray@hr-ub:~/tip$ sensors fam15h_power-pci-00c4 Adapter: PCI adapter power1: 23.73 mW (avg = 634.63 mW, interval = 0.01 s) (crit = 15.00 W) ... The result is current average processor power consumption in 10 millisecond. The unit of the result is uWatt. Suggested-by: Guenter Roeck Signed-off-by: Huang Rui Cc: Borislav Petkov Cc: Peter Zijlstra Cc: Ingo Molnar --- drivers/hwmon/fam15h_power.c | 117 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index ec09814..71c9e6c 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include @@ -48,6 +50,9 @@ MODULE_LICENSE("GPL"); #define FAM15H_NUM_GROUPS 2 #define MAX_CUS 8 +/* set maximum interval as 1 second */ +#define MAX_INTERVAL 1000 + #define MSR_F15H_CU_PWR_ACCUMULATOR 0xc001007a #define MSR_F15H_CU_MAX_PWR_ACCUMULATOR 0xc001007b @@ -65,6 +70,9 @@ struct fam15h_power_data { u64 cu_acc_power[MAX_CUS]; /* performance timestamp counter */ u64 cpu_sw_pwr_ptsc[MAX_CUS]; + /* online/offline status of current compute unit */ + int cu_on[MAX_CUS]; + unsigned long power_period; }; static ssize_t show_power(struct device *dev, @@ -135,6 +143,8 @@ static void do_read_registers_on_cu(void *_data) rdmsrl_safe(MSR_F15H_CU_PWR_ACCUMULATOR, &data->cu_acc_power[cu]); rdmsrl_safe(MSR_F15H_PTSC, &data->cpu_sw_pwr_ptsc[cu]); + + data->cu_on[cu] = 1; } /* @@ -150,6 +160,8 @@ static int read_registers(struct fam15h_power_data *data) cores_per_cu = amd_get_cores_per_cu(); cu_num = boot_cpu_data.x86_max_cores / cores_per_cu; + memset(data->cu_on, 0, sizeof(int) * MAX_CUS); + WARN_ON_ONCE(cu_num > MAX_CUS); ret = zalloc_cpumask_var(&mask, GFP_KERNEL); @@ -193,18 +205,115 @@ static int read_registers(struct fam15h_power_data *data) return 0; } +static ssize_t acc_show_power(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fam15h_power_data *data = dev_get_drvdata(dev); + u64 prev_cu_acc_power[MAX_CUS], prev_ptsc[MAX_CUS], + jdelta[MAX_CUS]; + u64 tdelta, avg_acc; + int cu, cu_num, cores_per_cu, ret; + signed long leftover; + + cores_per_cu = amd_get_cores_per_cu(); + cu_num = boot_cpu_data.x86_max_cores / cores_per_cu; + + ret = read_registers(data); + if (ret) + return 0; + + cu = 0; + while (cu++ < cu_num) { + prev_cu_acc_power[cu] = data->cu_acc_power[cu]; + prev_ptsc[cu] = data->cpu_sw_pwr_ptsc[cu]; + } + + leftover = schedule_timeout_interruptible(msecs_to_jiffies(data->power_period)); + if (leftover) + return 0; + + ret = read_registers(data); + if (ret) + return 0; + + for (cu = 0, avg_acc = 0; cu < cu_num; cu++) { + /* check if current compute unit is online */ + if (data->cu_on[cu] == 0) + continue; + + if (data->cu_acc_power[cu] < prev_cu_acc_power[cu]) { + jdelta[cu] = data->max_cu_acc_power + data->cu_acc_power[cu]; + jdelta[cu] -= prev_cu_acc_power[cu]; + } else { + jdelta[cu] = data->cu_acc_power[cu] - prev_cu_acc_power[cu]; + } + tdelta = data->cpu_sw_pwr_ptsc[cu] - prev_ptsc[cu]; + jdelta[cu] *= data->cpu_pwr_sample_ratio * 1000; + do_div(jdelta[cu], tdelta); + + /* the unit is microWatt */ + avg_acc += jdelta[cu]; + } + + return sprintf(buf, "%llu\n", (unsigned long long)avg_acc); +} +static DEVICE_ATTR(power1_average, S_IRUGO, acc_show_power, NULL); + +static ssize_t acc_show_power_period(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fam15h_power_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lu\n", data->power_period); +} + +static ssize_t acc_set_power_period(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fam15h_power_data *data = dev_get_drvdata(dev); + unsigned long temp; + int ret; + + ret = kstrtoul(buf, 10, &temp); + if (ret) + return ret; + + if (temp > MAX_INTERVAL) + return -EINVAL; + + /* the interval value should be greater than 0 */ + if (temp <= 0) + return -EINVAL; + + data->power_period = temp; + + return count; +} +static DEVICE_ATTR(power1_average_interval, S_IRUGO | S_IWUSR, + acc_show_power_period, acc_set_power_period); + static int fam15h_power_init_attrs(struct pci_dev *pdev, struct fam15h_power_data *data) { int n = FAM15H_MIN_NUM_ATTRS; struct attribute **fam15h_power_attrs; struct cpuinfo_x86 *c = &boot_cpu_data; + u32 cpuid; if (c->x86 == 0x15 && (c->x86_model <= 0xf || (c->x86_model >= 0x60 && c->x86_model <= 0x6f))) n += 1; + cpuid = cpuid_edx(0x80000007); + + /* check if processor supports accumulated power */ + if (cpuid & BIT(12)) + n += 2; + fam15h_power_attrs = devm_kcalloc(&pdev->dev, n, sizeof(*fam15h_power_attrs), GFP_KERNEL); @@ -219,6 +328,11 @@ static int fam15h_power_init_attrs(struct pci_dev *pdev, (c->x86_model >= 0x60 && c->x86_model <= 0x6f))) fam15h_power_attrs[n++] = &dev_attr_power1_input.attr; + if (cpuid & BIT(12)) { + fam15h_power_attrs[n++] = &dev_attr_power1_average.attr; + fam15h_power_attrs[n++] = &dev_attr_power1_average_interval.attr; + } + data->group.attrs = fam15h_power_attrs; return 0; @@ -331,6 +445,9 @@ static int fam15h_power_init_data(struct pci_dev *f4, data->max_cu_acc_power = tmp; + /* set default interval as 10 ms */ + data->power_period = 10; + return read_registers(data); } -- 1.9.1