[Intel-gfx] [PATCH] [v2] intel_frequency: A tool to manipulate Intel GPU frequency
O'Rourke, Tom
Tom.O'Rourke at intel.com
Tue Jan 13 13:19:04 PST 2015
>Sent: Sunday, January 11, 2015 7:48 PM
>To: Widawsky, Benjamin
>Cc: Intel GFX
>Subject: Re: [Intel-gfx] [PATCH] [v2] intel_frequency: A tool to manipulate Intel
>GPU frequency
>
>On Sun, Jan 11, 2015 at 07:35:21PM -0800, Ben Widawsky wrote:
>> WARNING: very minimally tested
>>
>> In general you should not need this tool. It's primary purpose is for
>> benchmarking, and for debugging performance issues.
>
>I noticed the "it's" vs "its" on v1, but forgot to fix it. IT'S fixed locally
>though.
>
>>
>> For many kernel releases now sysfs has supported reading and writing the GPU
>> frequency. Therefore, this tool provides no new functionality. What it does
>> provide is an easy to package (for distros) tool that handles the most common
>> scenarios.
[TOR:] This is a nice tool.
I am concerned that this tool may be confusing RP1 frequency with RPe (Efficient) frequency. On many platforms, these are not the same thing.
Thanks,
Tom O'Rourke
>>
>> v2:
>> Get rid of -f from the usage message (Jordan)
>> Add space before [-s (Jordan)
>> Add a -c/--custom example (Jordan)
>> Add a setting for resetting to hardware default (Ken)
>> Replicate examples in commit message in the source code. (me)
>>
>> Signed-off-by: Ben Widawsky <ben at bwidawsk.net>
>> Reviewed-by: Jordan Justen <jordan.l.justen at intel.com>
>> Cc: Kenneth Graunke <kenneth at whitecape.org>
>>
>> Here are some sample usages:
>> $ sudo intel_frequency --get=cur,min,max,eff
>> cur: 200 MHz
>> min: 200 MHz
>> RP1: 200 MHz
>> max: 1200 MHz
>>
>> $ sudo intel_frequency -g
>> cur: 200 MHz
>> min: 200 MHz
>> RP1: 200 MHz
>> max: 1200 MHz
>>
>> $ sudo intel_frequency -geff
>> RP1: 200 MHz
>>
>> $ sudo intel_frequency --set min=300
>> $ sudo intel_frequency --get min
>> cur: 300 MHz
>> min: 300 MHz
>> RP1: 200 MHz
>> max: 1200 MHz
>>
>> $ sudo intel_frequency --custom max=900
>> $ sudo intel_frequency --get max
>> cur: 300 MHz
>> min: 300 MHz
>> RP1: 200 MHz
>> max: 900 MHz
>>
>> $ sudo intel_frequency --max
>> $ sudo intel_frequency -g
>> cur: 1200 MHz
>> min: 1200 MHz
>> RP1: 200 MHz
>> max: 1200 MHz
>>
>> $ sudo intel_frequency -e
>> $ sudo intel_frequency -g
>> cur: 200 MHz
>> min: 200 MHz
>> RP1: 200 MHz
>> max: 200 MHz
>>
>> $ sudo intel_frequency --max
>> $ sudo intel_frequency -g
>> cur: 1200 MHz
>> min: 1200 MHz
>> RP1: 200 MHz
>> max: 1200 MHz
>>
>> $ sudo intel_frequency --min
>> $ sudo intel_frequency -g
>> cur: 200 MHz
>> min: 200 MHz
>> RP1: 200 MHz
>> max: 200 MHz
>> ---
>> tools/Makefile.sources | 1 +
>> tools/intel_frequency.c | 363
>++++++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 364 insertions(+)
>> create mode 100644 tools/intel_frequency.c
>>
>> diff --git a/tools/Makefile.sources b/tools/Makefile.sources
>> index b85a6b8..2bea389 100644
>> --- a/tools/Makefile.sources
>> +++ b/tools/Makefile.sources
>> @@ -14,6 +14,7 @@ bin_PROGRAMS = \
>> intel_dump_decode \
>> intel_error_decode \
>> intel_forcewaked \
>> + intel_frequency \
>> intel_framebuffer_dump \
>> intel_gpu_time \
>> intel_gpu_top \
>> diff --git a/tools/intel_frequency.c b/tools/intel_frequency.c
>> new file mode 100644
>> index 0000000..59f3814
>> --- /dev/null
>> +++ b/tools/intel_frequency.c
>> @@ -0,0 +1,363 @@
>> +/*
>> + * Copyright © 2015 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the next
>> + * paragraph) shall be included in all copies or substantial portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
>EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
>DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>OTHER
>> + * DEALINGS IN THE SOFTWARE.
>> + *
>> + * Example:
>> + * Get all frequencies:
>> + * intel_frequency --get=cur,min,max,eff
>> + *
>> + * Same as above:
>> + * intel_frequency -g
>> + *
>> + * Get the efficient frequency:
>> + * intel_frequency -geff
>> + *
>> + * Lock the GPU frequency to 300MHz:
>> + * intel_frequency --set min=300
>> + *
>> + * Set the maximum frequency to 900MHz:
>> + * intel_frequency --custom max=900
>> + *
>> + * Lock the GPU frequency to its maximum frequency:
>> + * intel_frequency --max
>> + *
>> + * Lock the GPU frequency to its most efficient frequency:
>> + * intel_frequency -e
>> + *
>> + * Lock The GPU frequency to its minimum frequency:
>> + * intel_frequency --min
>> + *
>> + * Reset the GPU to hardware defaults
>> + * intel_frequency -d
>> + */
>> +
>> +#define _GNU_SOURCE
>> +#include <assert.h>
>> +#include <getopt.h>
>> +#include <stdio.h>
>> +#include <time.h>
>> +#include <unistd.h>
>> +
>> +#include "drmtest.h"
>> +#include "intel_chipset.h"
>> +
>> +static int device, devid;
>> +
>> +enum {
>> + CUR=0,
>> + MIN,
>> + EFF,
>> + MAX,
>> + RP0,
>> + RPn
>> +};
>> +
>> +struct freq_info {
>> + const char *name;
>> + const char *mode;
>> + FILE *filp;
>> + char *path;
>> +};
>> +
>> +static struct freq_info info[] = {
>> + { "cur", "r" },
>> + { "min", "rb+" },
>> + { "RP1", "r" },
>> + { "max", "rb+" },
>> + { "RP0", "r" },
>> + { "RPn", "r" }
>> +};
>> +
>> +static char *
>> +get_sysfs_path(const char *which)
>> +{
>> + static const char fmt[] = "/sys/class/drm/card%1d/gt_%3s_freq_mhz";
>> + char *path;
>> + int ret;
>> +
>> +#define STATIC_STRLEN(string) (sizeof(string) / sizeof(string [0]))
>> + ret = asprintf(&path, fmt, device, which);
>> + assert(ret == (STATIC_STRLEN(fmt) - 3));
>> +#undef STATIC_STRLEN
>> +
>> + return path;
>> +}
>> +
>> +static void
>> +initialize_freq_info(struct freq_info *freq_info)
>> +{
>> + if (freq_info->filp)
>> + return;
>> +
>> + freq_info->path = get_sysfs_path(freq_info->name);
>> + assert(freq_info->path);
>> + freq_info->filp = fopen(freq_info->path, freq_info->mode);
>> + assert(freq_info->filp);
>> +}
>> +
>> +static void wait_freq_settle(void)
>> +{
>> + struct timespec ts;
>> +
>> + /* FIXME: Lazy sleep without check. */
>> + ts.tv_sec = 0;
>> + ts.tv_nsec = 20000;
>> + clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
>> +}
>> +
>> +static void set_frequency(struct freq_info *freq_info, int val)
>> +{
>> + initialize_freq_info(freq_info);
>> + rewind(freq_info->filp);
>> + assert(fprintf(freq_info->filp, "%d", val) > 0);
>> +
>> + wait_freq_settle();
>> +}
>> +
>> +static int get_frequency(struct freq_info *freq_info)
>> +{
>> + int val;
>> +
>> + initialize_freq_info(freq_info);
>> + rewind(freq_info->filp);
>> + assert(fscanf(freq_info->filp, "%d", &val)==1);
>> +
>> + return val;
>> +}
>> +
>> +static void
>> +usage(const char *prog)
>> +{
>> + printf("Usage: %s [-e] [--min | --max] [-g (min|max|efficient)] [-s
>frequency_mhz]\n\n", prog);
>> + printf("%s A program to manipulate Intel GPU frequencies.\n\n", prog);
>> + printf("Options: \n");
>> + printf(" -e Lock frequency to the most efficient
>frequency\n");
>> + printf(" -g, --get= Get the frequency (optional arg:
>\"cur\"|\"min\"|\"max\"|\"eff\")\n");
>> + printf(" -s, --set Lock frequency to an absolute value (MHz)\n");
>> + printf(" -c, --custom Set a min, or max frequency \"min=X |
>max=Y\"\n");
>> + printf(" -m --max Lock frequency to max frequency\n");
>> + printf(" -i --min Lock frequency to min (never a good idea, DEBUG
>ONLY)\n");
>> + printf(" -d --defaults Return the system to hardware defaults\n");
>> + printf("Examples:\n");
>> + printf("\tintel_frequency -gmin,cur Get the current and minimum
>frequency\n");
>> + printf("\tintel_frequency -s 400 Lock frequency to 400Mhz\n");
>> + printf("\tintel_frequency -c max=750 Set the max frequency to
>750MHz\n");
>> + exit(EXIT_FAILURE);
>> +}
>> +
>> +/* Returns read or write operation */
>> +static bool
>> +parse(int argc, char *argv[], bool *act_upon, int *new_freq)
>> +{
>> + int c, tmp;
>> + bool write = false;
>> +
>> + char *token[] = {
>> + (char *)info[CUR].name,
>> + (char *)info[MIN].name,
>> + (char *)"eff",
>> + (char *)info[MAX].name
>> + };
>> +
>> + /* No args means -g" */
>> + if (argc == 1) {
>> + for (c = 0; c < ARRAY_SIZE(act_upon); c++)
>> + act_upon[c] = true;
>> + goto done;
>> + }
>> + while (1) {
>> + int option_index = 0;
>> + static struct option long_options[] = {
>> + { "get", optional_argument, NULL, 'g' },
>> + { "set", required_argument, NULL, 's' },
>> + { "custom", required_argument, NULL, 'c'},
>> + { "min", no_argument, NULL, 'i' },
>> + { "max", no_argument, NULL, 'm' },
>> + { "defaults", no_argument, NULL, 'd' },
>> + { "help", no_argument, NULL, 'h' },
>> + { NULL, 0, NULL, 0}
>> + };
>> +
>> + c = getopt_long(argc, argv, "eg::s:c:midh", long_options,
>&option_index);
>> + if (c == -1)
>> + break;
>> +
>> + switch (c) {
>> + case 'g':
>> + if (write == true)
>> + fprintf(stderr, "Read and write operations not
>support simultaneously.\n");
>> +
>> + if (optarg) {
>> + char *value, *subopts = optarg;
>> + int x;
>> + while (*subopts != '\0') {
>> + x = getsubopt(&subopts, token,
>&value);
>> + if (x == -1) {
>> + fprintf(stderr, "Unrecognized
>option (%s)\n", value);
>> + break;
>> + } else
>> + act_upon[x] = true;
>> + }
>> + } else {
>> + int i;
>> + for (i = 0; i < ARRAY_SIZE(act_upon); i++)
>> + act_upon[i] = true;
>> + }
>> + break;
>> + case 's':
>> + if (!optarg)
>> + usage(argv[0]);
>> +
>> + if (write == true) {
>> + fprintf(stderr, "Only one write may be specified
>at a time\n");
>> + exit(EXIT_FAILURE);
>> + }
>> +
>> + write = true;
>> + act_upon[MIN] = true;
>> + act_upon[MAX] = true;
>> + sscanf(optarg, "%d", &new_freq[MAX]);
>> + new_freq[MIN] = new_freq[MAX];
>> + break;
>> + case 'c':
>> + if (!optarg)
>> + usage(argv[0]);
>> +
>> + if (write == true) {
>> + fprintf(stderr, "Only one write may be specified
>at a time\n");
>> + exit(EXIT_FAILURE);
>> + }
>> +
>> + write = true;
>> +
>> + if (!strncmp("min=", optarg, 4)) {
>> + act_upon[MIN] = true;
>> + sscanf(optarg+4, "%d", &new_freq[MIN]);
>> + } else if (!strncmp("max=", optarg, 4)) {
>> + act_upon[MAX] = true;
>> + sscanf(optarg+4, "%d", &new_freq[MAX]);
>> + } else {
>> + fprintf(stderr, "Selected unmodifiable
>frequency\n");
>> + exit(EXIT_FAILURE);
>> + }
>> + break;
>> + case 'e': /* efficient */
>> + if (IS_VALLEYVIEW(devid) || IS_CHERRYVIEW(devid)) {
>> + /* the LP parts have special efficient frequencies
>*/
>> + fprintf(stderr,
>> + "FIXME: Warning efficient frequency
>information is incorrect.\n");
>> + exit(EXIT_FAILURE);
>> + }
>> + tmp = get_frequency(&info[EFF]);
>> + new_freq[MIN] = tmp;
>> + new_freq[MAX] = tmp;
>> + act_upon[MIN] = true;
>> + act_upon[MAX] = true;
>> + write = true;
>> + break;
>> + case 'i': /* mIn */
>> + tmp = get_frequency(&info[RPn]);
>> + new_freq[MIN] = tmp;
>> + new_freq[MAX] = tmp;
>> + act_upon[MIN] = true;
>> + act_upon[MAX] = true;
>> + write = true;
>> + break;
>> + case 'm': /* max */
>> + tmp = get_frequency(&info[RP0]);
>> + new_freq[MIN] = tmp;
>> + new_freq[MAX] = tmp;
>> + act_upon[MIN] = true;
>> + act_upon[MAX] = true;
>> + write = true;
>> + break;
>> + case 'd': /* defaults */
>> + new_freq[MIN] = get_frequency(&info[RPn]);
>> + new_freq[MAX] = get_frequency(&info[RP0]);
>> + act_upon[MIN] = true;
>> + act_upon[MAX] = true;
>> + write = true;
>> + break;
>> + case 'h':
>> + default:
>> + usage(argv[0]);
>> + }
>> + }
>> +
>> +done:
>> + return write;
>> +}
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +
>> + bool write, fail, targets[MAX+1] = {false};
>> + int i, try = 1, set_freq[MAX+1] = {0};
>> +
>> + devid = intel_get_drm_devid(drm_open_any());
>> + device = drm_get_card();
>> +
>> + write = parse(argc, argv, targets, set_freq);
>> + fail = write;
>> +
>> + /* If we've previously locked the frequency, we need to make sure to set
>things
>> + * in the correct order, or else the operation will fail (ie. min = max =
>200,
>> + * and we set min to 300, we fail because it would try to set min >
>> + * max). This can be accomplished be going either forward or reverse
>> + * through the loop. MIN is always before MAX.
>> + *
>> + * XXX: Since only min and max are at play, the super lazy way is to do
>this
>> + * 3 times and if we still fail after 3, it's for real.
>> + */
>> +again:
>> + if (try > 2) {
>> + fprintf(stderr, "Did not achieve desired freq.\n");
>> + exit(EXIT_FAILURE);
>> + }
>> + for (i = 0; i < ARRAY_SIZE(targets); i++) {
>> + if (targets[i] == false)
>> + continue;
>> +
>> + if (write) {
>> + set_frequency(&info[i], set_freq[i]);
>> + if (get_frequency(&info[i]) != set_freq[i])
>> + fail = true;
>> + else
>> + fail = false;
>> + } else {
>> + printf("%s: %d MHz\n", info[i].name,
>get_frequency(&info[i]));
>> + }
>> + }
>> +
>> + if (fail) {
>> + try++;
>> + goto again;
>> + }
>> +
>> + for (i = 0; i < ARRAY_SIZE(targets); i++) {
>> + if (info[i].filp) {
>> + fclose(info[i].filp);
>> + free(info[i].path);
>> + }
>> + }
>> +
>> + return EXIT_SUCCESS;
>> +}
>> --
>> 2.2.1
>>
>_______________________________________________
>Intel-gfx mailing list
>Intel-gfx at lists.freedesktop.org
>http://lists.freedesktop.org/mailman/listinfo/intel-gfx
More information about the Intel-gfx
mailing list