shobhitmehrotra1 / core-plot

Automatically exported from code.google.com/p/core-plot
0 stars 0 forks source link

Poor performance when the plot range need reloading often #329

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
I was doing some profiling in my app that does a lot of pretty heavy math (FFTs 
and matrix algebra) and was surprised to find that about 22% of app's time is 
spent in a single method in CPTPlot:

-(CPTPlotRange *)plotRangeForField:(NSUInteger)fieldEnum

Now, my app could change the data for plot rather often and hence the frequent 
adjustment of plot ranges. The bottleneck is clearly the methods on 
NSDecimalNumber (mostly getting the minimum and maximum), especially when the 
number of points go to tens of thousands. Hence the fix that works for me (not 
sure of universal applicability since I always deal with doubles, not decimals):

NSUInteger numberOfSamples = numbers.numberOfSamples;

if ( numberOfSamples > 0 ) {

        const double *doubles = (const double *)numbers.bytes;

        // Should use Accelerate framework for min and max as soon as the minimum iOS version is 4.0

        double min = INFINITY;
        double max = -INFINITY;

        for (NSUInteger element = 0; element < numberOfSamples; element++) {
            min = MIN(min,doubles[element]);
            max = MAX(max,doubles[element]);
        }

        range = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(min) length:CPTDecimalFromDouble(max - min)];

    }

The bottleneck disappears completely.

Another one that was taking ~8% of running time was part of the time is the 
method on CPTScatterPlot:

-(void)calculateViewPoints:(CGPoint *)viewPoints withDrawPointFlags:(BOOL 
*)drawPointFlags

There constantly using convertPoint:fromLayer: is extremely inefficient, 
especially since we need to apply the same transformation to all the points. 
thus the fix (where we only convert the point once and than use the same 
transformation all the time):

if ( self.doublePrecisionCache ) {
        const double *xBytes = (const double *)[self cachedNumbersForField:CPTScatterPlotFieldX].data.bytes;
        const double *yBytes = (const double *)[self cachedNumbersForField:CPTScatterPlotFieldY].data.bytes;

        CGPoint originTransformed = [self convertPoint:self.frame.origin fromLayer:thePlotArea];

        for ( NSUInteger i = 0; i < dataCount; i++ ) {
            const double x = *xBytes++;
            const double y = *yBytes++;
            if ( !drawPointFlags[i] || isnan(x) || isnan(y) ) {
                viewPoints[i] = CGPointMake(NAN, NAN);
            }
            else {
                double plotPoint[2];
                plotPoint[CPTCoordinateX] = x;
                plotPoint[CPTCoordinateY] = y;

                CGPoint drawPoint = [thePlotSpace plotAreaViewPointForDoublePrecisionPlotPoint:plotPoint];
                drawPoint.x += originTransformed.x;
                drawPoint.y += originTransformed.y;

        viewPoints[i] = drawPoint;
        }
        }
}

The same could of course be done for the decimals. Hope this helps.

Original issue reported on code.google.com by sergiy.p...@gmail.com on 7 Sep 2011 at 3:58

GoogleCodeExporter commented 8 years ago

Original comment by eskr...@mac.com on 8 Sep 2011 at 2:38

GoogleCodeExporter commented 8 years ago
-[CPTPlot plotRangeForField:] is fixed. Changes are committed and pushed.

The enhancement suggested for CPTScatterPlot also applies to other plot types 
and the axes. I will work on those next.

Original comment by eskr...@mac.com on 9 Sep 2011 at 1:07

GoogleCodeExporter commented 8 years ago
This issue was closed by revision 08a91579dee7.

Original comment by eskr...@mac.com on 11 Sep 2011 at 1:41