| package org.apache.cassandra.stress.util; |
| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| |
| |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Random; |
| |
| // represents a sample of long (latencies) together with the probability of selection of each sample (i.e. the ratio of |
| // samples to total number of events). This is used to ensure that, when merging, the result has samples from each |
| // with equal probability |
| public final class SampleOfLongs |
| { |
| |
| // nanos |
| final long[] sample; |
| |
| // probability with which each sample was selected |
| final double p; |
| |
| SampleOfLongs(long[] sample, int p) |
| { |
| this.sample = sample; |
| this.p = 1 / (float) p; |
| } |
| |
| SampleOfLongs(long[] sample, double p) |
| { |
| this.sample = sample; |
| this.p = p; |
| } |
| |
| static SampleOfLongs merge(Random rnd, List<SampleOfLongs> merge, int maxSamples) |
| { |
| // grab the lowest probability of selection, and normalise all samples to that |
| double targetp = 1; |
| for (SampleOfLongs sampleOfLongs : merge) |
| targetp = Math.min(targetp, sampleOfLongs.p); |
| |
| // calculate how many samples we should encounter |
| int maxLength = 0; |
| for (SampleOfLongs sampleOfLongs : merge) |
| maxLength += sampleOfLongs.sample.length * (targetp / sampleOfLongs.p); |
| |
| if (maxLength > maxSamples) |
| { |
| targetp *= maxSamples / (double) maxLength; |
| maxLength = maxSamples; |
| } |
| |
| long[] sample = new long[maxLength]; |
| int count = 0; |
| out: for (SampleOfLongs latencies : merge) |
| { |
| long[] in = latencies.sample; |
| double p = targetp / latencies.p; |
| for (int i = 0 ; i < in.length ; i++) |
| { |
| if (rnd.nextDouble() < p) |
| { |
| sample[count++] = in[i]; |
| if (count == maxLength) |
| break out; |
| } |
| } |
| } |
| if (count != maxLength) |
| sample = Arrays.copyOf(sample, count); |
| Arrays.sort(sample); |
| return new SampleOfLongs(sample, targetp); |
| } |
| |
| public double medianLatency() |
| { |
| if (sample.length == 0) |
| return 0; |
| return sample[sample.length >> 1] * 0.000001d; |
| } |
| |
| // 0 < rank < 1 |
| public double rankLatency(float rank) |
| { |
| if (sample.length == 0) |
| return 0; |
| int index = (int)(rank * sample.length); |
| if (index >= sample.length) |
| index = sample.length - 1; |
| return sample[index] * 0.000001d; |
| } |
| |
| } |
| |