Created
August 11, 2019 21:31
-
-
Save superfunc/605dbef02595ef7e527bb3ba43ef25c0 to your computer and use it in GitHub Desktop.
STLCost/GBench
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Code by https://github.com/Atrix256/STLCost | |
// Blog at: https://blog.demofox.org/2019/08/10/measuring-debug-stl-container-perf-cost-in-msvc/ | |
// Modified to run under google benchmark | |
#include <benchmark/benchmark.h> | |
#include <chrono> | |
#include <cstdio> | |
#include <iostream> | |
#include <string> | |
#include <thread> | |
// the size of the image that is made into mips | |
#define IMAGE_SIZE() 512 | |
typedef float ChannelType; | |
#include <stdio.h> | |
#include <array> | |
#include <vector> | |
#include <chrono> | |
// calculate the total number of pixels needed to hold the image of size IMAGE_SIZE() as well as all the mips | |
constexpr size_t TotalPixelsMipped() | |
{ | |
size_t ret = 0; | |
size_t size = IMAGE_SIZE(); | |
while (size) | |
{ | |
ret += size * size; | |
size /= 2; | |
} | |
return ret; | |
} | |
constexpr size_t TotalChannelsMipped() | |
{ | |
// RGBA | |
return TotalPixelsMipped() * 4; | |
} | |
constexpr size_t NumMips() | |
{ | |
size_t ret = 0; | |
size_t size = IMAGE_SIZE(); | |
while (size) | |
{ | |
ret++; | |
size /= 2; | |
} | |
return ret; | |
} | |
void GetMipInfo(size_t desiredMipIndex, size_t& offset, size_t& width) | |
{ | |
offset = 0; | |
width = IMAGE_SIZE(); | |
for (size_t mipIndex = 0; mipIndex < desiredMipIndex; ++mipIndex) | |
{ | |
offset += width * width * 4; | |
width /= 2; | |
} | |
} | |
template<typename T> | |
void MakeMip(T& image, size_t mipIndex) | |
{ | |
size_t srcOffset; | |
size_t srcWidth; | |
GetMipInfo(mipIndex - 1, srcOffset, srcWidth); | |
size_t destOffset; | |
size_t destWidth; | |
GetMipInfo(mipIndex, destOffset, destWidth); | |
for (size_t destY = 0; destY < destWidth; ++destY) | |
{ | |
for (size_t destX = 0; destX < destWidth; ++destX) | |
{ | |
for (size_t channel = 0; channel < 4; ++channel) | |
{ | |
// 2x2 box filter source mip pixels | |
float value = | |
float(image[((destY * 2 + 0) * srcWidth + destX * 2 + 0) * 4 + srcOffset] + channel) + | |
float(image[((destY * 2 + 0) * srcWidth + destX * 2 + 1) * 4 + srcOffset] + channel) + | |
float(image[((destY * 2 + 1) * srcWidth + destX * 2 + 0) * 4 + srcOffset] + channel) + | |
float(image[((destY * 2 + 1) * srcWidth + destX * 2 + 1) * 4 + srcOffset] + channel); | |
image[destOffset] = ChannelType(value / 4.0f); | |
destOffset++; | |
} | |
} | |
} | |
} | |
template<typename T> | |
void MakeMips(T& image) | |
{ | |
size_t mipCount = NumMips(); | |
for (size_t mipIndex = 1; mipIndex < mipCount; ++mipIndex) | |
MakeMip(image, mipIndex); | |
} | |
template<typename T> | |
void InitImage(T& image) | |
{ | |
memset(&image[0], 0, TotalChannelsMipped() * sizeof(float)); | |
// It doesn't matter what we put into the image since we aren't ever looking at it, but initializing it anyhow. | |
size_t i = 0; | |
for (size_t y = 0; y < IMAGE_SIZE(); ++y) | |
{ | |
for (size_t x = 0; x < IMAGE_SIZE(); ++x) | |
{ | |
image[i * 4 + 0] = ChannelType(x % 256); | |
image[i * 4 + 1] = ChannelType(y % 256); | |
image[i * 4 + 2] = ChannelType(0); | |
image[i * 4 + 3] = ChannelType(255); | |
i++; | |
} | |
} | |
} | |
static void | |
array_stl_init_image(benchmark::State& state) | |
{ | |
for (auto _ : state) { | |
std::array<ChannelType, TotalChannelsMipped()>* array_ptr = new std::array<ChannelType, TotalChannelsMipped()>; | |
std::array<ChannelType, TotalChannelsMipped()>& array = *array_ptr; | |
InitImage(array); | |
benchmark::DoNotOptimize(array); | |
delete array_ptr; | |
} | |
} | |
static void | |
array_stl_init_image_and_make_mips(benchmark::State& state) | |
{ | |
for (auto _ : state) { | |
std::array<ChannelType, TotalChannelsMipped()>* array_ptr = new std::array<ChannelType, TotalChannelsMipped()>; | |
std::array<ChannelType, TotalChannelsMipped()>& array = *array_ptr; | |
InitImage(array); | |
MakeMips(array); | |
benchmark::DoNotOptimize(array); | |
delete array_ptr; | |
} | |
} | |
static void | |
vector_stl_init_image(benchmark::State& state) | |
{ | |
for (auto _ : state) { | |
std::vector<ChannelType> vector; | |
vector.resize(TotalChannelsMipped()); | |
InitImage(vector); | |
benchmark::DoNotOptimize(vector); | |
} | |
} | |
static void | |
vector_stl_init_image_and_make_mips(benchmark::State& state) | |
{ | |
for (auto _ : state) { | |
std::vector<ChannelType> vector; | |
vector.resize(TotalChannelsMipped()); | |
InitImage(vector); | |
MakeMips(vector); | |
benchmark::DoNotOptimize(vector); | |
} | |
} | |
static void | |
array_c_init_image(benchmark::State& state) | |
{ | |
for (auto _ : state) { | |
ChannelType* carray = nullptr; | |
carray = (ChannelType*)malloc(sizeof(ChannelType)*TotalChannelsMipped()); | |
InitImage(carray); | |
benchmark::DoNotOptimize(*carray); | |
free(carray); | |
} | |
} | |
static void | |
array_c_init_image_and_make_mips(benchmark::State& state) | |
{ | |
for (auto _ : state) { | |
ChannelType* carray = nullptr; | |
carray = (ChannelType*)malloc(sizeof(ChannelType)*TotalChannelsMipped()); | |
InitImage(carray); | |
MakeMips(carray); | |
benchmark::DoNotOptimize(*carray); | |
free(carray); | |
} | |
} | |
BENCHMARK(array_stl_init_image)->Unit(benchmark::kMicrosecond); | |
BENCHMARK(array_stl_init_image_and_make_mips)->Unit(benchmark::kMicrosecond); | |
BENCHMARK(vector_stl_init_image)->Unit(benchmark::kMicrosecond); | |
BENCHMARK(vector_stl_init_image_and_make_mips)->Unit(benchmark::kMicrosecond); | |
BENCHMARK(array_c_init_image)->Unit(benchmark::kMicrosecond); | |
BENCHMARK(array_c_init_image_and_make_mips)->Unit(benchmark::kMicrosecond); | |
BENCHMARK_MAIN(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment