On 21 October 2014 21:49, Daniel Lezcano <daniel.lezc...@linaro.org> wrote:
> On 10/21/2014 03:47 PM, Tuukka Tikkanen wrote:
>>
>> On Tue, Oct 21, 2014 at 3:42 PM, Daniel Lezcano
>> <daniel.lezc...@linaro.org> wrote:
>>>
>>> On 10/04/2014 06:33 AM, pi-cheng.chen wrote:
>>>>
>>>>
>>>> Initialize struct cpufreq_pstates with initial P-state of CPUs and
>>>> allocate
>>>> struct cpufreq_pstate dynamically when parsing trace file to solve the
>>>> issue
>>>> caused by missing "scaling_avaialable_freqs" attr when using
>>>> intel_pstate
>>>> driver.
>>>>
>>>> Changes v2 to v3:
>>>> Initialize struct cpufreq_pstates with initial P-state of all CPUs and
>>>> beginning timestamp before trace acquisition and close all P-states with
>>>> ending timestamp
>>>>
>>>> hanges v1 to v2:
>>>> Sort the cpufreq_pstate list when parsing events
>>>>
>>>> Signed-off-by: Pi-Cheng Chen <pi-cheng.c...@linaro.org>
>>>
>>>
>>>
>>> At the first glance it looks ok for me.
>>>
>>> Thanks
>>>    -- Daniel
>>
>>
>> Good enough for a reviewed-by with your name?
>
>
> Good enough for an Acked-by: Daniel Lezcano <daniel.lezc...@linaro.org>

Thanks for reviewing.

Pi-Cheng

