diff mbox

[4/4] tools/xenalyze: Allow automatic resizing of sample buffers

Message ID 1470650071-1157-4-git-send-email-george.dunlap@citrix.com (mailing list archive)
State New, archived
Headers show

Commit Message

George Dunlap Aug. 8, 2016, 9:54 a.m. UTC
Rather than have large fixed-size buffers, start with smaller buffers
and allow them to grow as needed (doubling each time), with a fairly
large maximum.  Allow this maximum to be set by a command-line
parameter.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
CC: Ian Jackson <ian.jackson@citrix.com>
CC: Wei Liu <wei.liu2@citrix.com>
CC: Dario Faggioli <dario.faggioli@citrix.com>
CC: Anshul Makkar <anshul.makkar@citrix.com>
---
 tools/xentrace/xenalyze.c | 95 +++++++++++++++++++++++++++++++++--------------
 1 file changed, 68 insertions(+), 27 deletions(-)

Comments

Wei Liu Aug. 8, 2016, 11:05 a.m. UTC | #1
On Mon, Aug 08, 2016 at 10:54:31AM +0100, George Dunlap wrote:
> +
> +            new_size = s->sample_size << 1;
> +
> +            if (new_size == 0)
> +                new_size = opt.sample_size;
> +
> +            if (opt.sample_max != 0 && new_size > opt.sample_max)
> +                new_size = opt.sample_max;
> +
> +            //printf("New size: %d\n", new_size);

Maybe this needs to be deleted?

Wei.
Wei Liu Aug. 8, 2016, 11:09 a.m. UTC | #2
On Mon, Aug 08, 2016 at 12:05:58PM +0100, Wei Liu wrote:
> On Mon, Aug 08, 2016 at 10:54:31AM +0100, George Dunlap wrote:
> > +
> > +            new_size = s->sample_size << 1;
> > +
> > +            if (new_size == 0)
> > +                new_size = opt.sample_size;
> > +
> > +            if (opt.sample_max != 0 && new_size > opt.sample_max)
> > +                new_size = opt.sample_max;
> > +
> > +            //printf("New size: %d\n", new_size);
> 
> Maybe this needs to be deleted?
> 

FAOD I don't think it is worthy of resending just because of this
cosmetic change. Whatever adjustment can be done while committing.

Acked-by: Wei Liu <wei.liu2@citrix.com>

> Wei.
Anshul Makkar Aug. 8, 2016, 5:11 p.m. UTC | #3
On 08/08/16 10:54, George Dunlap wrote:
> Rather than have large fixed-size buffers, start with smaller buffers
> and allow them to grow as needed (doubling each time), with a fairly
> large maximum.  Allow this maximum to be set by a command-line
> parameter.
>
> Signed-off-by: George Dunlap <george.dunlap@citrix.com>
> ---
> CC: Ian Jackson <ian.jackson@citrix.com>
> CC: Wei Liu <wei.liu2@citrix.com>
> CC: Dario Faggioli <dario.faggioli@citrix.com>
> CC: Anshul Makkar <anshul.makkar@citrix.com>
> ---
>   tools/xentrace/xenalyze.c | 95 +++++++++++++++++++++++++++++++++--------------
>   1 file changed, 68 insertions(+), 27 deletions(-)
>
> diff --git a/tools/xentrace/xenalyze.c b/tools/xentrace/xenalyze.c
> index 455cbdf..a4d8823 100644
> --- a/tools/xentrace/xenalyze.c
> +++ b/tools/xentrace/xenalyze.c
> @@ -44,7 +44,8 @@ struct mread_ctrl;
>   #define QHZ_FROM_HZ(_hz) (((_hz) << 10)/ 1000000000)
>
>   #define ADDR_SPACE_BITS 48
> -#define DEFAULT_SAMPLE_SIZE 10240
> +#define DEFAULT_SAMPLE_SIZE 1024
> +#define DEFAULT_SAMPLE_MAX  1024*1024*32
>   #define DEFAULT_INTERVAL_LENGTH 1000
>

