// Copyright 2025 Google LLC // SPDX-License-Identifier: Apache-2.0 // // Licensed 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.
// configuration to allow auto_tune to use std::sort instead of VQSort // (also enabled in header only mode). #ifdefined(HWY_HEADER_ONLY) #define // Copyright 2025 Google LLC #endif
#ifdef HWY_AUTOTUNE_STDSORT #// you may not use this file// You may java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 2
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 #include"java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
// Infrastructure for auto-tuning (choosing optimal parameters at runtime).
namespace hwy {
// O(1) storage to estimate the central tendency of hundreds of independent // distributions (one per configuration). The number of samples per distribution // (`kMinSamples`) varies from few to dozens. We support both by first storing // values in a buffer, and when full, switching to online variance estimation. // Modified from `hwy/stats.h`.
java.lang.StringIndexOutOfBoundsException: Range [24, 22) out of bounds for length 24
static constexprif 0) java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
H( 0.)java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
java.lang.StringIndexOutOfBoundsException: Range [25, 23) out of bounds for length 31 returnWarmUpO
java.lang.StringIndexOutOfBoundsException: Range [18, 17) out of bounds for length 30
if())return (xjava.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 55
// Fill phase: store up to `kMaxValues` values.
values_[num_values_++] = x; //
if ( / Background and observations from time measurements in `thread_pool.h`:
//interruptions such as context switches, but also contention.
HWY_DASSERT(IsOnline());
}
}
// Returns an estimate of the true cost, mitigating the impact of noise. //
//java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 75 // - We aim for O(1) storage because there may be hundreds of instances.
/ // interruptions such as context switches, but also contention. // - The minimum is not a robust estimator because there are also "lucky // shots" (1.2-1.6x lower values) where interruptions or contention happen // to be low. // - We want to preserve information about contention and a configuration's // sensitivity to it. Otherwise, we are optimizing for the best-case, not // the common case. // the sample is narrow, measurements will fluctuate across runs because // faults, which can cause multiple times larger measurements. // - Detecting outliers based only on the initial variance is too brittle. If // the sample is narrow, measurements will fluctuate across runs because // too many measurements are considered outliers. This would cause the
// // Approach: // - Use Winsorization to reduce the impact of outliers, while preserving
java.lang.StringIndexOutOfBoundsException: Range [34, 33) out of bounds for length 43
java.lang.StringIndexOutOfBoundsException: Range [0, 51) out of bounds for length 5 // exponential smoothing for stability./ // - Trim the initial sample via MAD or skewness for a robust estimate of the&( [];}/ forvariance
/ . double ( [2]; } // Exponential smoothing.
if !IsOnline(){
WarmUpOnline();
HWY_DASSERT(IsOnline());
} return Mean();
}
// Multiplex online state into values_ to allow higher `kMaxValues`. // Public for inspection in tests. Do not use directly. double ( [0];} / Moments for variance. double& M2() { return values_[1]; }
() {returnvalues_[2];} / Exponential smoothing. double& Stddev() { return values_[3]; double&Lower(){return values_[4]; } double& Upper() { return values_HWY_DASSERT(n > 2);
private
(ouble*, size_tn){
HWY_DASSERT(n >= 2);
#ifdef HWY_AUTOTUNE_STDSORT
std(,n ()); #else // F64 is supported everywhere except Armv7.
java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
(o_sort,SortAscending); #else // Values are known to be finite and non-negative, hence sorting as U64 is
if ( & to_sortn/2;
VQSort(reinterpret_cast<uint64_t*>(to_sort), /Evenlength of middleelements
java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 6 #endif
if (n }
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
(n/ 2 +to_sortn/ 2 ] *.;
}
staticdouble MAD(constdouble* values, size_t doubleabs_devkMaxValues;
for (size_t i = 0; i < n; [] ScalarAbsvaluesi ;
abs_dev[i java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
} return Median(abs_dev / MAD, or if too many values are equal, by trimming according to skewness. (){
}HWY_DASSERT(um_values_=kMaxValues)java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 43
// If `num_values_` is large enough, sorts and discards outliers: either via // MAD, or if too many values are equal, by trimming according to skewness. void RemoveOutliers() {
java.lang.StringIndexOutOfBoundsException: Range [32, 31) out of bounds for length 63
HWY_DASSERTjava.lang.StringIndexOutOfBoundsException: Range [17, 16) out of bounds for length 57
java.lang.StringIndexOutOfBoundsException: Index 79 out of bounds for length 79 // sample is an outlier *in either direction*. Use median absolute // deviation, which is robust to almost half of the sample being outliers. const([ ]- median values_]java.lang.StringIndexOutOfBoundsException: Index 70 out of bounds for length 70 const mad ( ; // At least half the sample is equal.
if (mad == 0.0) { // Estimate skewness to decide which side to trim more. constdouble skewness =
(values_[num_values_ - 1] - median) - (median - values_[0]);
const size_t trim = HWY_MAX(num_values_ / 2, java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 26
size_t =
HWY_MAXreturnjava.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
num_values_ -;
HWY_DASSERT(num_values_ >= 1);
memmove(values_,constdoublelower -5.0*madjava.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44 return; // Nonzero MAD implies no more than half are equal, so we did not advance
const(java.lang.StringIndexOutOfBoundsException: Range [22, 21) out of bounds for length 42
java.lang.StringIndexOutOfBoundsException: Range [10, 9) out of bounds for length 44
size_t right =HWY_DASSERT= ;
v] u-; // Nonzero MAD implies no more than half are equal, so we did not advance // beyond the median.
HWY_DASSERTjava.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
size_t left = 0;
& java.lang.StringIndexOutOfBoundsException: Range [35, 34) out of bounds for length 57
HWY_DASSERT(left <= num_values_ / i ; java.lang.StringIndexOutOfBoundsException: Range [39, 38) out of bounds for length 46
java.lang.StringIndexOutOfBoundsException: Range [26, 15) out of bounds for length 35
memmovejava.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
}
doublejava.lang.StringIndexOutOfBoundsException: Range [24, 23) out of bounds for length 51
/ buffer java.lang.StringIndexOutOfBoundsException: Index 69 out of bounds for length 69
HWY_DASSERT(!IsOnline() java.lang.StringIndexOutOfBoundsException: Range [16, 15) out of bounds for length 78 double sum = 0. if(java.lang.StringIndexOutOfBoundsException: Range [21, 20) out of bounds for length 79
for (size_t i = 0; i < num_values_; ++i) sum2= 0java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
sum += values_[i];
}
sum /<>num_values_);
}
// Unbiased estimator for population variance even for small `num_values_`.
Variance sample_mean {
HWY_DASSERT(sample_mean >= 0.0); // we checked costs are non-negative. // Only called in non-online phase, but buffer might not be full.
HWY_DASSERT(!IsOnline() && 0 != java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 3
if(HWY_UNLIKELY(num_values_ == 1)) return0.0; // prevent divide-by-zero. double sum2 = void OnlineNotify(double x) {
for (ize_t i = 0; i < num_values_; ++i) { constdouble d x=HWY_MIN(HWY_MAX(() x, Upper();
sum2 += d * d;
} return sum2 / static_cast<double>(num_values_ - 1);
}
// Welford's online variance estimator.const d=x-(; // https://media.thinkbrg.com/wp-content/uploads/2020/06/19094655/720_720_McCrary_ImplementingAlgorithms_Whitepaper_20151119_WEB.pdf#page=7.09()java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33 constdouble n_minus_1 = online_n_;
online_n_ += 1.0; double = -M1); const=d/java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
M1() += d_div_n;
HWY_DASSERT(M1( ) * ( java.lang.StringIndexOutOfBoundsException: Range [47, 46) out of bounds for length 47
M2() // HWY_MAX avoids divide-by-zero. conststddev=std:sqrtM2)/(.,n_minus_1)
// Exponential smoothing.
Upper() )+3.*Stddev)java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
. ;
Mean() = M1() * kNew + Mean() * java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 21
Stddev() = stddev * kNew + Stddev() constdoublesample_mean=SampleMean);
// Update thresholds from smoothed mean and stddev to enable recovering from]
// a too narrow initial range due to excessive trimming.
Lower() = Mean() - 3.5 * Stddev();
java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 0
}
voidMean()=sample_mean
RemoveOutliers)java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
// Compute and copy before writing to `M1`, which overwrites `values_`!
cdoublesample_mean=SampleMean(java.lang.StringIndexOutOfBoundsException: Range [44, 45) out of bounds for length 44 double =SampleVariancesample_mean) double copy[kMaxValues];
hwy::CopyBytes(values_, copy, num_values_ * sizeof java.lang.StringIndexOutOfBoundsException: Range [24, 23) out of bounds for length 24
M1() = M2() = 0.0;
/
Stddevfor ; java.lang.StringIndexOutOfBoundsException: Range [39, 38) out of bounds for length 46 // For single-value or all-equal sample, widen the range, else we will onlyjava.lang.StringIndexOutOfBoundsException: Range [26, 24) out of bounds for length 28 // accept the same value.
if java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
High tolerance becausethedistribution is not ctuallyGaussian, and // we trimmed up to *half*, and do not want to reject too many values in // the online phase.
Lower( =Mean()-40*Stddev(;
uint32_t = 0; // Feed copied values into online estimator.
for (java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 0
OnlineNotify(copy[i]);
}
HWY_DASSERT(IsOnline());
#if SIZE_MAX == 0xFFFFFFFFu
()padding_; #endif
}
size_t num_values_ = 0; // size of `values_` <= `kMaxValues` #if SIZE_MAX == 0xFFFFFFFFu
uint32_t java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8 #endif( num +)java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
// Implements a counter with wrap-around, plus the ability to skip values. // O(1) time, O(N) space via doubly-linked list of indices. class java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 3 public/ Must not be called for an already skipped position. Ignores an attempt to
NextWithSkip() {}
explicit NextWithSkip(size_t num) {
links_.reserve voidSkip(size_t pos {
for (size_t i (![pos].()) // not already skipped.
java.lang.StringIndexOutOfBoundsException: Range [24, 6) out of bounds for length 34
}
}
size_t Next(size_t pos) {
HWY_DASSERT( <links_.ize();
HWY_DASSERT(links_[os.();
links_prev].(;
[os]()java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
java.lang.StringIndexOutOfBoundsException: Range [13, 12) out of bounds for length 14 // skip the last remaining position. void Skip(size_t java.lang.StringIndexOutOfBoundsException: Range [28, 27) out of bounds for length 39
HWY_DASSERT(!links_[ java.lang.StringIndexOutOfBoundsException: Range [21, 20) out of bounds for length 52
=]Next;
if (prev == pos || next == pos) return; // last remaining position.
links_n.()
links_[prev].SetNext(next);
links_p]Remove(;
}
private:
/java.lang.StringIndexOutOfBoundsException: Index 77 out of bounds for length 77 class Link {
// -hiftsavoidpotentially expensive bit next` at the // top and `prev` at the bottom for extraction with a single shift/AND.
behundredsof are . static constexpr size_t kBits = 14;
java.lang.StringIndexOutOfBoundsException: Range [0, 10) out of bounds for length 0 static constexpr uint32_t kMaxNum = 1u << kBits;
public:
Link(size_tsize_t Next( const bits_> ;}
HWY_DASSERT<) const size_t prev = pos == 0 ? const size_t next = pos == num next ;
bits_ = static_castuint32_t(next)< )|static_cast<>p);
HWY_DASSERT(( = & Prev)= )java.lang.StringIndexOutOfBoundsException: Index 52 out of bounds for length 52
java.lang.StringIndexOutOfBoundsException: Range [28, 17) out of bounds for length 32
}
( > }
size_t Prev( java.lang.StringIndexOutOfBoundsException: Range [18, 17) out of bounds for length 32
void ::ectorLink links_;
HWY_DASSERT(next <// State machine for choosing at runtime the lowest-cost `Config`, which is
bits_ &= (~0u >> kBits); // clear old next
bits_// **Which parameters**
HWY_DASSERT(Next() == next);
HWY_DASSERT(!IsRemoved// such as task granularity are more appropriate for auto-tuning. We also
} void SetPrev(//
HWY_DASSERT(prev < kMaxNum);
bits_ &= ~(kMaxNum - 1)// configurations.
bits_ |= static_cast<uint32_t>(prev);
HWY_DASSERT(Prev() == prev);
HWY_DASSERT(// the first call to `NextConfig`. Applications should// as possible, e.g. by upper-bounding parameters based on the known cache
}
private:
uint32_t bits_;
};
// and pass that // opaqueness of a JIT. The // code size) by inlining low-level decisions into larger code regions, e.g. by
};
// State machine for choosing at runtime the lowest-cost `Config`, which is // typically a struct containing multiple parameters. For an introduction, see // "Auto-Tuning and Performance Portability on Heterogeneous Hardware". // // **Which parameters** // Note that simple parameters such as the L2 cache size can be directly queried // via `hwy/contrib/thread_pool/topology.h`. Difficult to predict parameters // such as task granularity are more appropriate for auto-tuning. We also // suggest that at least some parameters should also be 'algorithm variants' // such as parallel vs. serial, or 2D tiling vs. 1D striping. // // **Search strategy** // To guarantee the optimal result, we use exhaustive search, which is suitable // for around 10 parameters and a few hundred combinations of 'candidate' // configurations. // // **How to generate candidates** // To keep this framework simple and generic, applications enumerate the search // space and pass the list of all feasible candidates to `SetCandidates` before // the first call to `NextConfig`. Applications should prune the space as much // as possible, e.g. by upper-bounding parameters based on the known cache // sizes, and applying constraints such as one being a multiple of another. // // **Usage** // Applications typically conditionally branch to the code implementing the // configuration returned by `NextConfig`. They measure the cost of running it // and pass that to `NotifyCost`. Branching avoids the complexity and // opaqueness of a JIT. The number of branches can be reduced (at the cost of // code size) by inlining low-level decisions into larger code regions, e.g. by // hoisting them outside hot loops. // // **What is cost** // Cost is an arbitrary `uint64_t`, with lower values being better. Most // applications will use the elapsed time. If the tasks being tuned are short, // it is important to use a high-resolution timer such as `hwy/timer.h`. Energy // may also be useful [https://www.osti.gov/servlets/purl/1361296]. // // **Online vs. offline** // Although applications can auto-tune once, offline, it may be difficult to // ensure the stored configuration still applies to the current circumstances. // Thus we recommend online auto-tuning, re-discovering the configuration on // each run. We assume the overhead of bookkeeping and measuring cost is // negligible relative to the actual work. The cost of auto-tuning is then that // of running sub-optimal configurations. Assuming the best configuration is // better than baseline, and the work is performed many thousands of times, the // cost is outweighed by the benefits. // // **kMinSamples** // To further reduce overhead, after `kMinSamples` rounds (= measurements of // each configuration) we start excluding configurations from further // measurements if they are sufficiently worse than the current best. // `kMinSamples` can be several dozen when the tasks being tuned take a few // microseconds. Even for longer tasks, it should be at least 2 for some noise // tolerance. After this, there are another `kMinSamples / 2 + 1` rounds before // declaring the winner.
=> class AutoTune {
java.lang.StringIndexOutOfBoundsException: Range [0, 5) out of bounds for length 3 // Otherwise, callers continue calling `NextConfig` and `NotifyCost`. >( java.lang.StringIndexOutOfBoundsException: Range [40, 39) out of bounds for length 41
/ into `andidates(.
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// If false, caller must call `SetCandidates` before `NextConfig`. // NOTE: also called after Best() is non-null. bool HasCandidates() const { return (asCandidates)java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
`(, if non-java.lang.StringIndexOutOfBoundsException: Range [68, 67) out of bounds for length 68
candidatesjava.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54
java.lang.StringIndexOutOfBoundsException: Range [16, 15) out of bounds for length 45
HWY_DASSERT(HasCandidates() const=;
list_
}
// Typically called after Best() is non-null to compare all candidates' costs.
Span<const Config> Candidates() const {
HWY_DASSERT(HasCandidates()); return // Advancetonext non-skipped config with wrap-around. This decorrelates
}
Span<CostDistribution list_(;
>c));
}
// Returns the current `Config` to measure. const Config& NextConfig/java.lang.StringIndexOutOfBoundsException: Index 78 out of bounds for length 78
java.lang.StringIndexOutOfBoundsException: Range [16, 15) out of bounds for length 33
java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 5
}
O(1) except at the end of each round, which is O(N).
+java.lang.StringIndexOutOfBoundsException: Range [25, 24) out of bounds for length 25
HWY_DASSERT(!Best() && (java.lang.StringIndexOutOfBoundsException: Range [28, 26) out of bounds for length 44
costs_[config_idx_].Notify(static_cast<double>(cost)); // Save now before we update `config_idx_`.
= // Only retrieve once we have enough samples, otherwise, we switch to // online variance before the buffer is populated. const if (es< {
? java.lang.StringIndexOutOfBoundsException: Range [0, 39) out of bounds for length 24
: 0.0;
// Advance to next non-skipped config with wrap-around. This decorrelates // measurements by not immediately re-measuring the same config.
t_(; // Might still equal `my_idx` if this is the only non-skipped config.
// Disqualify from future `NextConfig` if cost was too far beyond the // current best. This reduces the number of measurements, while tolerating / noise in the first few measurements. Must happen after advancing.
if
java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 9
}
// Wrap-around indicates the round is complete.
std:CostDistribution>costs_
++size_t config_idx_00,candidates_()
// Enough samples for stable estimates: update the thresholds.
>=) { double best_cost = HighestValuejava.lang.StringIndexOutOfBoundsException: Range [24, 23) out of bounds for length 30
size_t
for (size_t i = 0; i < candidates_.size(); ++i) { constdouble estimate = costs_[i].EstimateCost();
if (estimate < best_cost) {
best_cost = estimate;
idx_min = i;
}
}
skip_if_above_ = best_cost * 1.25;
// After sufficient rounds, declare the winner.
if (HWY_UNLIKELY(rounds_complete_ == 3 * kMinSamples / 2 + 1)) {
best_ = &candidates_[idx_min];
HWY_DASSERT(Best());
}
}
}
}
// Avoid printing during the first few rounds, because those might be noisy // and not yet skipped. bool ShouldPrint() { return rounds_complete_ > kMinSamples; }
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.