>
>
>
>> Tuukka
>>
>>>
>>>
>>>> ---
>>>>    idlestat.c | 259
>>>> ++++++++++++++++++++++++++++++++++++++++++++-----------------
>>>>    idlestat.h |   7 ++
>>>>    trace.h    |   1 +
>>>>    3 files changed, 195 insertions(+), 72 deletions(-)
>>>>
>>>> diff --git a/idlestat.c b/idlestat.c
>>>> index da615cb..8230067 100644
>>>> --- a/idlestat.c
>>>> +++ b/idlestat.c
>>>> @@ -536,6 +536,121 @@ static struct cpuidle_cstates
>>>> *build_cstate_info(int
>>>> nrcpus)
>>>>          return cstates;
>>>>    }
>>>>
>>>> +#define TRACE_STAT_FORMAT "%*[^:]:%lf"
>>>> +
>>>> +static double get_trace_ts(void)
>>>> +{
>>>> +       FILE *f;
>>>> +       double ts;
>>>> +
>>>> +       f = fopen(TRACE_STAT_FILE, "r");
>>>> +       if (!f)
>>>> +               return -1;
>>>> +
>>>> +       while (fgets(buffer, BUFSIZE, f)) {
>>>> +               if (!strstr(buffer, "now ts"))
>>>> +                       continue;
>>>> +               if (!sscanf(buffer, TRACE_STAT_FORMAT, &ts))
>>>> +                       ts = -1;
>>>> +               break;
>>>> +       }
>>>> +       fclose(f);
>>>> +
>>>> +       return ts;
>>>> +}
>>>> +
>>>> +static void release_init_pstates(struct init_pstates *init)
>>>> +{
>>>> +       free(init->freqs);
>>>> +       free(init);
>>>> +}
>>>> +
>>>> +static struct init_pstates *build_init_pstates(void)
>>>> +{
>>>> +       struct init_pstates *init;
>>>> +       int nr_cpus, cpu;
>>>> +       unsigned int *freqs;
>>>> +
>>>> +       nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
>>>> +       if (nr_cpus < 0)
>>>> +               return NULL;
>>>> +
>>>> +       init = malloc(sizeof(*init));
>>>> +       if (!init)
>>>> +               return NULL;
>>>> +
>>>> +       freqs = calloc(nr_cpus, sizeof(*freqs));
>>>> +       if (!freqs) {
>>>> +               free(init);
>>>> +               return NULL;
>>>> +       }
>>>> +       memset(freqs, 0, sizeof(*freqs) * nr_cpus);
>>>> +
>>>> +       for (cpu = 0; cpu < nr_cpus; cpu++) {
>>>> +               char *fpath;
>>>> +               unsigned int *freq = &(freqs[cpu]);
>>>> +
>>>> +               if (asprintf(&fpath, CPUFREQ_CURFREQ_PATH_FORMAT, cpu) <
>>>> 0) {
>>>> +                       release_init_pstates(init);
>>>> +                       return NULL;
>>>> +               }
>>>> +               if (read_int(fpath, (int *)freq))
>>>> +                       *freq = 0;
>>>> +               free(fpath);
>>>> +       }
>>>> +       init->nr_cpus = nr_cpus;
>>>> +       init->freqs = freqs;
>>>> +
>>>> +       return init;
>>>> +}
>>>> +
>>>> +/**
>>>> + * alloc_pstate - allocate, sort, and initialize pstate struct
>>>> + * to maintain statistics of P-state transitions
>>>> + * @pstates: per-CPU P-state statistics struct
>>>> + * @freq: frequency for which the newly pstate is allocated
>>>> + *
>>>> + * Return: the index of the newly allocated pstate struct
>>>> + */
>>>> +static int alloc_pstate(struct cpufreq_pstates *pstates, unsigned int
>>>> freq)
>>>> +{
>>>> +       struct cpufreq_pstate *pstate, *tmp;
>>>> +       int nrfreq, i, next = 0;
>>>> +
>>>> +       pstate = pstates->pstate;
>>>> +       nrfreq = pstates->max;
>>>> +
>>>> +       tmp = realloc(pstate, sizeof(*pstate) * (nrfreq + 1));
>>>> +       if (!tmp) {
>>>> +               perror("realloc pstate");
>>>> +               return -1;
>>>> +       }
>>>> +       pstate = tmp;
>>>> +       pstates->pstate = tmp;
>>>> +       pstates->max = nrfreq + 1;
>>>> +
>>>> +       for (i = 0; i < nrfreq && freq <= pstate[i].freq; i++)
>>>> +               ;
>>>> +
>>>> +       next = i;
>>>> +       for (i = nrfreq; i > next && i > 0; i--) {
>>>> +               pstate[i] = pstate[i - 1];
>>>> +               pstate[i].id = i;
>>>> +               pstates->current = (pstates->current == i - 1)?
>>>> +                                       i : pstates->current;
>>>> +       }
>>>> +
>>>> +       pstate[next].id = next;
>>>> +       pstate[next].freq = freq;
>>>> +       pstate[next].count = 0;
>>>> +       pstate[next].min_time = DBL_MAX;
>>>> +       pstate[next].max_time = 0;
>>>> +       pstate[next].avg_time = 0;
>>>> +       pstate[next].duration = 0;
>>>> +
>>>> +       return next;
>>>> +}
>>>> +
>>>>    /**
>>>>     * release_pstate_info - free all P-state related structs
>>>>     * @pstates: per-cpu array of P-state statistics structs
>>>> @@ -560,14 +675,16 @@ static void release_pstate_info(struct
>>>> cpufreq_pstates *pstates, int nrcpus)
>>>>          return;
>>>>    }
>>>>
>>>> -/**
>>>> - * build_pstate_info - parse cpufreq sysfs entries and build per-CPU
>>>> - * structs to maintain statistics of P-state transitions
>>>> +/* build_pstate_info - allocate and initialize per-CPU structs to
>>>> + * maintain statistics of P-state transitions
>>>>     * @nrcpus: number of CPUs
>>>> + * @initp: initial P-state of CPUs before trace acquistion
>>>> + * @start_ts: timestamp when trace acquisition started
>>>>     *
>>>>     * Return: per-CPU array of structs (success) or NULL (error)
>>>>     */
>>>> -static struct cpufreq_pstates *build_pstate_info(int nrcpus)
>>>> +static struct cpufreq_pstates *build_pstate_info(int nrcpus,
>>>> +                       struct init_pstates *initp, double start_ts)
>>>>    {
>>>>          int cpu;
>>>>          struct cpufreq_pstates *pstates;
>>>> @@ -577,67 +694,28 @@ static struct cpufreq_pstates
>>>> *build_pstate_info(int
>>>> nrcpus)
>>>>                  return NULL;
>>>>          memset(pstates, 0, sizeof(*pstates) * nrcpus);
>>>>
>>>> -       for (cpu = 0; cpu < nrcpus; cpu++) {
>>>> -               struct cpufreq_pstate *pstate;
>>>> -               int nrfreq;
>>>> -               char *fpath, *freq, line[256];
>>>> -               FILE *sc_av_freq;
>>>> -
>>>> -               if (asprintf(&fpath, CPUFREQ_AVFREQ_PATH_FORMAT, cpu) <
>>>> 0)
>>>> -                       goto clean_exit;
>>>> -
>>>> -               /* read scaling_available_frequencies for the CPU */
>>>> -               sc_av_freq = fopen(fpath, "r");
>>>> -               free(fpath);
>>>> -               if (!sc_av_freq) {
>>>> -                       fprintf(stderr, "warning: P-states not supported
>>>> for "
>>>> -                               "CPU%d\n", cpu);
>>>> -                       continue;
>>>> -               }
>>>> -               freq = fgets(line, sizeof(line)/sizeof(line[0]),
>>>> sc_av_freq);
>>>> -               fclose(sc_av_freq);
>>>> -               if (!freq) {
>>>> -                       /* unlikely to be here, but just in case... */
>>>> -                       fprintf(stderr, "warning: P-state info not found
>>>> for "
>>>> -                               "CPU%d\n", cpu);
>>>> -                       continue;
>>>> -               }
>>>> +       if (initp)
>>>> +               assert(initp->nr_cpus == nrcpus);
>>>>
>>>> -               /* tokenize line and populate each frequency */
>>>> -               nrfreq = 0;
>>>> -               pstate = NULL;
>>>> -               while ((freq = strtok(freq, "\n ")) != NULL) {
>>>> -                       struct cpufreq_pstate *tmp = realloc(pstate,
>>>> sizeof(*pstate) * (nrfreq+1));
>>>> -                       if (!tmp)
>>>> -                               goto clean_exit;
>>>> -                       pstate = tmp;
>>>> -
>>>> -                       /* initialize pstate record */
>>>> -                       pstate[nrfreq].id = nrfreq;
>>>> -                       pstate[nrfreq].freq = atol(freq);
>>>> -                       pstate[nrfreq].count = 0;
>>>> -                       pstate[nrfreq].min_time = DBL_MAX;
>>>> -                       pstate[nrfreq].max_time = 0.;
>>>> -                       pstate[nrfreq].avg_time = 0.;
>>>> -                       pstate[nrfreq].duration = 0.;
>>>> -                       nrfreq++;
>>>> -                       freq = NULL;
>>>> +       for (cpu = 0; cpu < nrcpus; cpu++) {
>>>> +               struct cpufreq_pstates *ps = &(pstates[cpu]);
>>>> +
>>>> +               ps->pstate = NULL;
>>>> +               ps->max = 0;
>>>> +               ps->current = -1;      /* unknown */
>>>> +               ps->idle = -1;         /* unknown */
>>>> +               ps->time_enter = 0.;
>>>> +               ps->time_exit = 0.;
>>>> +
>>>> +               if (initp && initp->freqs[cpu] > 0 && start_ts > 0) {
>>>> +                       ps->current = alloc_pstate(ps,
>>>> initp->freqs[cpu]);
>>>> +                       assert(ps->current >= 0);
>>>> +                       ps->time_enter = start_ts;
>>>> +                       ps->idle = 0;
>>>>                  }
>>>> -
>>>> -               /* now populate cpufreq_pstates for this CPU */
>>>> -               pstates[cpu].pstate = pstate;
>>>> -               pstates[cpu].max = nrfreq;
>>>> -               pstates[cpu].current = -1;      /* unknown */
>>>> -               pstates[cpu].idle = -1;         /* unknown */
>>>> -               pstates[cpu].time_enter = 0.;
>>>> -               pstates[cpu].time_exit = 0.;
>>>>          }
>>>>
>>>>          return pstates;
>>>> -
>>>> -clean_exit:
>>>> -       release_pstate_info(pstates, nrcpus);
>>>> -       return NULL;
>>>>    }
>>>>
>>>>    static int get_current_pstate(struct cpuidle_datas *datas, int cpu,
>>>> @@ -712,6 +790,9 @@ static void cpu_change_pstate(struct cpuidle_datas
>>>> *datas, int cpu,
>>>>
>>>>          cur = get_current_pstate(datas, cpu, &ps, &p);
>>>>          next = freq_to_pstate_index(ps, freq);
>>>> +       if (next < 0)
>>>> +               next = alloc_pstate(ps, freq);
>>>> +       assert(next >= 0);
>>>>
>>>>          switch (cur) {
>>>>          case 1:
>>>> @@ -742,6 +823,19 @@ static void cpu_change_pstate(struct cpuidle_datas
>>>> *datas, int cpu,
>>>>          }
>>>>    }
>>>>
>>>> +static void cpu_close_all_pstate(struct cpuidle_datas *datas, double
>>>> time)
>>>> +{
>>>> +       struct cpufreq_pstates *ps;
>>>> +       struct cpufreq_pstate *p;
>>>> +       int cpu, cur;
>>>> +
>>>> +       for (cpu = 0; cpu < datas->nrcpus; cpu++) {
>>>> +               cur = get_current_pstate(datas, cpu, &ps, &p);
>>>> +               if (p && !cur && time > 0)
>>>> +                       close_current_pstate(ps, time);
>>>> +       }
>>>> +}
>>>> +
>>>>    static void cpu_pstate_idle(struct cpuidle_datas *datas, int cpu,
>>>> double
>>>> time)
>>>>    {
>>>>          struct cpufreq_pstates *ps = &(datas->pstates[cpu]);
>>>> @@ -763,7 +857,6 @@ static int store_data(double time, int state, int
>>>> cpu,
>>>>                        struct cpuidle_datas *datas, int count)
>>>>    {
>>>>          struct cpuidle_cstates *cstates = &datas->cstates[cpu];
>>>> -       struct cpufreq_pstate *pstate = datas->pstates[cpu].pstate;
>>>>          struct cpuidle_cstate *cstate;
>>>>          struct cpuidle_data *data, *tmp;
>>>>          int nrdata, last_cstate = cstates->last_cstate;
>>>> @@ -826,9 +919,8 @@ static int store_data(double time, int state, int
>>>> cpu,
>>>>                  /* need indication if CPU is idle or not */
>>>>                  cstates->last_cstate = -1;
>>>>
>>>> -               /* update P-state stats if supported */
>>>> -               if (pstate)
>>>> -                       cpu_pstate_running(datas, cpu, time);
>>>> +               /* update P-state stats */
>>>> +               cpu_pstate_running(datas, cpu, time);
>>>>
>>>>                  return 0;
>>>>          }
>>>> @@ -846,9 +938,8 @@ static int store_data(double time, int state, int
>>>> cpu,
>>>>          cstates->cstate_max = MAX(cstates->cstate_max, state);
>>>>          cstates->last_cstate = state;
>>>>          cstates->wakeirq = NULL;
>>>> -       /* update P-state stats if supported */
>>>> -       if (pstate)
>>>> -               cpu_pstate_idle(datas, cpu, time);
>>>> +       /* update P-state stats*/
>>>> +       cpu_pstate_idle(datas, cpu, time);
>>>>
>>>>          return 0;
>>>>    }
>>>> @@ -932,7 +1023,8 @@ static int get_wakeup_irq(struct cpuidle_datas
>>>> *datas, char *buffer, int count)
>>>>          return -1;
>>>>    }
>>>>
>>>> -static struct cpuidle_datas *idlestat_load(struct program_options
>>>> *options)
>>>> +static struct cpuidle_datas *idlestat_load(struct program_options
>>>> *options,
>>>> +                       struct init_pstates *initp, double start_ts,
>>>> double end_ts)
>>>>    {
>>>>          FILE *f;
>>>>          unsigned int state = 0, freq = 0, cpu = 0, nrcpus = 0;
>>>> @@ -988,14 +1080,13 @@ static struct cpuidle_datas *idlestat_load(struct
>>>> program_options *options)
>>>>                  return ptrerror("build_cstate_info: out of memory");
>>>>          }
>>>>
>>>> -       datas->pstates = build_pstate_info(nrcpus);
>>>> +       datas->pstates = build_pstate_info(nrcpus, initp, start_ts);
>>>>          if (!datas->pstates) {
>>>>                  free(datas->cstates);
>>>>                  free(datas);
>>>>                  fclose(f);
>>>>                  return ptrerror("build_pstate_info: out of memory");
>>>>          }
>>>> -
>>>>          datas->nrcpus = nrcpus;
>>>>
>>>>          /* read topology information */
>>>> @@ -1018,7 +1109,6 @@ static struct cpuidle_datas *idlestat_load(struct
>>>> program_options *options)
>>>>                  } else if (strstr(buffer, "cpu_frequency")) {
>>>>                          assert(sscanf(buffer, TRACE_FORMAT, &time,
>>>> &freq,
>>>>                                        &cpu) == 3);
>>>> -                       assert(datas->pstates[cpu].pstate != NULL);
>>>>                          cpu_change_pstate(datas, cpu, freq, time);
>>>>                          count++;
>>>>                          continue;
>>>> @@ -1031,6 +1121,9 @@ static struct cpuidle_datas *idlestat_load(struct
>>>> program_options *options)
>>>>
>>>>          fclose(f);
>>>>
>>>> +       /* close all p-state with end timestamp */
>>>> +       cpu_close_all_pstate(datas, end_ts);
>>>> +
>>>>          fprintf(stderr, "Log is %lf secs long with %zd events\n",
>>>>                  end - begin, count);
>>>>
>>>> @@ -1481,7 +1574,9 @@ int main(int argc, char *argv[], char *const
>>>> envp[])
>>>>    {
>>>>          struct cpuidle_datas *datas;
>>>>          struct program_options options;
>>>> +       struct init_pstates *initp = NULL;
>>>>          int args;
>>>> +       double start_ts, end_ts;
>>>>
>>>>          args = getoptions(argc, argv, &options);
>>>>          if (args <= 0)
>>>> @@ -1527,6 +1622,14 @@ int main(int argc, char *argv[], char *const
>>>> envp[])
>>>>                  if (idlestat_flush_trace())
>>>>                          return -1;
>>>>
>>>> +               /* Get current P-state of all CPUs */
>>>> +               if (options.display & FREQUENCY_DISPLAY)
>>>> +                       initp = build_init_pstates();
>>>> +
>>>> +               /* Get timestamp before trace acquisition */
>>>> +               if (options.display & FREQUENCY_DISPLAY)
>>>> +                       start_ts = get_trace_ts();
>>>> +
>>>>                  /* Start the recording */
>>>>                  if (idlestat_trace_enable(true))
>>>>                          return -1;
>>>> @@ -1549,6 +1652,17 @@ int main(int argc, char *argv[], char *const
>>>> envp[])
>>>>                  if (idlestat_trace_enable(false))
>>>>                          return -1;
>>>>
>>>> +               /* Get timestamp after trace acquisition */
>>>> +               if (options.display & FREQUENCY_DISPLAY)
>>>> +                       end_ts = get_trace_ts();
>>>> +
>>>> +               /* Emit warning messages when P-state info might be
>>>> partial */
>>>> +               if (options.display & FREQUENCY_DISPLAY &&
>>>> +                       (!initp || start_ts < 0 || end_ts < 0))
>>>> +                       fprintf(stderr, "Unable to get initial P-state,"
>>>> +                               " beginning timestamp, or ending
>>>> timestamp!\n"
>>>> +                               "P-state statistics data might be
>>>> partial!\n");
>>>> +
>>>>                  /* At this point we should have some spurious wake up
>>>>                   * at the beginning of the traces and at the end (wake
>>>>                   * up all cpus and timer expiration for the timer
>>>> @@ -1559,7 +1673,7 @@ int main(int argc, char *argv[], char *const
>>>> envp[])
>>>>          }
>>>>
>>>>          /* Load the idle states information */
>>>> -       datas = idlestat_load(&options);
>>>> +       datas = idlestat_load(&options, initp, start_ts, end_ts);
>>>>
>>>>          if (!datas)
>>>>                  return 1;
>>>> @@ -1590,6 +1704,7 @@ int main(int argc, char *argv[], char *const
>>>> envp[])
>>>>                  }
>>>>          }
>>>>
>>>> +       release_init_pstates(initp);
>>>>          release_cpu_topo_cstates();
>>>>          release_cpu_topo_info();
>>>>          release_pstate_info(datas->pstates, datas->nrcpus);
>>>> diff --git a/idlestat.h b/idlestat.h
>>>> index 735f0fe..39ba4d7 100644
>>>> --- a/idlestat.h
>>>> +++ b/idlestat.h
>>>> @@ -41,6 +41,8 @@
>>>>          "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/residency"
>>>>    #define CPUFREQ_AVFREQ_PATH_FORMAT \
>>>>
>>>> "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_available_frequencies"
>>>> +#define CPUFREQ_CURFREQ_PATH_FORMAT \
>>>> +       "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_cur_freq"
>>>>    #define CPUIDLE_STATENAME_PATH_FORMAT \
>>>>          "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name"
>>>>
>>>> @@ -63,6 +65,11 @@ struct cpuidle_cstate {
>>>>          int target_residency; /* -1 if not available */
>>>>    };
>>>>
>>>> +struct init_pstates {
>>>> +       int nr_cpus;
>>>> +       unsigned int *freqs;
>>>> +};
>>>> +
>>>>    enum IRQ_TYPE {
>>>>          HARD_IRQ = 0,
>>>>          IPI_IRQ,
>>>> diff --git a/trace.h b/trace.h
>>>> index bef6703..90b4a6a 100644
>>>> --- a/trace.h
>>>> +++ b/trace.h
>>>> @@ -33,6 +33,7 @@
>>>>    #define TRACE_EVENT_PATH TRACE_PATH "/events/enable"
>>>>    #define TRACE_FREE TRACE_PATH "/free_buffer"
>>>>    #define TRACE_FILE TRACE_PATH "/trace"
>>>> +#define TRACE_STAT_FILE TRACE_PATH "/per_cpu/cpu0/stats"
>>>>    #define TRACE_IDLE_NRHITS_PER_SEC 10000
>>>>    #define TRACE_IDLE_LENGTH 196
>>>>    #define TRACE_CPUFREQ_NRHITS_PER_SEC 100
>>>>
>>>
>>>
>>> --
>>>   <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
>>>
>>> Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
>>> <http://twitter.com/#!/linaroorg> Twitter |
>>> <http://www.linaro.org/linaro-blog/> Blog
>>>
>>>
>>>
>>> _______________________________________________
>>> linaro-dev mailing list
>>> linaro-dev@lists.linaro.org
>>> http://lists.linaro.org/mailman/listinfo/linaro-dev
>
>
>
> --
>  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
>
> Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
> <http://twitter.com/#!/linaroorg> Twitter |
> <http://www.linaro.org/linaro-blog/> Blog
>

_______________________________________________
linaro-dev mailing list
linaro-dev@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-dev

Reply via email to