>       s->event_count++;
>
>       if (!c)
>           return;
>
>       if(opt.sample_size) {
> -        int lap = (s->count/opt.sample_size)+1,
> -            index =s->count % opt.sample_size;
> -        if((index - (lap/3))%lap == 0) {
> -            if(!s->sample) {
> -                s->sample = malloc(sizeof(*s->sample) * opt.sample_size);
> -                if(!s->sample) {
> -                    fprintf(stderr, "%s: malloc failed!\n", __func__);
> -                    error(ERR_SYSTEM, NULL);
> -                }
> +        if (s->count >= s->sample_size
> +            && (s->count == 0
> +                || opt.sample_max == 0
> +                || s->sample_size < opt.sample_max)) {
> +            int new_size;
> +            void * new_sample = NULL;
> +
> +            new_size = s->sample_size << 1;
Sorry for my ignorance here, but why we have chosen to double the size. 
Can't we increase by fixed size X where X < double size. Are we sure 
that we will be able to fully utilize the double sized buffer.
> +
> +            if (new_size == 0)
> +                new_size = opt.sample_size;
> +
> +            if (opt.sample_max != 0 && new_size > opt.sample_max)
> +                new_size = opt.sample_max;
> +
> +            //printf("New size: %d\n", new_size);
> +
> +            new_sample = realloc(s->sample, sizeof(*s->sample) * new_size);
> +
> +            if (new_sample) {
> +                s->sample = new_sample;
> +                s->sample_size = new_size;
>               }
> -            s->sample[index]=c;
>           }
> +
> +        if (s->count < s->sample_size) {
> +            s->sample[s->count]=c;
> +        } else {
> +            /*
> +             * If we run out of space for samples, start taking only a
> +             * subset of samples.
> +             */
> +            int lap, index;
> +            lap = (s->count/s->sample_size)+1;
> +            index =s->count % s->sample_size;
> +            if((index - (lap/3))%lap == 0) {
> +                s->sample[index]=c;
> +             }
> +         }
>       }
>       s->count++;

>
George Dunlap Aug. 9, 2016, 10:01 a.m. UTC | #4
On Mon, Aug 8, 2016 at 6:11 PM, anshul makkar <anshul.makkar@citrix.com> wrote:
> On 08/08/16 10:54, George Dunlap wrote:
>>
>> Rather than have large fixed-size buffers, start with smaller buffers
>> and allow them to grow as needed (doubling each time), with a fairly
>> large maximum.  Allow this maximum to be set by a command-line
>> parameter.
>>
>> Signed-off-by: George Dunlap <george.dunlap@citrix.com>
>> ---
>> CC: Ian Jackson <ian.jackson@citrix.com>
>> CC: Wei Liu <wei.liu2@citrix.com>
>> CC: Dario Faggioli <dario.faggioli@citrix.com>
>> CC: Anshul Makkar <anshul.makkar@citrix.com>
>> ---
>>   tools/xentrace/xenalyze.c | 95
>> +++++++++++++++++++++++++++++++++--------------
>>   1 file changed, 68 insertions(+), 27 deletions(-)
>>
>> diff --git a/tools/xentrace/xenalyze.c b/tools/xentrace/xenalyze.c
>> index 455cbdf..a4d8823 100644
>> --- a/tools/xentrace/xenalyze.c
>> +++ b/tools/xentrace/xenalyze.c
>> @@ -44,7 +44,8 @@ struct mread_ctrl;
>>   #define QHZ_FROM_HZ(_hz) (((_hz) << 10)/ 1000000000)
>>
>>   #define ADDR_SPACE_BITS 48
>> -#define DEFAULT_SAMPLE_SIZE 10240
>> +#define DEFAULT_SAMPLE_SIZE 1024
>> +#define DEFAULT_SAMPLE_MAX  1024*1024*32
>>   #define DEFAULT_INTERVAL_LENGTH 1000
>>
>
>>       s->event_count++;
>>
>>       if (!c)
>>           return;
>>
>>       if(opt.sample_size) {
>> -        int lap = (s->count/opt.sample_size)+1,
>> -            index =s->count % opt.sample_size;
>> -        if((index - (lap/3))%lap == 0) {
>> -            if(!s->sample) {
>> -                s->sample = malloc(sizeof(*s->sample) * opt.sample_size);
>> -                if(!s->sample) {
>> -                    fprintf(stderr, "%s: malloc failed!\n", __func__);
>> -                    error(ERR_SYSTEM, NULL);
>> -                }
>> +        if (s->count >= s->sample_size
>> +            && (s->count == 0
>> +                || opt.sample_max == 0
>> +                || s->sample_size < opt.sample_max)) {
>> +            int new_size;
>> +            void * new_sample = NULL;
>> +
>> +            new_size = s->sample_size << 1;
>
> Sorry for my ignorance here, but why we have chosen to double the size.
> Can't we increase by fixed size X where X < double size. Are we sure that we
> will be able to fully utilize the double sized buffer.

Well we're sure it will be at least 50% utilized. :-)  Also remember
that we're in userspace here, so no physical memory will be allocated
until the process actually writes to the virtual memory anyway.  The
main goal is to balance virtual memory usage against the cost of
reallocation (which will probably involve copying all the data from
the old buffer into the new buffer), and there's no point in having a
really complicated algorithm until we find cases where the simple
algorithm is a problem.

 -George
George Dunlap Aug. 9, 2016, 2:48 p.m. UTC | #5
On 08/08/16 12:09, Wei Liu wrote:
> On Mon, Aug 08, 2016 at 12:05:58PM +0100, Wei Liu wrote:
>> On Mon, Aug 08, 2016 at 10:54:31AM +0100, George Dunlap wrote:
>>> +
>>> +            new_size = s->sample_size << 1;
>>> +
>>> +            if (new_size == 0)
>>> +                new_size = opt.sample_size;
>>> +
>>> +            if (opt.sample_max != 0 && new_size > opt.sample_max)
>>> +                new_size = opt.sample_max;
>>> +
>>> +            //printf("New size: %d\n", new_size);
>>
>> Maybe this needs to be deleted?
>>
> 
> FAOD I don't think it is worthy of resending just because of this
> cosmetic change. Whatever adjustment can be done while committing.
> 
> Acked-by: Wei Liu <wei.liu2@citrix.com>

Thanks -- I've fixed this and added your ack. :-)

 -George
diff mbox

Patch

diff --git a/tools/xentrace/xenalyze.c b/tools/xentrace/xenalyze.c
index 455cbdf..a4d8823 100644
--- a/tools/xentrace/xenalyze.c
+++ b/tools/xentrace/xenalyze.c
@@ -44,7 +44,8 @@  struct mread_ctrl;
 #define QHZ_FROM_HZ(_hz) (((_hz) << 10)/ 1000000000)
 
 #define ADDR_SPACE_BITS 48
-#define DEFAULT_SAMPLE_SIZE 10240
+#define DEFAULT_SAMPLE_SIZE 1024
+#define DEFAULT_SAMPLE_MAX  1024*1024*32
 #define DEFAULT_INTERVAL_LENGTH 1000
 
 struct array_struct {
@@ -187,7 +188,7 @@  struct {
     unsigned long long histogram_interrupt_increment;
     int interrupt_eip_enumeration_vector;
     int default_guest_paging_levels;
-    int sample_size;
+    int sample_size, sample_max;
     enum error_level tolerance; /* Tolerate up to this level of error */
     struct {
         tsc_t cycles;
@@ -257,6 +258,7 @@  struct {
     .cpu_qhz = QHZ_FROM_HZ(DEFAULT_CPU_HZ),
     .default_guest_paging_levels = 2,
     .sample_size = DEFAULT_SAMPLE_SIZE,
+    .sample_max = DEFAULT_SAMPLE_MAX,
     .tolerance = ERR_SANITY,
     .interval = { .msec = DEFAULT_INTERVAL_LENGTH },
 };
@@ -275,7 +277,7 @@  struct interval_element {
 };
 
 struct cycle_summary {
-    int event_count, count;
+    int event_count, count, sample_size;
     unsigned long long cycles;
     long long *sample;
     struct interval_element interval;
@@ -2203,28 +2205,51 @@  static inline double summary_percent_global(struct cycle_summary *s) {
 }
 
 static inline void update_cycles(struct cycle_summary *s, long long c) {
-/* We don't know ahead of time how many samples there are, and working
- * with dynamic stuff is a pain, and unnecessary.  This algorithm will
- * generate a sample set that approximates an even sample.  We can
- * then take the percentiles on this, and get an approximate value. */
     s->event_count++;
 
     if (!c)
         return;
             
     if(opt.sample_size) {
-        int lap = (s->count/opt.sample_size)+1,
-            index =s->count % opt.sample_size;
-        if((index - (lap/3))%lap == 0) {
-            if(!s->sample) {
-                s->sample = malloc(sizeof(*s->sample) * opt.sample_size);
-                if(!s->sample) {
-                    fprintf(stderr, "%s: malloc failed!\n", __func__);
-                    error(ERR_SYSTEM, NULL);
-                }
+        if (s->count >= s->sample_size
+            && (s->count == 0
+                || opt.sample_max == 0
+                || s->sample_size < opt.sample_max)) {
+            int new_size;
+            void * new_sample = NULL;
+
+            new_size = s->sample_size << 1;
+
+            if (new_size == 0)
+                new_size = opt.sample_size;
+
+            if (opt.sample_max != 0 && new_size > opt.sample_max)
+                new_size = opt.sample_max;
+
+            //printf("New size: %d\n", new_size);
+            
+            new_sample = realloc(s->sample, sizeof(*s->sample) * new_size);
+            
+            if (new_sample) {
+                s->sample = new_sample;
+                s->sample_size = new_size;
             }
-            s->sample[index]=c;
         }
+        
+        if (s->count < s->sample_size) {
+            s->sample[s->count]=c;
+        } else {
+            /* 
+             * If we run out of space for samples, start taking only a
+             * subset of samples.
+             */
+            int lap, index;
+            lap = (s->count/s->sample_size)+1;
+            index =s->count % s->sample_size;
+            if((index - (lap/3))%lap == 0) {
+                s->sample[index]=c;
+             }
+         }
     }
     s->count++;
     s->cycles += c;
@@ -2248,8 +2273,8 @@  static inline void print_cpu_affinity(struct cycle_summary *s, char *p) {
         if ( opt.sample_size ) {
             long long  p5, p50, p95;
             int data_size = s->count;
-           if(data_size > opt.sample_size)
-                data_size = opt.sample_size;
+           if(data_size > s->sample_size)
+               data_size = s->sample_size;
 
             p50 = percentile(s->sample, data_size, 50);
             p5 = percentile(s->sample, data_size, 5);
@@ -2280,8 +2305,8 @@  static inline void print_cycle_percent_summary(struct cycle_summary *s,
             long long p5, p50, p95;
             int data_size = s->count;
 
-            if(data_size > opt.sample_size)
-                data_size = opt.sample_size;
+            if(data_size > s->sample_size)
+                data_size = s->sample_size;
 
             p50 = self_weighted_percentile(s->sample, data_size, 50);
             p5 = self_weighted_percentile(s->sample, data_size, 5);
@@ -2312,8 +2337,8 @@  static inline void print_cycle_summary(struct cycle_summary *s, char *p) {
             long long p5, p50, p95;
             int data_size = s->count;
 
-            if(data_size > opt.sample_size)
-                data_size = opt.sample_size;
+            if(data_size > s->sample_size)
+                data_size = s->sample_size;
 
             p50 = self_weighted_percentile(s->sample, data_size, 50);
             p5 = self_weighted_percentile(s->sample, data_size, 5);
@@ -2335,8 +2360,8 @@  static inline void print_cycle_summary(struct cycle_summary *s, char *p) {
             if ( opt.sample_size ) {                                    \
                 unsigned long long p5, p50, p95;                        \
                 int data_size=(_s).count;                               \
-                if(data_size > opt.sample_size)                         \
-                    data_size=opt.sample_size;                          \
+                if(data_size > (_s).sample_size)                         \
+                    data_size=(_s).sample_size;                          \
                 p50=percentile((_s).sample, data_size, 50);      \
                 p5=percentile((_s).sample, data_size, 5);        \
                 p95=percentile((_s).sample, data_size, 95);      \
@@ -9800,6 +9825,7 @@  enum {
     OPT_SHOW_DEFAULT_DOMAIN_SUMMARY,
     OPT_MMIO_ENUMERATION_SKIP_VGA,
     OPT_SAMPLE_SIZE,
+    OPT_SAMPLE_MAX,
     OPT_REPORT_PCPU,
     /* Guest info */
     OPT_DEFAULT_GUEST_PAGING_LEVELS,
@@ -9982,6 +10008,14 @@  error_t cmd_parser(int key, char *arg, struct argp_state *state)
             argp_usage(state);
         break;
     }
+    case OPT_SAMPLE_MAX:
+    {
+        char * inval;
+        opt.sample_max = (int)strtol(arg, &inval, 0);
+        if( inval == arg )
+            argp_usage(state);
+        break;
+    }
     case OPT_MMIO_ENUMERATION_SKIP_VGA:
     {
         char * inval;
@@ -10519,8 +10553,15 @@  const struct argp_option cmd_opts[] =  {
       .key = OPT_SAMPLE_SIZE,
       .arg = "size",
       .group = OPT_GROUP_SUMMARY,
-      .doc = "Keep [size] samples for percentile purposes.  Enter 0 to " \
-      "disable.  Default 10240.", },
+      .doc = "Start with [size] samples for percentile purposes.  Enter 0 to" \
+      "disable.  Default 1024.", },
+
+    { .name = "sample-max",
+      .key = OPT_SAMPLE_MAX,
+      .arg = "size",
+      .group = OPT_GROUP_SUMMARY,
+      .doc = "Do not allow sample to grow beyond [size] samples for percentile"\
+      " purposes.  Enter 0 for no limit.", },
 
     { .name = "summary",
       .key = OPT_SUMMARY,