1+
2+ #include < benchmark/benchmark.h>
3+ #include " RipTide.h" // Required for MultiKey.h included from GroupBy.h
4+ #include " GroupBy.h"
5+ #include " numpy_traits.h"
6+ #include < random>
7+
8+ using namespace riptide ::benchmark;
9+
10+ template <typename T>
11+ std::vector<T> uniform_random_vector (size_t length, T min, T max)
12+ {
13+ std::default_random_engine engine;
14+ std::uniform_int_distribution<T> distribution (min, max);
15+
16+ auto random = [&]
17+ {
18+ return distribution (engine);
19+ };
20+
21+ std::vector<T> result (length);
22+ std::generate (result.begin (), result.end (), random);
23+ return result;
24+ }
25+
26+ template <GB_FUNCTIONS function, NPY_TYPES TypeCode>
27+ static void BM_GroupByTwo (benchmark::State & state)
28+ {
29+ int64_t length = state.range (0 );
30+ int64_t bins = state.range (1 );
31+
32+ auto groupby = get_groupby_two_function (function, TypeCode);
33+
34+ // Allocate input/output/etc buffers
35+ std::vector<typename riptide::numpy_cpp_type<TypeCode>::type> input (length);
36+ std::vector<uint8_t > output (bins * groupby.output_type_size );
37+ std::vector<uint8_t > temp (bins * groupby.temp_type_size );
38+ std::vector<CountType> count (bins);
39+
40+ // Populate index vector to simulate real memory access patterns
41+ auto index = uniform_random_vector<IndexType>(length, 0 , bins - 1 );
42+
43+ for (auto _ : state)
44+ {
45+ groupby.function (input.data (), index.data (), count.data (), output.data (), length, 0 , bins, -1 , temp.data ());
46+ }
47+ }
48+
49+ template <typename T>
50+ struct first_and_count
51+ {
52+ std::vector<T> first;
53+ std::vector<T> count;
54+ };
55+
56+ template <typename T>
57+ first_and_count<T> generate_first_and_count (int64_t length, int64_t bins)
58+ {
59+ // Groups are packed such that all elements in the same group are adjacent
60+ // Each entry is the index to the first element of that group
61+ auto first = uniform_random_vector<T>(bins, 0 , length - 1 );
62+
63+ // Sort it so that generating count is easier
64+ std::sort (first.begin (), first.end ());
65+ // Set first entry to 0 so that we aren't missing items
66+ first[0 ] = 0 ;
67+
68+ // Each entry is the number of items in the group
69+ // We can just compute this by finding the difference between entries in first
70+ std::vector<T> count (bins);
71+ for (size_t i = 0 ; i < count.size () - 1 ; i++)
72+ count[i] = first[i + 1 ] - first[i];
73+ count.back () = length - first.back ();
74+
75+ return { first, count };
76+ }
77+
78+ template <GB_FUNCTIONS function, NPY_TYPES TypeCode, int64_t funcParam = 0 >
79+ static void BM_GroupByX (benchmark::State & state)
80+ {
81+ int64_t length = state.range (0 );
82+ int64_t bins = state.range (1 );
83+
84+ auto groupby = get_groupby_x_function (function, TypeCode);
85+
86+ // The values here don't matter
87+ std::vector<typename riptide::numpy_cpp_type<TypeCode>::type> input (length);
88+ std::vector<uint8_t > output;
89+
90+ if constexpr (function >= GB_ROLLING_SUM)
91+ // Rolling functions require that the output the same size as the input
92+ output = std::vector<uint8_t >(length * groupby.output_type_size );
93+ else
94+ // Other functions require the number of bins
95+ output = std::vector<uint8_t >(bins * groupby.output_type_size );
96+
97+ // Populate group, first and count to simulate real memory access patterns
98+ auto group = uniform_random_vector<IndexType>(length, 0 , length - 1 );
99+ auto [first, count] = generate_first_and_count<IndexType>(length, bins);
100+
101+ for (auto _ : state)
102+ {
103+ groupby.function (input.data (), group.data (), first.data (), count.data (), output.data (), 0 , bins, length,
104+ groupby.output_type_size , funcParam);
105+ }
106+ }
107+
108+ static void GroupByArguments (benchmark::internal::Benchmark * b)
109+ {
110+ // Benchmark with 1 million values and 1000 groups
111+ b->Args ({ 1000000 , 1000 });
112+ }
113+
114+ #define BENCHMARK_GROUPBY_TWO_ALL_TYPES (GB_FUNCTION ) \
115+ BENCHMARK (BM_GroupByTwo<GB_FUNCTION, NPY_INT8>)->Apply(GroupByArguments); \
116+ BENCHMARK (BM_GroupByTwo<GB_FUNCTION, NPY_INT16>)->Apply(GroupByArguments); \
117+ BENCHMARK (BM_GroupByTwo<GB_FUNCTION, NPY_INT32>)->Apply(GroupByArguments); \
118+ BENCHMARK (BM_GroupByTwo<GB_FUNCTION, NPY_INT64>)->Apply(GroupByArguments); \
119+ BENCHMARK (BM_GroupByTwo<GB_FUNCTION, NPY_UINT8>)->Apply(GroupByArguments); \
120+ BENCHMARK (BM_GroupByTwo<GB_FUNCTION, NPY_UINT16>)->Apply(GroupByArguments); \
121+ BENCHMARK (BM_GroupByTwo<GB_FUNCTION, NPY_UINT32>)->Apply(GroupByArguments); \
122+ BENCHMARK (BM_GroupByTwo<GB_FUNCTION, NPY_UINT64>)->Apply(GroupByArguments); \
123+ BENCHMARK (BM_GroupByTwo<GB_FUNCTION, NPY_FLOAT>)->Apply(GroupByArguments); \
124+ BENCHMARK (BM_GroupByTwo<GB_FUNCTION, NPY_DOUBLE>)->Apply(GroupByArguments); \
125+ BENCHMARK (BM_GroupByTwo<GB_FUNCTION, NPY_LONGDOUBLE>)->Apply(GroupByArguments);
126+
127+ BENCHMARK_GROUPBY_TWO_ALL_TYPES (GB_SUM);
128+ BENCHMARK_GROUPBY_TWO_ALL_TYPES (GB_MEAN);
129+ BENCHMARK_GROUPBY_TWO_ALL_TYPES (GB_MIN);
130+ BENCHMARK_GROUPBY_TWO_ALL_TYPES (GB_MAX);
131+ BENCHMARK_GROUPBY_TWO_ALL_TYPES (GB_VAR);
132+ BENCHMARK_GROUPBY_TWO_ALL_TYPES (GB_STD);
133+ BENCHMARK_GROUPBY_TWO_ALL_TYPES (GB_NANSUM);
134+ BENCHMARK_GROUPBY_TWO_ALL_TYPES (GB_NANMEAN);
135+ BENCHMARK_GROUPBY_TWO_ALL_TYPES (GB_NANMIN);
136+ BENCHMARK_GROUPBY_TWO_ALL_TYPES (GB_NANMAX);
137+ BENCHMARK_GROUPBY_TWO_ALL_TYPES (GB_NANVAR);
138+ BENCHMARK_GROUPBY_TWO_ALL_TYPES (GB_NANSTD);
139+
140+ // Parameters for GroupByX functions
141+ namespace
142+ {
143+ constexpr int64_t unused = 0 ;
144+ constexpr int64_t nth = 5 ;
145+ constexpr int64_t window = 10 ;
146+ constexpr int64_t multiplier = 1e9 ;
147+ constexpr int64_t quantile = 0.2 * multiplier;
148+ constexpr int64_t quantile_and_window = quantile + window * (multiplier + 1 );
149+ }
150+
151+ #define BENCHMARK_GROUPBY_X_ALL_TYPES (GB_FUNCTION, funcParam ) \
152+ BENCHMARK (BM_GroupByX<GB_FUNCTION, NPY_INT8, funcParam>)->Apply(GroupByArguments); \
153+ BENCHMARK (BM_GroupByX<GB_FUNCTION, NPY_INT16, funcParam>)->Apply(GroupByArguments); \
154+ BENCHMARK (BM_GroupByX<GB_FUNCTION, NPY_INT32, funcParam>)->Apply(GroupByArguments); \
155+ BENCHMARK (BM_GroupByX<GB_FUNCTION, NPY_INT64, funcParam>)->Apply(GroupByArguments); \
156+ BENCHMARK (BM_GroupByX<GB_FUNCTION, NPY_UINT8, funcParam>)->Apply(GroupByArguments); \
157+ BENCHMARK (BM_GroupByX<GB_FUNCTION, NPY_UINT16, funcParam>)->Apply(GroupByArguments); \
158+ BENCHMARK (BM_GroupByX<GB_FUNCTION, NPY_UINT32, funcParam>)->Apply(GroupByArguments); \
159+ BENCHMARK (BM_GroupByX<GB_FUNCTION, NPY_UINT64, funcParam>)->Apply(GroupByArguments); \
160+ BENCHMARK (BM_GroupByX<GB_FUNCTION, NPY_FLOAT, funcParam>)->Apply(GroupByArguments); \
161+ BENCHMARK (BM_GroupByX<GB_FUNCTION, NPY_DOUBLE, funcParam>)->Apply(GroupByArguments); \
162+ BENCHMARK (BM_GroupByX<GB_FUNCTION, NPY_LONGDOUBLE, funcParam>)->Apply(GroupByArguments);
163+
164+ BENCHMARK_GROUPBY_X_ALL_TYPES (GB_FIRST, unused);
165+ BENCHMARK_GROUPBY_X_ALL_TYPES (GB_NTH, nth);
166+ BENCHMARK_GROUPBY_X_ALL_TYPES (GB_LAST, unused);
167+ BENCHMARK_GROUPBY_X_ALL_TYPES (GB_MEDIAN, unused);
168+ BENCHMARK_GROUPBY_X_ALL_TYPES (GB_MODE, unused);
169+ BENCHMARK_GROUPBY_X_ALL_TYPES (GB_TRIMBR, unused);
170+ BENCHMARK_GROUPBY_X_ALL_TYPES (GB_QUANTILE_MULT, quantile);
171+ BENCHMARK_GROUPBY_X_ALL_TYPES (GB_ROLLING_SUM, window);
172+ BENCHMARK_GROUPBY_X_ALL_TYPES (GB_ROLLING_NANSUM, window);
173+ BENCHMARK_GROUPBY_X_ALL_TYPES (GB_ROLLING_DIFF, window);
174+ BENCHMARK_GROUPBY_X_ALL_TYPES (GB_ROLLING_SHIFT, window);
175+ BENCHMARK_GROUPBY_X_ALL_TYPES (GB_ROLLING_MEAN, window);
176+ BENCHMARK_GROUPBY_X_ALL_TYPES (GB_ROLLING_NANMEAN, window);
177+ BENCHMARK_GROUPBY_X_ALL_TYPES (GB_ROLLING_QUANTILE, quantile_and_window);
178+
179+ BENCHMARK (BM_GroupByX<GB_ROLLING_COUNT, NPY_INT8, 0 >)->Apply(GroupByArguments);
180+ BENCHMARK (BM_GroupByX<GB_ROLLING_COUNT, NPY_INT16, 0 >)->Apply(GroupByArguments);
181+ BENCHMARK (BM_GroupByX<GB_ROLLING_COUNT, NPY_INT32, 0 >)->Apply(GroupByArguments);
182+ BENCHMARK (BM_GroupByX<GB_ROLLING_COUNT, NPY_INT64, 0 >)->Apply(GroupByArguments);
183+ // BENCHMARK(BM_GroupByX<GB_ROLLING_COUNT, NPY_UINT8, 0>)->Apply(GroupByArguments);
184+ // BENCHMARK(BM_GroupByX<GB_ROLLING_COUNT, NPY_UINT16, 0>)->Apply(GroupByArguments);
185+ // BENCHMARK(BM_GroupByX<GB_ROLLING_COUNT, NPY_UINT32, 0>)->Apply(GroupByArguments);
186+ // BENCHMARK(BM_GroupByX<GB_ROLLING_COUNT, NPY_UINT64, 0>)->Apply(GroupByArguments);
187+ // BENCHMARK(BM_GroupByX<GB_ROLLING_COUNT, NPY_FLOAT, 0>)->Apply(GroupByArguments);
188+ // BENCHMARK(BM_GroupByX<GB_ROLLING_COUNT, NPY_DOUBLE, 0>)->Apply(GroupByArguments);
189+ // BENCHMARK(BM_GroupByX<GB_FUNCTION, NPY_LONGDOUBLE, 0>)->Apply(GroupByArguments);
0 commit comments