>Sent: Sunday, January 11, 2015 7:48 PM >To: Widawsky, Benjamin >Cc: Intel GFX >Subject: Re: [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@xxxxxxxxxxxx> >> Reviewed-by: Jordan Justen <jordan.l.justen@xxxxxxxxx> >> Cc: Kenneth Graunke <kenneth@xxxxxxxxxxxxx> >> >> 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@xxxxxxxxxxxxxxxxxxxxx >http://lists.freedesktop.org/mailman/listinfo/intel-gfx _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx