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: [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
> > 
> 
> 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 <b...@bwidawsk.net>
> > >> Reviewed-by: Jordan Justen <jordan.l.jus...@intel.com>
> > >> Cc: Kenneth Graunke <kenn...@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@lists.freedesktop.org
> > >http://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to