Skip to content

Instantly share code, notes, and snippets.

@superfunc
Created August 11, 2019 21:31
Show Gist options
  • Save superfunc/605dbef02595ef7e527bb3ba43ef25c0 to your computer and use it in GitHub Desktop.
Save superfunc/605dbef02595ef7e527bb3ba43ef25c0 to your computer and use it in GitHub Desktop.
STLCost/GBench
// 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