On Tue, Jan 13, 2015 at 02:36:56PM -0800, Ben Widawsky wrote: > On Tue, Jan 13, 2015 at 09:19:04PM +0000, O'Rourke, Tom wrote: > > >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 > > > > Any platform other than BYT/CHV? [TOR:] I am thinking about Haswell and Broadwell. The RP1 value can be read from RP_STATE_CAP while the RPe value can be read from PCU mailbox. Do we need to add a sysfs entry for RPe? > >> + 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); > >> + } > > > >> > > >> 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