I switched to using strokePath() instead of drawLine() (coded pretty much exactly as suggested by samuel) but it doesn't seem to have made much difference to the CPU load (maybe x2 improvement, but not, say, x10).
I'm drawing 11 paths, each of which grows to ~2000 path segments (as external data arrives), so > 20,000 path segments for each paint(). Once this much data is available, it takes ~4 seconds to paint the whole graph. The time taken to draw is pretty much linearly related to the number of path segments rather than any of the more constant bits like the gridlines and text.
(Drawing that many segments may sound excessive but I'm already sub-sampling the data so that I don't draw sub-pixel lines and I need to represent a min/max Y value at each X pixel with a vertical line.)
I'm running Kubuntu 12.04 on an i5 Sony Vaio laptop using JUCE 3.0.8.
Maybe that sort of paint time is to be expected? I don't have the experience to know, but it does feel like I should be able to do better!
gprof gives me:
% cumulative self self total
time seconds seconds calls Ts/call Ts/call name
23.17 3.07 3.07 juce::EdgeTable::copyEdgeTableData(int*, int, int const*, int, int)
11.62 4.61 1.54 juce::RenderingHelpers::EdgeTableFillers::SolidColour<juce::PixelARGB, false>::replaceLine(juce::PixelARGB*, juce::PixelARGB, int) const
6.57 5.48 0.87 juce_xy_graph_t::x_to_px(double) const
5.74 6.24 0.76 juce::PixelARGB::getARGB() const
5.21 6.93 0.69 juce_scrolling_time_graph_t::paint_data(juce::Graphics&, juce_scrolling_time_graph_t::y_data_fifo_t*, unsigned int, unsigned int, bool)
3.77 7.43 0.50 juce::PixelARGB* juce::addBytesToPointer<juce::PixelARGB, int>(juce::PixelARGB*, int)
3.47 7.89 0.46 juce::EdgeTable::EdgeTable(juce::Rectangle<int> const&, juce::Path const&, juce::AffineTransform const&)
3.40 8.34 0.45 juce::EdgeTable::LineItem::operator<(juce::EdgeTable::LineItem const&) const
2.75 8.71 0.36 void juce::PixelARGB::set<juce::PixelARGB>(juce::PixelARGB const&)
2.72 9.06 0.36 void std::__adjust_heap<juce::EdgeTable::LineItem*, int, juce::EdgeTable::LineItem>(juce::EdgeTable::LineItem*, int, int, juce::EdgeTable::LineItem)
2.04 9.34 0.27 juce::EdgeTable::LineItem* std::__unguarded_partition<juce::EdgeTable::LineItem*, juce::EdgeTable::LineItem>(juce::EdgeTable::LineItem*, juce::EdgeTable::LineItem*, juce::EdgeTable::LineItem const&)
2.00 9.60 0.27 juce_xy_graph_t::y1_to_px(float) const
1.43 9.79 0.19 void juce::EdgeTable::iterate<juce::RenderingHelpers::EdgeTableFillers::SolidColour<juce::PixelARGB, false> >(juce::RenderingHelpers::EdgeTableFillers::SolidColour<juce::PixelARGB, false>&) const
1.36 9.97 0.18 juce::PathFlatteningIterator::next()
1.36 10.15 0.18 int const& std::max<int>(int const&, int const&)
1.17 10.30 0.15 void juce::PixelRGB::set<juce::PixelARGB>(juce::PixelARGB const&)
1.09 10.45 0.14 juce::EdgeTable::sanitiseLevels(bool)
Any further pointers gratefully received. Thanks!