func uploadPlot(dataPoints []*data.Point, s3Config *uploader.Config, cpuCsv []byte) {
	ag := aggregator.New(dataPoints, time.Duration(*interval)*time.Second)
	report := ag.Data()

	filename := time.Now().UTC().Format(time.RFC3339)

	csvData := report.GenerateCSV()
	loc, err := uploader.Upload(s3Config, bytes.NewBuffer(csvData), filename+".csv", false)
	if err != nil {
		fmt.Fprintf(os.Stderr, "uploading to s3 error: %s\n", err)
		os.Exit(1)
	}
	fmt.Fprintf(os.Stdout, "csv uploaded to %s\n", loc)

	fmt.Fprintln(os.Stderr, "Generating plot from csv data")
	plotBuffer, err := plotgen.Generate(filename, csvData, cpuCsv, *comparisonFile)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to generate plot: %s\n", err)
		os.Exit(1)
	}

	loc, err = uploader.Upload(s3Config, plotBuffer, filename+".png", true)
	if err != nil {
		fmt.Fprintf(os.Stderr, "uploading to s3 error: %s\n", err)
		os.Exit(1)
	}
	fmt.Fprintf(os.Stdout, "png uploaded to %s\n", loc)
}
func stopCPUMonitor(url string, s3config *uploader.Config) ([]byte, error) {
	startURL := fmt.Sprintf("http://%s/stop", url)
	resp, err := http.Get(startURL)
	if err != nil {
		return nil, fmt.Errorf("calling cpumonitor stop %s", err)
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("received resp %d", resp.StatusCode)
	}

	rawData, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()

	filename := fmt.Sprintf("cpuStats-%s.csv", time.Now().UTC().Format(time.RFC3339))

	csvData, err := data.GenerateCpuCSV(rawData)
	if err != nil {
		return nil, fmt.Errorf("GeneratateCpuCSV %d", resp.StatusCode)
	}

	loc, err := uploader.Upload(s3config, bytes.NewBuffer(csvData), filename, false)
	if err != nil {
		return nil, fmt.Errorf("uploading to s3 error: %s", err)
	}
	fmt.Fprintf(os.Stdout, "csv uploaded to %s\n", loc)

	return csvData, nil
}
					ghttp.VerifyHeaderKV("X-Amz-Acl", "public-read"),
					func(rw http.ResponseWriter, req *http.Request) {
						defer GinkgoRecover()
						defer req.Body.Close()
						bodyBytes, err := ioutil.ReadAll(req.Body)
						Expect(err).ToNot(HaveOccurred())
						bodyChan <- bodyBytes
					},
					ghttp.RespondWith(http.StatusOK, nil),
				))
			})
			AfterEach(func() {
				close(bodyChan)
			})
			It("can upload a publicly-readable file S3 with retries", func() {
				dest, err := uploader.Upload(uploadConfig, file, fileName, false)
				Expect(err).ToNot(HaveOccurred())
				Expect(dest).To(Equal(testS3Server.URL() + "/" + bucketName + "/" + fileName))
				var bodyBytes []byte
				Eventually(bodyChan).Should(Receive(&bodyBytes))
				Expect(string(bodyBytes)).To(Equal("test body"))
			})
		})
		Context("with a content type specified", func() {
			BeforeEach(func() {
				testS3Server.AppendHandlers(ghttp.VerifyContentType("image/png"))
			})
			It("can upload a publicly-readable file S3 with retries", func() {
				dest, err := uploader.Upload(uploadConfig, file, fileName, true)
				Expect(err).ToNot(HaveOccurred())
				Expect(dest).To(Equal(testS3Server.URL() + "/" + bucketName + "/" + fileName))